Fossil

Check-in [fa17e0980c]
Login

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

Overview
Comment:A number of small doc improvements.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | json-multitag-test | json
Files: files | file ages | folders
SHA1: fa17e0980cd098a964a27033deb18a1a83f275ba
User & Date: stephan 2011-10-19 20:36:09.927
Context
2011-10-19
20:54
Fixed a C99/C++ism. Added json_new_string_f() (printf-style). ... (check-in: f5cc421dc2 user: stephan tags: json-multitag-test, json)
20:36
A number of small doc improvements. ... (check-in: fa17e0980c user: stephan tags: json-multitag-test, json)
15:47
fixed json_page_top() and json_cmd_top() to behave as documented when a callback returns non-NULL but does set the error state. ... (check-in: 2f48be58a7 user: stephan tags: json-multitag-test, json)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/json.c.
277
278
279
280
281
282
283
284
285

286
287
288
289
290
291
292
int cson_data_dest_Blob(void * pState, void const * src, unsigned int n){
  Blob * b = (Blob*)pState;
  blob_append( b, (char const *)src, (int)n ) /* will die on OOM */;
  return 0;
}

/*
** Implements the cson_data_source_f() interface and reads
** input from a fossil Blob object. pState must be-a (Blob*).

*/
int cson_data_src_Blob(void * pState, void * dest, unsigned int * n){
  Blob * b = (Blob*)pState;
  *n = blob_read( b, dest, *n );
  return 0;
}








|
|
>







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
int cson_data_dest_Blob(void * pState, void const * src, unsigned int n){
  Blob * b = (Blob*)pState;
  blob_append( b, (char const *)src, (int)n ) /* will die on OOM */;
  return 0;
}

/*
** Implements the cson_data_source_f() interface and reads input from
** a fossil Blob object. pState must be-a (Blob*) populated with JSON
** data.
*/
int cson_data_src_Blob(void * pState, void * dest, unsigned int * n){
  Blob * b = (Blob*)pState;
  *n = blob_read( b, dest, *n );
  return 0;
}

302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/*
** Convenience wrapper around cson_parse() which reads its input
** from pSrc. pSrc is rewound before parsing.
**
** pInfo may be NULL. If it is not NULL then it will contain details
** about the parse state when this function returns.
**
** On success a new JSON Object or Array is returned. On error NULL is
** returned.
*/
cson_value * cson_parse_Blob( Blob * pSrc, cson_parse_info * pInfo ){
  cson_value * root = NULL;
  blob_rewind( pSrc );
  cson_parse( &root, cson_data_src_Blob, pSrc, NULL, pInfo );
  return root;
}







|
|







303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/*
** Convenience wrapper around cson_parse() which reads its input
** from pSrc. pSrc is rewound before parsing.
**
** pInfo may be NULL. If it is not NULL then it will contain details
** about the parse state when this function returns.
**
** On success a new JSON Object or Array is returned (owned by the
** caller). On error NULL is returned.
*/
cson_value * cson_parse_Blob( Blob * pSrc, cson_parse_info * pInfo ){
  cson_value * root = NULL;
  blob_rewind( pSrc );
  cson_parse( &root, cson_data_src_Blob, pSrc, NULL, pInfo );
  return root;
}
367
368
369
370
371
372
373
374




375
376
377
378
379
380
381
  int const rc = cson_array_append( g.json.gc.a, v );
  assert( NULL != g.json.gc.a );
  if( 0 != rc ){
    cson_value_free( v );
  }
  assert( (0==rc) && "Adding item to GC failed." );
  if(0!=rc){
    fprintf(stderr,"%s: FATAL: alloc error.\n", fossil_nameofexe());




    fossil_exit(1)/*not fossil_panic() b/c it might land us somewhere
                    where this function is called again.
                  */;
  }
}









|
>
>
>
>







368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  int const rc = cson_array_append( g.json.gc.a, v );
  assert( NULL != g.json.gc.a );
  if( 0 != rc ){
    cson_value_free( v );
  }
  assert( (0==rc) && "Adding item to GC failed." );
  if(0!=rc){
    fprintf(stderr,"%s: FATAL: alloc error.\n", fossil_nameofexe())
        /* reminder: allocation error is the only reasonable cause of
           error here, provided g.json.gc.a and v are not NULL.
        */
        ;
    fossil_exit(1)/*not fossil_panic() b/c it might land us somewhere
                    where this function is called again.
                  */;
  }
}


435
436
437
438
439
440
441



