Fossil

Check-in [9fe06e2f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Removed the json warnings bitset crap. Still not sure i like the warnings mechanism at all.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | json
Files: files | file ages | folders
SHA1: 9fe06e2fdad0dba1492a972e2352a3c3c0633fa4
User & Date: stephan 2011-09-29 21:57:00
Context
2011-09-29
22:27
json ajax: fixed POST/GET message sending determination (broken by a previous change this evening). check-in: 37963253 user: stephan tags: json
21:57
Removed the json warnings bitset crap. Still not sure i like the warnings mechanism at all. check-in: 9fe06e2f user: stephan tags: json
21:55
Corrected a JSON-mode result code when db rebuild is required. check-in: 44644d43 user: stephan tags: json
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/json.c.

724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
....
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313

1314
1315
1316
1317
1318
1319
1320
1321
1322
1323



1324
1325
1326
1327
1328
1329
1330
....
1604
1605
1606
1607
1608
1609
1610

1611
1612
1613
1614
1615
1616
1617
....
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681




1682
1683
1684
1685
1686
1687
1688
*/
void json_warn( int code, char const * msg ){
  cson_value * objV = NULL;
  cson_object * obj = NULL;
  assert( (code>FSL_JSON_W_START)
          && (code<FSL_JSON_W_END)
          && "Invalid warning code.");
  if( BITSET_GET(g.json.warnings.bitset,code) ){
    return;
  }
  if(!g.json.warnings.v){
    g.json.warnings.v = cson_value_new_array();
    assert((NULL != g.json.warnings.v) && "Alloc error.");
    g.json.warnings.a = cson_value_get_array(g.json.warnings.v);
    json_gc_add("$WARNINGS",g.json.warnings.v,0);
  }
  objV = cson_value_new_object();
................................................................................
  cson_object_set(obj,"code",cson_value_new_integer(code));
  if(msg && *msg){
    /* FIXME: treat NULL msg as standard warning message for
       the code, but we don't have those yet.
    */
    cson_object_set(obj,"text",cson_value_new_string(msg,strlen(msg)));
  }
  BITSET_SET(g.json.warnings.bitset,code);
}

/*
** Splits zStr (which must not be NULL) into tokens separated by the
** given separator character. If doDeHttp is true then each element
** will be passed through dehttpize(), otherwise they are used
** as-is. Each new element is appended to the given target array
................................................................................
** Iterates through a prepared SELECT statement and converts each row
** to a JSON object. If pTgt is not NULL then it must be-a Array
** object and this function will return pTgt. If pTgt is NULL then a
** new Array object is created and returned (owned by the
** caller). Each row of pStmt is converted to an Object and appended
** to the array.
*/
static cson_value * json_stmt_to_array_of_obj(Stmt *pStmt,
                                              cson_value * pTgt){
  cson_value * v = pTgt ? pTgt : cson_value_new_array();
  cson_array * a = cson_value_get_array(pTgt ? pTgt : v);

  assert( NULL != a );
  while( (SQLITE_ROW==db_step(pStmt)) ){
    cson_value * row = cson_sqlite3_row_to_object(pStmt->pStmt);
    if(!row){
      json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED,
                 "Could not convert at least one result row to JSON." );
      continue;
    }
    cson_array_append(a, row);
  }



  return v;  
}

