Fossil

Check-in [9fe06e2fda]
Login

Check-in [9fe06e2fda]

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
Timelines: family | ancestors | descendants | both | json
Files: files | file ages | folders
SHA1: 9fe06e2fdad0dba1492a972e2352a3c3c0633fa4
User & Date: stephan 2011-09-29 21:57:00.848
Context
2011-09-29
22:27
json ajax: fixed POST/GET message sending determination (broken by a previous change this evening). ... (check-in: 37963253b9 user: stephan tags: json)
21:57
Removed the json warnings bitset crap. Still not sure i like the warnings mechanism at all. ... (check-in: 9fe06e2fda user: stephan tags: json)
21:55
Corrected a JSON-mode result code when db rebuild is required. ... (check-in: 44644d43dc user: stephan tags: json)
Changes
Unified Diff 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
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
*/
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();
  assert((NULL != objV) && "Alloc error.");
  cson_array_append(g.json.warnings.a, objV);
  obj = cson_value_get_object(objV);
  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







<
<
<

















<







724
725
726
727
728
729
730



731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747

748
749
750
751
752
753
754
*/
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();
  assert((NULL != objV) && "Alloc error.");
  cson_array_append(g.json.warnings.a, objV);
  obj = cson_value_get_object(objV);
  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
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
** 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).







|
|


>



|
<
|




>
>
>







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
** 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).
1604
1605
1606
1607
1608
1609
1610

1611
1612
1613
1614
1615
1616
1617
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);







>







1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
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);
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677



1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
  
  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(){







|
|
|
>
>
>
|
|
|
<







1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683

1684
1685
1686
1687
1688
1689
1690
  
  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
  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);







>
>







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  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);
312
313
314
315
316
317
318
319

320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

338
339
340
341
342
343
344
  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(tagsStr){
      cson_value * tags = json_string_split2( cson_string_cstr(tagsStr),
                                              ',', 0);
      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");







|
>

















|
>







314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  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(tagsStr){
      cson_value * tags = json_string_split2( cson_string_cstr(tagsStr),
                                              ',', 0);
      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");
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
             " 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:







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







422
423
424
425
426
427
428










429








430
431
432
433
434
435
436
             " 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
    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:
*/







<
<
<
<
<
<







215
216
217
218
219
220
221






222
223
224
225
226
227
228
    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:
*/
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
}


/* 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);







<
<
<
<
<
<



>
>
|






>







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
}


/* 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);