Fossil SCM

More work on the warnings infrastructure. json_warn() now (experimentally) disallows (elides) duplicate warning codes to simplify downstream loops. Still undecided on that behaviour, though.

stephan 2011-09-21 17:38 json
Commit 576425e862f08acf94e6e006832d89543e669b93
3 files changed +110 -19 +14 -8 +16 -2
+110 -19
--- src/json.c
+++ src/json.c
@@ -81,10 +81,22 @@
8181
** sent to stderr ends up in my apache log, so that might be useful
8282
** for debuggering in some cases, but so such code should be left
8383
** enabled for non-debuggering builds.
8484
*/
8585
typedef cson_value * (*fossil_json_f)(unsigned int depth);
86
+
87
+/*
88
+** Internal helpers to manipulate a byte array as a bitset. The B
89
+** argument must be-a array at least (BIT/8+1) bytes long.
90
+** The BIT argument is the bit number to query/set/clear/toggle.
91
+*/
92
+#define BITSET_BYTEFOR(B,BIT) ((B)[ BIT / 8 ])
93
+#define BITSET_SET(B,BIT) ((BITSET_BYTEFOR(B,BIT) |= (0x01 << (BIT%8))),0x01)
94
+#define BITSET_UNSET(B,BIT) ((BITSET_BYTEFOR(B,BIT) &= ~(0x01 << (BIT%8))),0x00)
95
+#define BITSET_GET(B,BIT) ((BITSET_BYTEFOR(B,BIT) & (0x01 << (BIT%8))) ? 0x01 : 0x00)
96
+#define BITSET_TOGGLE(B,BIT) (BITSET_GET(B,BIT) ? (BITSET_UNSET(B,BIT)) : (BITSET_SET(B,BIT)))
97
+
8698
8799
/*
88100
** Placeholder /json/XXX page impl for NYI (Not Yet Implemented)
89101
** (but planned) pages/commands.
90102
*/
@@ -463,26 +475,46 @@
463475
g.json.param.o = cson_value_get_object(v);
464476
json_gc_add("$PARAMS", v, 1);
465477
}
466478
467479
/*
468
-** Appends a warning object to the response.
480
+** Appends a warning object to the (pending) JSON response.
469481
**
470
-** TODO: specify what the code must be.
482
+** Code must be a FSL_JSON_W_xxx value from the FossilJsonCodes enum.
471483
**
472484
** A Warning object has this JSON structure:
473485
**
474486
** { "code":integer, "text":"string" }
475487
**
476488
** But the text part is optional.
477489
**
478
-** If msg is non-NULL and not empty then it is used
479
-** as the "text" property's value.
490
+** FIXME FIXME FIXME: i am EXPERIMENTALLY using integer codes instead
491
+** of FOSSIL-XXXX codes here. i may end up switching FOSSIL-XXXX
492
+** string-form codes to integers. Let's ask the mailing list for
493
+** opinions...
494
+**
495
+** If msg is non-NULL and not empty then it is used as the "text"
496
+** property's value. It is copied, and need not refer to static
497
+** memory.
498
+**
499
+** CURRENTLY this code only allows a given warning code to be
500
+** added one time, and elides subsequent warnings. The intention
501
+** is to remove that burden from loops which produce warnings.
502
+**
503
+** FIXME: if msg is NULL then use a standard string for
504
+** the given code. If !*msg then elide the "text" property,
505
+** for consistency with how json_err() works.
480506
*/
481
-void json_add_warning( int code, char const * msg ){
507
+void json_warn( int code, char const * msg ){
482508
cson_value * objV = NULL;
483509
cson_object * obj = NULL;
510
+ assert( (code>FSL_JSON_W_START)
511
+ && (code<FSL_JSON_W_END)
512
+ && "Invalid warning code.");
513
+ if( BITSET_GET(g.json.warnings.bitset,code) ){
514
+ return;
515
+ }
484516
if(!g.json.warnings.v){
485517
g.json.warnings.v = cson_value_new_array();
486518
assert((NULL != g.json.warnings.v) && "Alloc error.");
487519
g.json.warnings.a = cson_value_get_array(g.json.warnings.v);
488520
json_gc_add("$WARNINGS",g.json.warnings.v,0);
@@ -496,10 +528,11 @@
496528
/* FIXME: treat NULL msg as standard warning message for
497529
the code, but we don't have those yet.
498530
*/
499531
cson_object_set(obj,"text",cson_value_new_string(msg,strlen(msg)));
500532
}
533
+ BITSET_SET(g.json.warnings.bitset,code);
501534
}
502535
503536
/*
504537
** Splits zStr (which must not be NULL) into tokens separated by the
505538
** given separator character. If doDeHttp is true then each element
@@ -553,10 +586,18 @@
553586
rc = rc ? -rc : 0;
554587
break;
555588
}
556589
}else{
557590
assert(0 && "i didn't think this was possible!");
591
+ fprintf(stderr,"%s:%d: My God! It's full of stars!\n",
592
+ __FILE__, __LINE__);
593
+ fossil_exit(1)
594
+ /* Not fossil_panic() b/c this code needs to be able to
595
+ run before some of the fossil/json bits are initialized,
596
+ and fossil_panic() calls into the JSON API.
597
+ */
598
+ ;
558599
}
559600
free(zPart);
560601
len = 0;
561602
}
562603
if( !*p ){
@@ -567,10 +608,36 @@
567608
}
568609
++len;
569610
}
570611
return rc;
571612
}
613
+
614
+/*
615
+** Wrapper around json_string_split(), taking the same first 3
616
+** parameters as this function, but returns the results as
617
+** a JSON Array (if splitting produced tokens)
618
+** OR a JSON null value (if splitting produced no tokens)
619
+** OR NULL (if splitting failed in any way).
620
+**
621
+** The returned value is owned by the caller. If not NULL then it
622
+** _will_ have a JSON type of Array or Null.
623
+*/
624
+cson_value * json_string_split2( char const * zStr,
625
+ char separator,
626
+ char doDeHttp ){
627
+ cson_value * v = cson_value_new_array();
628
+ cson_array * a = cson_value_get_array(v);
629
+ int rc = json_string_split( zStr, separator, doDeHttp, a );
630
+ if( 0 == rc ){
631
+ cson_value_free(v);
632
+ v = cson_value_null();
633
+ }else if(rc<0){
634
+ cson_value_free(v);
635
+ v = NULL;
636
+ }
637
+ return v;
638
+}
572639
573640
/*
574641
** Performs some common initialization of JSON-related state. Must be
575642
** called by the json_page_top() and json_cmd_top() dispatching
576643
** functions to set up the JSON stat used by the dispatched functions.
@@ -799,16 +866,19 @@
799866
/*
800867
** Given a Fossil/JSON result code, this function "dumbs it down"
801868
** according to the current value of g.json.errorDetailParanoia. The
802869
** dumbed-down value is returned.
803870
**
804
-** This function assert()s that code is either 0
805
-** or between the range of 1000 and 9999.
871
+** This function assert()s that code is in the inclusive range 0 to
872
+** 9999.
873
+**
874
+** Note that WARNING codes (1..999) are never dumbed down.
875
+**
806876
*/
807877
static int json_dumbdown_rc( int code ){
808
- if( !code ){
809
- return 0;
878
+ if(!code || ((code>FSL_JSON_W_START) && (code>FSL_JSON_W_END))){
879
+ return code;
810880
}else{
811881
int modulo = 0;
812882
assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
813883
switch( g.json.errorDetailParanoia ){
814884
case 1: modulo = 10; break;
@@ -1595,11 +1665,10 @@
15951665
" brief AS briefText"
15961666
" FROM json_timeline"
15971667
" ORDER BY mtime DESC",
15981668
-1);
15991669
db_prepare(&q,blob_buffer(&sql));
1600
- tmp = NULL;
16011670
listV = cson_value_new_array();
16021671
list = cson_value_get_array(listV);
16031672
tmp = listV;
16041673
SET("timeline");
16051674
while( (SQLITE_ROW == db_step(&q) )){
@@ -1606,27 +1675,42 @@
16061675
/* convert each row into a JSON object...*/
16071676
cson_value * rowV = cson_sqlite3_row_to_object(q.pStmt);
16081677
cson_object * row = cson_value_get_object(rowV);
16091678
cson_string const * tagsStr = NULL;
16101679
if(!row){
1611
- /* need a way of warning about this */
1680
+ json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED,
1681
+ "Could not convert at least one timeline result row to JSON." );
16121682
continue;
16131683
}
1614
-
16151684
/* Split tags string field into JSON Array... */
16161685
cson_array_append(list, rowV);
16171686
tagsStr = cson_value_get_string(cson_object_get(row,"tags"));
16181687
if(tagsStr){
1619
- cson_value * tagsV = cson_value_new_array();
1620
- cson_array * tags = cson_value_get_array(tagsV);
1621
- if( 0 < json_string_split( cson_string_cstr(tagsStr), ',', 0, tags)){
1622
- cson_object_set(row,"tags",tagsV)
1623
- /*replaces/deletes old tags value, invalidating tagsStr!*/;
1688
+ cson_value * tags = json_string_split2( cson_string_cstr(tagsStr),
1689
+ ',', 0);
1690
+ if( tags ){
1691
+ if(0 != cson_object_set(row,"tags",tags)){
1692
+ cson_value_free(tags);
1693
+ }else{
1694
+ /*replaced/deleted old tags value, invalidating tagsStr*/;
1695
+ tagsStr = NULL;
1696
+ }
16241697
}else{
1625
- cson_value_free(tagsV);
1698
+ json_warn(FSL_JSON_W_STRING_TO_ARRAY_FAILED,
1699
+ "Could not convert tags string to array.");
16261700
}
16271701
}
1702
+
1703
+ /* replace isLeaf int w/ JSON bool */
1704
+ tmp = cson_object_get(row,"isLeaf");
1705
+ if(tmp && cson_value_is_integer(tmp)){
1706
+ cson_object_set(row,"isLeaf",
1707
+ cson_value_get_integer(tmp)
1708
+ ? cson_value_true()
1709
+ : cson_value_false());
1710
+ tmp = NULL;
1711
+ }
16281712
}
16291713
db_finalize(&q);
16301714
#undef SET
16311715
goto ok;
16321716
error:
@@ -1787,11 +1871,12 @@
17871871
if( g.argc<3 ){
17881872
goto usage;
17891873
}
17901874
db_find_and_open_repository(0, 0);
17911875
#if 0
1792
- json_add_warning(-1, "Just testing.");
1876
+ json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
1877
+ json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again.");
17931878
#endif
17941879
cmd = json_command_arg(1);
17951880
if( !cmd || !*cmd ){
17961881
goto usage;
17971882
}
@@ -1821,5 +1906,11 @@
18211906
}
18221907
return;
18231908
usage:
18241909
usage("subcommand");
18251910
}
1911
+
1912
+#undef BITSET_BYTEFOR
1913
+#undef BITSET_SET
1914
+#undef BITSET_UNSET
1915
+#undef BITSET_GET
1916
+#undef BITSET_TOGGLE
18261917
--- src/json.c
+++ src/json.c
@@ -81,10 +81,22 @@
81 ** sent to stderr ends up in my apache log, so that might be useful
82 ** for debuggering in some cases, but so such code should be left
83 ** enabled for non-debuggering builds.
84 */
85 typedef cson_value * (*fossil_json_f)(unsigned int depth);
 
 
 
 
 
 
 
 
 
 
 
 
86
87 /*
88 ** Placeholder /json/XXX page impl for NYI (Not Yet Implemented)
89 ** (but planned) pages/commands.
90 */
@@ -463,26 +475,46 @@
463 g.json.param.o = cson_value_get_object(v);
464 json_gc_add("$PARAMS", v, 1);
465 }
466
467 /*
468 ** Appends a warning object to the response.
469 **
470 ** TODO: specify what the code must be.
471 **
472 ** A Warning object has this JSON structure:
473 **
474 ** { "code":integer, "text":"string" }
475 **
476 ** But the text part is optional.
477 **
478 ** If msg is non-NULL and not empty then it is used
479 ** as the "text" property's value.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480 */
481 void json_add_warning( int code, char const * msg ){
482 cson_value * objV = NULL;
483 cson_object * obj = NULL;
 
 
 
 
 
 
484 if(!g.json.warnings.v){
485 g.json.warnings.v = cson_value_new_array();
486 assert((NULL != g.json.warnings.v) && "Alloc error.");
487 g.json.warnings.a = cson_value_get_array(g.json.warnings.v);
488 json_gc_add("$WARNINGS",g.json.warnings.v,0);
@@ -496,10 +528,11 @@
496 /* FIXME: treat NULL msg as standard warning message for
497 the code, but we don't have those yet.
498 */
499 cson_object_set(obj,"text",cson_value_new_string(msg,strlen(msg)));
500 }
 
501 }
502
503 /*
504 ** Splits zStr (which must not be NULL) into tokens separated by the
505 ** given separator character. If doDeHttp is true then each element
@@ -553,10 +586,18 @@
553 rc = rc ? -rc : 0;
554 break;
555 }
556 }else{
557 assert(0 && "i didn't think this was possible!");
 
 
 
 
 
 
 
 
558 }
559 free(zPart);
560 len = 0;
561 }
562 if( !*p ){
@@ -567,10 +608,36 @@
567 }
568 ++len;
569 }
570 return rc;
571 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
573 /*
574 ** Performs some common initialization of JSON-related state. Must be
575 ** called by the json_page_top() and json_cmd_top() dispatching
576 ** functions to set up the JSON stat used by the dispatched functions.
@@ -799,16 +866,19 @@
799 /*
800 ** Given a Fossil/JSON result code, this function "dumbs it down"
801 ** according to the current value of g.json.errorDetailParanoia. The
802 ** dumbed-down value is returned.
803 **
804 ** This function assert()s that code is either 0
805 ** or between the range of 1000 and 9999.
 
 
 
806 */
807 static int json_dumbdown_rc( int code ){
808 if( !code ){
809 return 0;
810 }else{
811 int modulo = 0;
812 assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
813 switch( g.json.errorDetailParanoia ){
814 case 1: modulo = 10; break;
@@ -1595,11 +1665,10 @@
1595 " brief AS briefText"
1596 " FROM json_timeline"
1597 " ORDER BY mtime DESC",
1598 -1);
1599 db_prepare(&q,blob_buffer(&sql));
1600 tmp = NULL;
1601 listV = cson_value_new_array();
1602 list = cson_value_get_array(listV);
1603 tmp = listV;
1604 SET("timeline");
1605 while( (SQLITE_ROW == db_step(&q) )){
@@ -1606,27 +1675,42 @@
1606 /* convert each row into a JSON object...*/
1607 cson_value * rowV = cson_sqlite3_row_to_object(q.pStmt);
1608 cson_object * row = cson_value_get_object(rowV);
1609 cson_string const * tagsStr = NULL;
1610 if(!row){
1611 /* need a way of warning about this */
 
1612 continue;
1613 }
1614
1615 /* Split tags string field into JSON Array... */
1616 cson_array_append(list, rowV);
1617 tagsStr = cson_value_get_string(cson_object_get(row,"tags"));
1618 if(tagsStr){
1619 cson_value * tagsV = cson_value_new_array();
1620 cson_array * tags = cson_value_get_array(tagsV);
1621 if( 0 < json_string_split( cson_string_cstr(tagsStr), ',', 0, tags)){
1622 cson_object_set(row,"tags",tagsV)
1623 /*replaces/deletes old tags value, invalidating tagsStr!*/;
 
 
 
 
1624 }else{
1625 cson_value_free(tagsV);
 
1626 }
1627 }
 
 
 
 
 
 
 
 
 
 
1628 }
1629 db_finalize(&q);
1630 #undef SET
1631 goto ok;
1632 error:
@@ -1787,11 +1871,12 @@
1787 if( g.argc<3 ){
1788 goto usage;
1789 }
1790 db_find_and_open_repository(0, 0);
1791 #if 0
1792 json_add_warning(-1, "Just testing.");
 
1793 #endif
1794 cmd = json_command_arg(1);
1795 if( !cmd || !*cmd ){
1796 goto usage;
1797 }
@@ -1821,5 +1906,11 @@
1821 }
1822 return;
1823 usage:
1824 usage("subcommand");
1825 }
 
 
 
 
 
 
1826
--- src/json.c
+++ src/json.c
@@ -81,10 +81,22 @@
81 ** sent to stderr ends up in my apache log, so that might be useful
82 ** for debuggering in some cases, but so such code should be left
83 ** enabled for non-debuggering builds.
84 */
85 typedef cson_value * (*fossil_json_f)(unsigned int depth);
86
87 /*
88 ** Internal helpers to manipulate a byte array as a bitset. The B
89 ** argument must be-a array at least (BIT/8+1) bytes long.
90 ** The BIT argument is the bit number to query/set/clear/toggle.
91 */
92 #define BITSET_BYTEFOR(B,BIT) ((B)[ BIT / 8 ])
93 #define BITSET_SET(B,BIT) ((BITSET_BYTEFOR(B,BIT) |= (0x01 << (BIT%8))),0x01)
94 #define BITSET_UNSET(B,BIT) ((BITSET_BYTEFOR(B,BIT) &= ~(0x01 << (BIT%8))),0x00)
95 #define BITSET_GET(B,BIT) ((BITSET_BYTEFOR(B,BIT) & (0x01 << (BIT%8))) ? 0x01 : 0x00)
96 #define BITSET_TOGGLE(B,BIT) (BITSET_GET(B,BIT) ? (BITSET_UNSET(B,BIT)) : (BITSET_SET(B,BIT)))
97
98
99 /*
100 ** Placeholder /json/XXX page impl for NYI (Not Yet Implemented)
101 ** (but planned) pages/commands.
102 */
@@ -463,26 +475,46 @@
475 g.json.param.o = cson_value_get_object(v);
476 json_gc_add("$PARAMS", v, 1);
477 }
478
479 /*
480 ** Appends a warning object to the (pending) JSON response.
481 **
482 ** Code must be a FSL_JSON_W_xxx value from the FossilJsonCodes enum.
483 **
484 ** A Warning object has this JSON structure:
485 **
486 ** { "code":integer, "text":"string" }
487 **
488 ** But the text part is optional.
489 **
490 ** FIXME FIXME FIXME: i am EXPERIMENTALLY using integer codes instead
491 ** of FOSSIL-XXXX codes here. i may end up switching FOSSIL-XXXX
492 ** string-form codes to integers. Let's ask the mailing list for
493 ** opinions...
494 **
495 ** If msg is non-NULL and not empty then it is used as the "text"
496 ** property's value. It is copied, and need not refer to static
497 ** memory.
498 **
499 ** CURRENTLY this code only allows a given warning code to be
500 ** added one time, and elides subsequent warnings. The intention
501 ** is to remove that burden from loops which produce warnings.
502 **
503 ** FIXME: if msg is NULL then use a standard string for
504 ** the given code. If !*msg then elide the "text" property,
505 ** for consistency with how json_err() works.
506 */
507 void json_warn( int code, char const * msg ){
508 cson_value * objV = NULL;
509 cson_object * obj = NULL;
510 assert( (code>FSL_JSON_W_START)
511 && (code<FSL_JSON_W_END)
512 && "Invalid warning code.");
513 if( BITSET_GET(g.json.warnings.bitset,code) ){
514 return;
515 }
516 if(!g.json.warnings.v){
517 g.json.warnings.v = cson_value_new_array();
518 assert((NULL != g.json.warnings.v) && "Alloc error.");
519 g.json.warnings.a = cson_value_get_array(g.json.warnings.v);
520 json_gc_add("$WARNINGS",g.json.warnings.v,0);
@@ -496,10 +528,11 @@
528 /* FIXME: treat NULL msg as standard warning message for
529 the code, but we don't have those yet.
530 */
531 cson_object_set(obj,"text",cson_value_new_string(msg,strlen(msg)));
532 }
533 BITSET_SET(g.json.warnings.bitset,code);
534 }
535
536 /*
537 ** Splits zStr (which must not be NULL) into tokens separated by the
538 ** given separator character. If doDeHttp is true then each element
@@ -553,10 +586,18 @@
586 rc = rc ? -rc : 0;
587 break;
588 }
589 }else{
590 assert(0 && "i didn't think this was possible!");
591 fprintf(stderr,"%s:%d: My God! It's full of stars!\n",
592 __FILE__, __LINE__);
593 fossil_exit(1)
594 /* Not fossil_panic() b/c this code needs to be able to
595 run before some of the fossil/json bits are initialized,
596 and fossil_panic() calls into the JSON API.
597 */
598 ;
599 }
600 free(zPart);
601 len = 0;
602 }
603 if( !*p ){
@@ -567,10 +608,36 @@
608 }
609 ++len;
610 }
611 return rc;
612 }
613
614 /*
615 ** Wrapper around json_string_split(), taking the same first 3
616 ** parameters as this function, but returns the results as
617 ** a JSON Array (if splitting produced tokens)
618 ** OR a JSON null value (if splitting produced no tokens)
619 ** OR NULL (if splitting failed in any way).
620 **
621 ** The returned value is owned by the caller. If not NULL then it
622 ** _will_ have a JSON type of Array or Null.
623 */
624 cson_value * json_string_split2( char const * zStr,
625 char separator,
626 char doDeHttp ){
627 cson_value * v = cson_value_new_array();
628 cson_array * a = cson_value_get_array(v);
629 int rc = json_string_split( zStr, separator, doDeHttp, a );
630 if( 0 == rc ){
631 cson_value_free(v);
632 v = cson_value_null();
633 }else if(rc<0){
634 cson_value_free(v);
635 v = NULL;
636 }
637 return v;
638 }
639
640 /*
641 ** Performs some common initialization of JSON-related state. Must be
642 ** called by the json_page_top() and json_cmd_top() dispatching
643 ** functions to set up the JSON stat used by the dispatched functions.
@@ -799,16 +866,19 @@
866 /*
867 ** Given a Fossil/JSON result code, this function "dumbs it down"
868 ** according to the current value of g.json.errorDetailParanoia. The
869 ** dumbed-down value is returned.
870 **
871 ** This function assert()s that code is in the inclusive range 0 to
872 ** 9999.
873 **
874 ** Note that WARNING codes (1..999) are never dumbed down.
875 **
876 */
877 static int json_dumbdown_rc( int code ){
878 if(!code || ((code>FSL_JSON_W_START) && (code>FSL_JSON_W_END))){
879 return code;
880 }else{
881 int modulo = 0;
882 assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
883 switch( g.json.errorDetailParanoia ){
884 case 1: modulo = 10; break;
@@ -1595,11 +1665,10 @@
1665 " brief AS briefText"
1666 " FROM json_timeline"
1667 " ORDER BY mtime DESC",
1668 -1);
1669 db_prepare(&q,blob_buffer(&sql));
 
1670 listV = cson_value_new_array();
1671 list = cson_value_get_array(listV);
1672 tmp = listV;
1673 SET("timeline");
1674 while( (SQLITE_ROW == db_step(&q) )){
@@ -1606,27 +1675,42 @@
1675 /* convert each row into a JSON object...*/
1676 cson_value * rowV = cson_sqlite3_row_to_object(q.pStmt);
1677 cson_object * row = cson_value_get_object(rowV);
1678 cson_string const * tagsStr = NULL;
1679 if(!row){
1680 json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED,
1681 "Could not convert at least one timeline result row to JSON." );
1682 continue;
1683 }
 
1684 /* Split tags string field into JSON Array... */
1685 cson_array_append(list, rowV);
1686 tagsStr = cson_value_get_string(cson_object_get(row,"tags"));
1687 if(tagsStr){
1688 cson_value * tags = json_string_split2( cson_string_cstr(tagsStr),
1689 ',', 0);
1690 if( tags ){
1691 if(0 != cson_object_set(row,"tags",tags)){
1692 cson_value_free(tags);
1693 }else{
1694 /*replaced/deleted old tags value, invalidating tagsStr*/;
1695 tagsStr = NULL;
1696 }
1697 }else{
1698 json_warn(FSL_JSON_W_STRING_TO_ARRAY_FAILED,
1699 "Could not convert tags string to array.");
1700 }
1701 }
1702
1703 /* replace isLeaf int w/ JSON bool */
1704 tmp = cson_object_get(row,"isLeaf");
1705 if(tmp && cson_value_is_integer(tmp)){
1706 cson_object_set(row,"isLeaf",
1707 cson_value_get_integer(tmp)
1708 ? cson_value_true()
1709 : cson_value_false());
1710 tmp = NULL;
1711 }
1712 }
1713 db_finalize(&q);
1714 #undef SET
1715 goto ok;
1716 error:
@@ -1787,11 +1871,12 @@
1871 if( g.argc<3 ){
1872 goto usage;
1873 }
1874 db_find_and_open_repository(0, 0);
1875 #if 0
1876 json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
1877 json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again.");
1878 #endif
1879 cmd = json_command_arg(1);
1880 if( !cmd || !*cmd ){
1881 goto usage;
1882 }
@@ -1821,5 +1906,11 @@
1906 }
1907 return;
1908 usage:
1909 usage("subcommand");
1910 }
1911
1912 #undef BITSET_BYTEFOR
1913 #undef BITSET_SET
1914 #undef BITSET_UNSET
1915 #undef BITSET_GET
1916 #undef BITSET_TOGGLE
1917
--- src/json_detail.h
+++ src/json_detail.h
@@ -2,23 +2,28 @@
22
** Impl details for the JSON API which need to be shared
33
** across multiple C files.
44
*/
55
66
/*
7
-** The "official" list of Fossil/JSON error codes.
8
-** Their values might very well change during initial
9
-** development but after their first public release
10
-** they must stay stable.
11
-** Values must be in the range 1..9999
7
+** The "official" list of Fossil/JSON error codes. Their values might
8
+** very well change during initial development but after their first
9
+** public release they must stay stable.
10
+**
11
+** Values must be in the range 1000..9999 for error codes and 1..999
12
+** for warning codes.
1213
**
13
-** Numbers evenly dividable by 100 are "categories",
14
-** and error codes for a given category have their
15
-** high bits set to the category value.
14
+** Numbers evenly dividable by 100 are "categories", and error codes
15
+** for a given category have their high bits set to the category
16
+** value.
1617
**
1718
*/
1819
enum FossilJsonCodes {
20
+FSL_JSON_W_START = 0,
21
+FSL_JSON_W_ROW_TO_JSON_FAILED = FSL_JSON_W_START + 1,
22
+FSL_JSON_W_STRING_TO_ARRAY_FAILED = FSL_JSON_W_START + 2,
1923
24
+FSL_JSON_W_END = 1000,
2025
FSL_JSON_E_GENERIC = 1000,
2126
FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100,
2227
FSL_JSON_E_INVALID_REQUEST = FSL_JSON_E_GENERIC_SUB1 + 1,
2328
FSL_JSON_E_UNKNOWN_COMMAND = FSL_JSON_E_GENERIC_SUB1 + 2,
2429
FSL_JSON_E_UNKNOWN = FSL_JSON_E_GENERIC_SUB1 + 3,
@@ -49,7 +54,8 @@
4954
FSL_JSON_E_STMT_BIND = FSL_JSON_E_DB + 2,
5055
FSL_JSON_E_STMT_EXEC = FSL_JSON_E_DB + 3,
5156
FSL_JSON_E_DB_LOCKED = FSL_JSON_E_DB + 4,
5257
5358
FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101
59
+
5460
};
5561
5662
--- src/json_detail.h
+++ src/json_detail.h
@@ -2,23 +2,28 @@
2 ** Impl details for the JSON API which need to be shared
3 ** across multiple C files.
4 */
5
6 /*
7 ** The "official" list of Fossil/JSON error codes.
8 ** Their values might very well change during initial
9 ** development but after their first public release
10 ** they must stay stable.
11 ** Values must be in the range 1..9999
 
12 **
13 ** Numbers evenly dividable by 100 are "categories",
14 ** and error codes for a given category have their
15 ** high bits set to the category value.
16 **
17 */
18 enum FossilJsonCodes {
 
 
 
19
 
20 FSL_JSON_E_GENERIC = 1000,
21 FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100,
22 FSL_JSON_E_INVALID_REQUEST = FSL_JSON_E_GENERIC_SUB1 + 1,
23 FSL_JSON_E_UNKNOWN_COMMAND = FSL_JSON_E_GENERIC_SUB1 + 2,
24 FSL_JSON_E_UNKNOWN = FSL_JSON_E_GENERIC_SUB1 + 3,
@@ -49,7 +54,8 @@
49 FSL_JSON_E_STMT_BIND = FSL_JSON_E_DB + 2,
50 FSL_JSON_E_STMT_EXEC = FSL_JSON_E_DB + 3,
51 FSL_JSON_E_DB_LOCKED = FSL_JSON_E_DB + 4,
52
53 FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101
 
54 };
55
56
--- src/json_detail.h
+++ src/json_detail.h
@@ -2,23 +2,28 @@
2 ** Impl details for the JSON API which need to be shared
3 ** across multiple C files.
4 */
5
6 /*
7 ** The "official" list of Fossil/JSON error codes. Their values might
8 ** very well change during initial development but after their first
9 ** public release they must stay stable.
10 **
11 ** Values must be in the range 1000..9999 for error codes and 1..999
12 ** for warning codes.
13 **
14 ** Numbers evenly dividable by 100 are "categories", and error codes
15 ** for a given category have their high bits set to the category
16 ** value.
17 **
18 */
19 enum FossilJsonCodes {
20 FSL_JSON_W_START = 0,
21 FSL_JSON_W_ROW_TO_JSON_FAILED = FSL_JSON_W_START + 1,
22 FSL_JSON_W_STRING_TO_ARRAY_FAILED = FSL_JSON_W_START + 2,
23
24 FSL_JSON_W_END = 1000,
25 FSL_JSON_E_GENERIC = 1000,
26 FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100,
27 FSL_JSON_E_INVALID_REQUEST = FSL_JSON_E_GENERIC_SUB1 + 1,
28 FSL_JSON_E_UNKNOWN_COMMAND = FSL_JSON_E_GENERIC_SUB1 + 2,
29 FSL_JSON_E_UNKNOWN = FSL_JSON_E_GENERIC_SUB1 + 3,
@@ -49,7 +54,8 @@
54 FSL_JSON_E_STMT_BIND = FSL_JSON_E_DB + 2,
55 FSL_JSON_E_STMT_EXEC = FSL_JSON_E_DB + 3,
56 FSL_JSON_E_DB_LOCKED = FSL_JSON_E_DB + 4,
57
58 FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101
59
60 };
61
62
+16 -2
--- src/main.c
+++ src/main.c
@@ -27,10 +27,11 @@
2727
#include <sys/stat.h>
2828
#include <stdlib.h> /* atexit() */
2929
3030
#if INTERFACE
3131
#include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */
32
+#include "json_detail.h"
3233
3334
/*
3435
** Number of elements in an array
3536
*/
3637
#define count(X) (sizeof(X)/sizeof(X[0]))
@@ -210,10 +211,16 @@
210211
cson_object * o;
211212
} reqPayload; /* request payload object (if any) */
212213
struct { /* response warnings */
213214
cson_value * v;
214215
cson_array * a;
216
+ int bitset[FSL_JSON_W_END/8/sizeof(int)+1]
217
+ /* allows json_add_warning() to know if a given warning
218
+ has been set or not (we don't produce dupes, to simplify
219
+ downstream loop logic).
220
+ */
221
+ ;
215222
} warnings;
216223
} json;
217224
};
218225
219226
/*
@@ -476,25 +483,32 @@
476483
** be prepared for this routine to return.
477484
*/
478485
void fossil_fatal_recursive(const char *zFormat, ...){
479486
char *z;
480487
va_list ap;
488
+ int rc = 1;
481489
if( mainInFatalError ) return;
482490
mainInFatalError = 1;
483491
va_start(ap, zFormat);
484492
z = vmprintf(zFormat, ap);
485493
va_end(ap);
486
- if( g.cgiOutput ){
494
+ if( g.json.isJsonMode ){
495
+ json_err( g.json.resultCode, z, 1 );
496
+ if( g.isHTTP ){
497
+ rc = 0 /* avoid HTTP 500 */;
498
+ }
499
+ }else if( g.cgiOutput ){
487500
g.cgiOutput = 0;
488501
cgi_printf("<p class=\"generalError\">%h</p>", z);
489502
cgi_reply();
490503
}else{
491504
char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z);
492505
fossil_puts(zOut, 1);
506
+ free(zOut);
493507
}
494508
db_force_rollback();
495
- fossil_exit(1);
509
+ fossil_exit(rc);
496510
}
497511
498512
499513
/* Print a warning message */
500514
void fossil_warning(const char *zFormat, ...){
501515
--- src/main.c
+++ src/main.c
@@ -27,10 +27,11 @@
27 #include <sys/stat.h>
28 #include <stdlib.h> /* atexit() */
29
30 #if INTERFACE
31 #include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */
 
32
33 /*
34 ** Number of elements in an array
35 */
36 #define count(X) (sizeof(X)/sizeof(X[0]))
@@ -210,10 +211,16 @@
210 cson_object * o;
211 } reqPayload; /* request payload object (if any) */
212 struct { /* response warnings */
213 cson_value * v;
214 cson_array * a;
 
 
 
 
 
 
215 } warnings;
216 } json;
217 };
218
219 /*
@@ -476,25 +483,32 @@
476 ** be prepared for this routine to return.
477 */
478 void fossil_fatal_recursive(const char *zFormat, ...){
479 char *z;
480 va_list ap;
 
481 if( mainInFatalError ) return;
482 mainInFatalError = 1;
483 va_start(ap, zFormat);
484 z = vmprintf(zFormat, ap);
485 va_end(ap);
486 if( g.cgiOutput ){
 
 
 
 
 
487 g.cgiOutput = 0;
488 cgi_printf("<p class=\"generalError\">%h</p>", z);
489 cgi_reply();
490 }else{
491 char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z);
492 fossil_puts(zOut, 1);
 
493 }
494 db_force_rollback();
495 fossil_exit(1);
496 }
497
498
499 /* Print a warning message */
500 void fossil_warning(const char *zFormat, ...){
501
--- src/main.c
+++ src/main.c
@@ -27,10 +27,11 @@
27 #include <sys/stat.h>
28 #include <stdlib.h> /* atexit() */
29
30 #if INTERFACE
31 #include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */
32 #include "json_detail.h"
33
34 /*
35 ** Number of elements in an array
36 */
37 #define count(X) (sizeof(X)/sizeof(X[0]))
@@ -210,10 +211,16 @@
211 cson_object * o;
212 } reqPayload; /* request payload object (if any) */
213 struct { /* response warnings */
214 cson_value * v;
215 cson_array * a;
216 int bitset[FSL_JSON_W_END/8/sizeof(int)+1]
217 /* allows json_add_warning() to know if a given warning
218 has been set or not (we don't produce dupes, to simplify
219 downstream loop logic).
220 */
221 ;
222 } warnings;
223 } json;
224 };
225
226 /*
@@ -476,25 +483,32 @@
483 ** be prepared for this routine to return.
484 */
485 void fossil_fatal_recursive(const char *zFormat, ...){
486 char *z;
487 va_list ap;
488 int rc = 1;
489 if( mainInFatalError ) return;
490 mainInFatalError = 1;
491 va_start(ap, zFormat);
492 z = vmprintf(zFormat, ap);
493 va_end(ap);
494 if( g.json.isJsonMode ){
495 json_err( g.json.resultCode, z, 1 );
496 if( g.isHTTP ){
497 rc = 0 /* avoid HTTP 500 */;
498 }
499 }else if( g.cgiOutput ){
500 g.cgiOutput = 0;
501 cgi_printf("<p class=\"generalError\">%h</p>", z);
502 cgi_reply();
503 }else{
504 char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z);
505 fossil_puts(zOut, 1);
506 free(zOut);
507 }
508 db_force_rollback();
509 fossil_exit(rc);
510 }
511
512
513 /* Print a warning message */
514 void fossil_warning(const char *zFormat, ...){
515

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button