/*
** /json/version implementation.
**
** Returns the payload object (owned by the caller).
................................................................................
static cson_value * json_branch_list(){
  cson_value * payV;
  cson_object * pay;
  cson_value * listV;
  cson_array * list;
  char const * range = NULL;
  int which = 0;

  Stmt q;
  if( !g.perm.Read ){
    g.json.resultCode = FSL_JSON_E_DENIED;
    return NULL;
  }
  payV = cson_value_new_object();
  pay = cson_value_get_object(payV);
................................................................................
  
  branch_prepare_list_query(&q, which);
  cson_object_set(pay,"branches",listV);
  while((SQLITE_ROW==db_step(&q))){
    cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
    if(v){
      cson_array_append(list,v);
    }else{
      char * msg = mprintf("Column-to-json failed @ %s:%d",
                           __FILE__,__LINE__);
      json_warn(FSL_JSON_W_COL_TO_JSON_FAILED,msg);
      free(msg);
    }
  }




  return payV;
}

/*
** Impl of /json/rebuild. Requires admin previleges.
*/
static cson_value * json_page_rebuild(){







<
<
<







 







<







 







|
|


>



|
<
|




>
>
>







 







>







 







|
|
|
<
<


>
>
>
>







724
725
726
727
728
729
730



731
732
733
734
735
736
737
...
741
742
743
744
745
746
747

748
749
750
751
752
753
754
....
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314

1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
....
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
....
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677


1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
*/
void json_warn( int code, char const * msg ){
  cson_value * objV = NULL;
  cson_object * obj = NULL;
  assert( (code>FSL_JSON_W_START)
          && (code<FSL_JSON_W_END)
          && "Invalid warning code.");



  if(!g.json.warnings.v){
    g.json.warnings.v = cson_value_new_array();
    assert((NULL != g.json.warnings.v) && "Alloc error.");
    g.json.warnings.a = cson_value_get_array(g.json.warnings.v);
    json_gc_add("$WARNINGS",g.json.warnings.v,0);
  }
  objV = cson_value_new_object();
................................................................................
  cson_object_set(obj,"code",cson_value_new_integer(code));
  if(msg && *msg){
    /* FIXME: treat NULL msg as standard warning message for
       the code, but we don't have those yet.
    */
    cson_object_set(obj,"text",cson_value_new_string(msg,strlen(msg)));
  }

}

/*
** Splits zStr (which must not be NULL) into tokens separated by the
** given separator character. If doDeHttp is true then each element
** will be passed through dehttpize(), otherwise they are used
** as-is. Each new element is appended to the given target array
................................................................................
** Iterates through a prepared SELECT statement and converts each row
** to a JSON object. If pTgt is not NULL then it must be-a Array
** object and this function will return pTgt. If pTgt is NULL then a
** new Array object is created and returned (owned by the
** caller). Each row of pStmt is converted to an Object and appended
** to the array.
*/
cson_value * json_stmt_to_array_of_obj(Stmt *pStmt,
                                       cson_value * pTgt){
  cson_value * v = pTgt ? pTgt : cson_value_new_array();
  cson_array * a = cson_value_get_array(pTgt ? pTgt : v);
  char const * warnMsg = NULL;
  assert( NULL != a );
  while( (SQLITE_ROW==db_step(pStmt)) ){
    cson_value * row = cson_sqlite3_row_to_object(pStmt->pStmt);
    if(!row && !warnMsg){

      warnMsg = "Could not convert at least one result row to JSON.";
      continue;
    }
    cson_array_append(a, row);
  }
  if(warnMsg){
    json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
  }
  return v;  
}

/*
** /json/version implementation.
**
** Returns the payload object (owned by the caller).
................................................................................
static cson_value * json_branch_list(){
  cson_value * payV;
  cson_object * pay;
  cson_value * listV;
  cson_array * list;
  char const * range = NULL;
  int which = 0;
  char * sawConversionError = NULL;
  Stmt q;
  if( !g.perm.Read ){
    g.json.resultCode = FSL_JSON_E_DENIED;
    return NULL;
  }
  payV = cson_value_new_object();
  pay = cson_value_get_object(payV);
................................................................................
  
  branch_prepare_list_query(&q, which);
  cson_object_set(pay,"branches",listV);
  while((SQLITE_ROW==db_step(&q))){
    cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
    if(v){
      cson_array_append(list,v);
    }else if(!sawConversionError){
      sawConversionError = mprintf("Column-to-json failed @ %s:%d",
                                   __FILE__,__LINE__);


    }
  }
  if( sawConversionError ){
    json_warn(FSL_JSON_W_COL_TO_JSON_FAILED,sawConversionError);
    free(sawConversionError);
}
  return payV;
}

/*
** Impl of /json/rebuild. Requires admin previleges.
*/
static cson_value * json_page_rebuild(){

Changes to src/json_detail.h.

18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
** Numbers evenly dividable by 100 are "categories", and error codes
** for a given category have their high bits set to the category
** value.
**
*/
enum FossilJsonCodes {
FSL_JSON_W_START = 0,

FSL_JSON_W_ROW_TO_JSON_FAILED = FSL_JSON_W_START + 1,
FSL_JSON_W_COL_TO_JSON_FAILED = FSL_JSON_W_START + 2,
FSL_JSON_W_STRING_TO_ARRAY_FAILED = FSL_JSON_W_START + 3,

FSL_JSON_W_END = 1000,
FSL_JSON_E_GENERIC = 1000,
FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100,
FSL_JSON_E_INVALID_REQUEST = FSL_JSON_E_GENERIC_SUB1 + 1,
FSL_JSON_E_UNKNOWN_COMMAND = FSL_JSON_E_GENERIC_SUB1 + 2,
FSL_JSON_E_UNKNOWN = FSL_JSON_E_GENERIC_SUB1 + 3,







>
|
|
|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
** Numbers evenly dividable by 100 are "categories", and error codes
** for a given category have their high bits set to the category
** value.
**
*/
enum FossilJsonCodes {
FSL_JSON_W_START = 0,
FSL_JSON_W_UNKNOWN = FSL_JSON_W_START + 1,
FSL_JSON_W_ROW_TO_JSON_FAILED = FSL_JSON_W_START + 2,
FSL_JSON_W_COL_TO_JSON_FAILED = FSL_JSON_W_START + 3,
FSL_JSON_W_STRING_TO_ARRAY_FAILED = FSL_JSON_W_START + 4,

FSL_JSON_W_END = 1000,
FSL_JSON_E_GENERIC = 1000,
FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100,
FSL_JSON_E_INVALID_REQUEST = FSL_JSON_E_GENERIC_SUB1 + 1,
FSL_JSON_E_UNKNOWN_COMMAND = FSL_JSON_E_GENERIC_SUB1 + 2,
FSL_JSON_E_UNKNOWN = FSL_JSON_E_GENERIC_SUB1 + 3,

Changes to src/json_timeline.c.

257
258
259
260
261
262
263


264
265
266
267
268
269
270
...
312
313
314
315
316
317
318
319

320
321
322
323
324
325
326
...
330
331
332
333
334
335
336
337

338
339
340
341
342
343
344
...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  cson_object * pay = NULL;
  cson_value * tmp = NULL;
  cson_value * listV = NULL;
  cson_array * list = NULL;
  int check = 0;
  int showFiles = 0;
  Stmt q;


  Blob sql = empty_blob;
  if( !g.perm.Read/* && !g.perm.RdTkt && !g.perm.RdWiki*/ ){
    g.json.resultCode = FSL_JSON_E_DENIED;
    return NULL;
  }
  if( g.isHTTP ){
    showFiles = json_getenv_bool("showFiles",0);
................................................................................
  SET("timeline");
  while( (SQLITE_ROW == db_step(&q) )){
    /* convert each row into a JSON object...*/
    int const rid = db_column_int(&q,0);
    cson_value * rowV = cson_sqlite3_row_to_object(q.pStmt);
    cson_object * row = cson_value_get_object(rowV);
    cson_string const * tagsStr = NULL;
    if(!row){

      json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED,
                 "Could not convert at least one timeline result row to JSON." );
      continue;
    }
    /* Split tags string field into JSON Array... */
    cson_array_append(list, rowV);
    tagsStr = cson_value_get_string(cson_object_get(row,"tags"));
................................................................................
      if( tags ){
        if(0 != cson_object_set(row,"tags",tags)){
          cson_value_free(tags);
        }else{
          /*replaced/deleted old tags value, invalidating tagsStr*/;
          tagsStr = NULL;
        }
      }else{

        json_warn(FSL_JSON_W_STRING_TO_ARRAY_FAILED,
                  "Could not convert tags string to array.");
      }
    }

    /* replace isLeaf int w/ JSON bool */
    tmp = cson_object_get(row,"isLeaf");
................................................................................
             " FROM json_timeline"
             " ORDER BY sortId",
             -1);
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  tmp = listV;
  SET("timeline");
  while( (SQLITE_ROW == db_step(&q) )){
    /* convert each row into a JSON object...*/
    cson_value * rowV = cson_sqlite3_row_to_object(q.pStmt);
    cson_object * row = cson_value_get_object(rowV);
    int rc;
    if(!row){
      json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED,
                 "Could not convert at least one timeline result row to JSON." );
      continue;
    }
    rc = cson_array_append( list, rowV );
    if( 0 != rc ){
      cson_value_free(rowV);
      g.json.resultCode = (cson_rc.AllocError==rc)
        ? FSL_JSON_E_ALLOC
        : FSL_JSON_E_UNKNOWN;
      goto error;
    }
  }
#undef SET
  goto ok;
  error:
  assert( 0 != g.json.resultCode );
  cson_value_free(payV);
  payV = NULL;
  ok:







>
>







 







|
>







 







|
>







 







|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
422
423
424
425
426
427
428
429


















430
431
432
433
434
435
436
  cson_object * pay = NULL;
  cson_value * tmp = NULL;
  cson_value * listV = NULL;
  cson_array * list = NULL;
  int check = 0;
  int showFiles = 0;
  Stmt q;
  char warnRowToJsonFailed = 0;
  char warnStringToArrayFailed = 0;
  Blob sql = empty_blob;
  if( !g.perm.Read/* && !g.perm.RdTkt && !g.perm.RdWiki*/ ){
    g.json.resultCode = FSL_JSON_E_DENIED;
    return NULL;
  }
  if( g.isHTTP ){
    showFiles = json_getenv_bool("showFiles",0);
................................................................................
  SET("timeline");
  while( (SQLITE_ROW == db_step(&q) )){
    /* convert each row into a JSON object...*/
    int const rid = db_column_int(&q,0);
    cson_value * rowV = cson_sqlite3_row_to_object(q.pStmt);
    cson_object * row = cson_value_get_object(rowV);
    cson_string const * tagsStr = NULL;
    if(!row && !warnRowToJsonFailed){
      warnRowToJsonFailed = 1;
      json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED,
                 "Could not convert at least one timeline result row to JSON." );
      continue;
    }
    /* Split tags string field into JSON Array... */
    cson_array_append(list, rowV);
    tagsStr = cson_value_get_string(cson_object_get(row,"tags"));
................................................................................
      if( tags ){
        if(0 != cson_object_set(row,"tags",tags)){
          cson_value_free(tags);
        }else{
          /*replaced/deleted old tags value, invalidating tagsStr*/;
          tagsStr = NULL;
        }
      }else if(!warnStringToArrayFailed){
        warnStringToArrayFailed = 1;
        json_warn(FSL_JSON_W_STRING_TO_ARRAY_FAILED,
                  "Could not convert tags string to array.");
      }
    }

    /* replace isLeaf int w/ JSON bool */
    tmp = cson_object_get(row,"isLeaf");
................................................................................
             " FROM json_timeline"
             " ORDER BY sortId",
             -1);
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  tmp = listV;
  SET("timeline");
  json_stmt_to_array_of_obj(&q, listV);


















#undef SET
  goto ok;
  error:
  assert( 0 != g.json.resultCode );
  cson_value_free(payV);
  payV = NULL;
  ok:

Changes to src/main.c.

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531


532
533
534
535
536
537
538

539
540
541
542
543
544
545
    struct {
      cson_value * v;
      cson_object * o;
    } reqPayload;              /* request payload object (if any) */
    struct {                   /* response warnings */
      cson_value * v;
      cson_array * a;
      int bitset[FSL_JSON_W_END/8/sizeof(int)+1]
      /* allows json_add_warning() to know if a given warning
         has been set or not (we don't produce dupes, to simplify
         downstream loop logic).
      */
      ;
    } warnings;
  } json;
};