442
443
444
445
446
447
448
         default for the XYZ param here.
      */
      cv = getenv(zKey);
    }
    if(cv){/*transform it to JSON for later use.*/
      /* use sscanf() to figure out if it's an int,
         and transform it to JSON int if it is.



      */
      int intVal = -1;
      char endOfIntCheck;
      int const scanRc = sscanf(cv,"%d%c",&intVal, &endOfIntCheck)
        /* The %c bit there is to make sure that we don't accept 123x
          as a number. sscanf() returns the number of tokens
          successfully parsed, so an RC of 1 will be correct for "123"







>
>
>







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
         default for the XYZ param here.
      */
      cv = getenv(zKey);
    }
    if(cv){/*transform it to JSON for later use.*/
      /* use sscanf() to figure out if it's an int,
         and transform it to JSON int if it is.

         FIXME: use strtol(), since it has more accurate
         error handling.
      */
      int intVal = -1;
      char endOfIntCheck;
      int const scanRc = sscanf(cv,"%d%c",&intVal, &endOfIntCheck)
        /* The %c bit there is to make sure that we don't accept 123x
          as a number. sscanf() returns the number of tokens
          successfully parsed, so an RC of 1 will be correct for "123"
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
}

/*
** An extended form of find_option() which tries to look up a combo
** GET/POST/CLI argument.
**
** zKey must be the GET/POST parameter key. zCLILong must be the "long
** form" CLI flag (NULL means to use zKey). zCLIShort may be NUL or
** the "short form" CLI flag.
**
** If argPos is >=0 and no other match is found,
** json_command_arg(argPos) is also checked.
**
** On error (no match found) NULL is returned.
**
** This ONLY works for String JSON/GET/CLI values, not JSON







|
|







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
}

/*
** An extended form of find_option() which tries to look up a combo
** GET/POST/CLI argument.
**
** zKey must be the GET/POST parameter key. zCLILong must be the "long
** form" CLI flag (NULL means to use zKey). zCLIShort may be NULL or
** the "short form" CLI flag (if NULL, no short form is used).
**
** If argPos is >=0 and no other match is found,
** json_command_arg(argPos) is also checked.
**
** On error (no match found) NULL is returned.
**
** This ONLY works for String JSON/GET/CLI values, not JSON
611
612
613
614
615
616
617

618
619
620
621
622
623
624
int json_find_option_int(char const * zKey,
                         char const * zCLILong,
                         char const * zCLIShort,
                         int dflt ){
  enum { Magic = -947 };
  int rc = Magic;
  if(!g.isHTTP){

    char const * opt = find_option(zCLILong ? zCLILong : zKey,
                                   zCLIShort, 1);
    if(NULL!=opt){
      rc = atoi(opt);
    }
  }
  if(Magic==rc){







>







619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
int json_find_option_int(char const * zKey,
                         char const * zCLILong,
                         char const * zCLIShort,
                         int dflt ){
  enum { Magic = -947 };
  int rc = Magic;
  if(!g.isHTTP){
    /* FIXME: use strtol() for better error/dflt handling. */
    char const * opt = find_option(zCLILong ? zCLILong : zKey,
                                   zCLIShort, 1);
    if(NULL!=opt){
      rc = atoi(opt);
    }
  }
  if(Magic==rc){
643
644
645
646
647
648
649
650


651
652
653
654
655
656
657
** Guesses a RESPONSE Content-Type value based (primarily) on the
** HTTP_ACCEPT header.
**
** It will try to figure out if the client can support
** application/json or application/javascript, and will fall back to
** text/plain if it cannot figure out anything more specific.
**
** Returned memory is static and immutable.


*/
char const * json_guess_content_type(){
  char const * cset;
  char doUtf8;
  cset = PD("HTTP_ACCEPT_CHARSET",NULL);
  doUtf8 = ((NULL == cset) || (NULL!=strstr("utf-8",cset)))
    ? 1 : 0;







|
>
>







652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
** Guesses a RESPONSE Content-Type value based (primarily) on the
** HTTP_ACCEPT header.
**
** It will try to figure out if the client can support
** application/json or application/javascript, and will fall back to
** text/plain if it cannot figure out anything more specific.
**
** Returned memory is static and immutable, but if the environment
** changes after calling this then subsequent calls to this function
** might return different (also static/immutable) values.
*/
char const * json_guess_content_type(){
  char const * cset;
  char doUtf8;
  cset = PD("HTTP_ACCEPT_CHARSET",NULL);
  doUtf8 = ((NULL == cset) || (NULL!=strstr("utf-8",cset)))
    ? 1 : 0;
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
  if(warnMsg){
    json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
  }
  return v;  
}

/*
** Works just like json_stmt_to_array_of_obj(), but
** each row in the result set is represented as an
** Array instead of an Object.
*/
cson_value * json_stmt_to_array_of_array(Stmt *pStmt,
                                         cson_value * pTgt){
  cson_value * v = pTgt;
  cson_array * a = NULL;
  if(v && !cson_value_is_array(v)){
    return NULL;







|
|
|







1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
  if(warnMsg){
    json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
  }
  return v;  
}

/*
** Works just like json_stmt_to_array_of_obj(), but each row in the
** result set is represented as an Array of values instead of an
** Object (key/value pairs).
*/
cson_value * json_stmt_to_array_of_array(Stmt *pStmt,
                                         cson_value * pTgt){
  cson_value * v = pTgt;
  cson_array * a = NULL;
  if(v && !cson_value_is_array(v)){
    return NULL;
Changes to src/json_detail.h.
106
107
108
109
110
111
112
113
114



115
116
117
118
119
120
121
122
123
124
125
126




127
128
129
130
131
132
133
** success value - it simply means the response will contain no
** payload. If g.json.resultCode is non-zero when this function
** returns then the top-level dispatcher will destroy any payload
** returned by this function and will output a JSON error response
** instead.
**
** All of the setup/response code is handled by the top dispatcher
** functions and the callbacks concern themselves only with generating
** the payload.



**
** It is imperitive that NO callback functions EVER output ANYTHING to
** stdout, as that will effectively corrupt any JSON output, and
** almost certainly will corrupt any HTTP response headers. Output
** sent to stderr ends up in my apache log, so that might be useful
** for debuggering in some cases, but so such code should be left
** enabled for non-debuggering builds.
*/
typedef cson_value * (*fossil_json_f)();

/*
** Holds name-to-function mappings for JSON page/command dispatching.




**
*/
typedef struct JsonPageDef{
  /*
  ** The commmand/page's name (path, not including leading /json/).
  **
  ** Reminder to self: we cannot use sub-paths with commands this way







|
|
>
>
>





|






>
>
>
>







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
** success value - it simply means the response will contain no
** payload. If g.json.resultCode is non-zero when this function
** returns then the top-level dispatcher will destroy any payload
** returned by this function and will output a JSON error response
** instead.
**
** All of the setup/response code is handled by the top dispatcher
** functions and the callbacks concern themselves only with:
**
** a) Permissions checking (inspecting g.perm).
** b) generating a response payload (if applicable)
** c) Setting g.json's error state (if applicable). See json_set_err().
**
** It is imperitive that NO callback functions EVER output ANYTHING to
** stdout, as that will effectively corrupt any JSON output, and
** almost certainly will corrupt any HTTP response headers. Output
** sent to stderr ends up in my apache log, so that might be useful
** for debuggering in some cases, but no such code should be left
** enabled for non-debuggering builds.
*/
typedef cson_value * (*fossil_json_f)();

/*
** Holds name-to-function mappings for JSON page/command dispatching.
**
** Internally we model page dispatching lists as arrays of these
** objects, where the final entry in the array has a NULL name value
** to act as the end-of-list sentinel.
**
*/
typedef struct JsonPageDef{
  /*
  ** The commmand/page's name (path, not including leading /json/).
  **
  ** Reminder to self: we cannot use sub-paths with commands this way
179
180
181
182
183
184
185
186


187
188
189
190
191
192
193
** This function takes the command specified in
** json_comand_arg(1+g.json.dispatchDepth) and searches pages for a
** matching name. If found then that page's func() is called to fetch
** the payload, which is returned to the caller.
**
** On error, g.json.resultCode is set to one of the FossilJsonCodes
** values and NULL is returned. If non-NULL is returned, ownership is
** transfered to the caller.


*/
cson_value * json_page_dispatch_helper(JsonPageDef const * pages);

/*
** Implements the /json/wiki family of pages/commands.
**
*/







|
>
>







186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
** This function takes the command specified in
** json_comand_arg(1+g.json.dispatchDepth) and searches pages for a
** matching name. If found then that page's func() is called to fetch
** the payload, which is returned to the caller.
**
** On error, g.json.resultCode is set to one of the FossilJsonCodes
** values and NULL is returned. If non-NULL is returned, ownership is
** transfered to the caller (but the g.json error state might still be
** set in that case, so the caller must check that or pass it on up
** the dispatch chain).
*/
cson_value * json_page_dispatch_helper(JsonPageDef const * pages);

/*
** Implements the /json/wiki family of pages/commands.
**
*/