/*
** Macro for debugging:
*/
................................................................................
}


/* Print a warning message */
void fossil_warning(const char *zFormat, ...){
  char *z;
  va_list ap;
  if( g.json.isJsonMode ){
      /* The JSON API has no way of dealing with warnings and
         outputing them here will corrupt the output.
      */
      return;
  }
  va_start(ap, zFormat);
  z = vmprintf(zFormat, ap);
  va_end(ap);


  if( g.cgiOutput ){
    cgi_printf("<p class=\"generalError\">%h</p>", z);
  }else{
    char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z);
    fossil_puts(zOut, 1);
    free(zOut);
  }

}

/*
** Malloc and free routines that cannot fail
*/
void *fossil_malloc(size_t n){
  void *p = malloc(n==0 ? 1 : n);







<
<
<
<
<
<







 







<
<
<
<
<
<



>
>
|






>







215
216
217
218
219
220
221






222
223
224
225
226
227
228
...
510
511
512
513
514
515
516






517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
    struct {
      cson_value * v;
      cson_object * o;
    } reqPayload;              /* request payload object (if any) */
    struct {                   /* response warnings */
      cson_value * v;
      cson_array * a;






    } warnings;
  } json;
};

/*
** Macro for debugging:
*/
................................................................................
}


/* Print a warning message */
void fossil_warning(const char *zFormat, ...){
  char *z;
  va_list ap;






  va_start(ap, zFormat);
  z = vmprintf(zFormat, ap);
  va_end(ap);
  if(g.json.isJsonMode){
    json_warn( FSL_JSON_W_UNKNOWN, z );
  }else if( g.cgiOutput ){
    cgi_printf("<p class=\"generalError\">%h</p>", z);
  }else{
    char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z);
    fossil_puts(zOut, 1);
    free(zOut);
  }
  free(z);
}

/*
** Malloc and free routines that cannot fail
*/
void *fossil_malloc(size_t n){
  void *p = malloc(n==0 ? 1 : n);