| | @@ -183,10 +183,30 @@ |
| 183 | 183 | #define BEGIN_TIMER |
| 184 | 184 | #define END_TIMER 0.0 |
| 185 | 185 | #define HAS_TIMER 0 |
| 186 | 186 | #endif |
| 187 | 187 | |
| 188 | + |
| 189 | +/* |
| 190 | +** Returns true if fossil is running in JSON mode and we are either |
| 191 | +** running in HTTP mode OR g.json.post.o is not NULL (meaning POST |
| 192 | +** data was fed in from CLI mode). |
| 193 | +** |
| 194 | +** Specifically, it will return false when any of these apply: |
| 195 | +** |
| 196 | +** a) Not running in JSON mode (via json command or /json path). |
| 197 | +** |
| 198 | +** b) We are running in JSON CLI mode, but no POST data has been fed |
| 199 | +** in. |
| 200 | +** |
| 201 | +** Whether or not we need to take args from CLI or POST data makes a |
| 202 | +** difference in argument/parameter handling in many JSON rountines. |
| 203 | +*/ |
| 204 | +char fossil_is_json(){ |
| 205 | + return g.json.isJsonMode && (g.isHTTP || g.json.post.o); |
| 206 | +} |
| 207 | + |
| 188 | 208 | /* |
| 189 | 209 | ** Placeholder /json/XXX page impl for NYI (Not Yet Implemented) |
| 190 | 210 | ** (but planned) pages/commands. |
| 191 | 211 | */ |
| 192 | 212 | cson_value * json_page_nyi(){ |
| | @@ -466,10 +486,16 @@ |
| 466 | 486 | ** json_getenv_int(), with the addition that string values which |
| 467 | 487 | ** either start with a digit 1..9 or the letters [tT] are considered |
| 468 | 488 | ** to be true. If this function cannot find a matching key/value then |
| 469 | 489 | ** dflt is returned. e.g. if it finds the key but the value is-a |
| 470 | 490 | ** Object then dftl is returned. |
| 491 | +** |
| 492 | +** If an entry is found, this function guarantees that it will return |
| 493 | +** either 0 or 1, as opposed to "0 or non-zero", so that clients can |
| 494 | +** pass a different value as dflt. Thus they can use, e.g. -1 to know |
| 495 | +** whether or not this function found a match (it will return -1 in |
| 496 | +** that case). |
| 471 | 497 | */ |
| 472 | 498 | char json_getenv_bool(char const * pKey, char dflt ){ |
| 473 | 499 | cson_value const * v = json_getenv(pKey); |
| 474 | 500 | if(!v){ |
| 475 | 501 | return dflt; |
| | @@ -501,10 +527,82 @@ |
| 501 | 527 | ** internals via cgi_replace_parameter() and friends or json_setenv(). |
| 502 | 528 | */ |
| 503 | 529 | char const * json_getenv_cstr( char const * zKey ){ |
| 504 | 530 | return cson_value_get_cstr( json_getenv(zKey) ); |
| 505 | 531 | } |
| 532 | + |
| 533 | +/* |
| 534 | +** An extended form of find_option() which tries to look up a combo |
| 535 | +** GET/POST/CLI argument. |
| 536 | +** |
| 537 | +** zKey must be the GET/POST parameter key. zCLILong must be the "long |
| 538 | +** form" CLI flag (NULL means to use zKey). zCLIShort may be NUL or |
| 539 | +** the "short form" CLI flag. |
| 540 | +** |
| 541 | +** On error (no match found) NULL is returned. |
| 542 | +** |
| 543 | +** This ONLY works for String JSON/GET/CLI values, not JSON |
| 544 | +** booleans and whatnot. |
| 545 | +*/ |
| 546 | +char const * json_find_option_cstr(char const * zKey, |
| 547 | + char const * zCLILong, |
| 548 | + char const * zCLIShort){ |
| 549 | + char const * rc = NULL; |
| 550 | + assert(NULL != zKey); |
| 551 | + if(!g.isHTTP){ |
| 552 | + rc = find_option(zCLILong ? zCLILong : zKey, |
| 553 | + zCLIShort, 1); |
| 554 | + } |
| 555 | + if(!rc && fossil_is_json()){ |
| 556 | + rc = json_getenv_cstr(zKey); |
| 557 | + } |
| 558 | + return rc; |
| 559 | +} |
| 560 | + |
| 561 | +/* |
| 562 | +** The boolean equivalent of json_find_option_cstr(). |
| 563 | +** If the option is not found, dftl is returned. |
| 564 | +*/ |
| 565 | +char json_find_option_bool(char const * zKey, |
| 566 | + char const * zCLILong, |
| 567 | + char const * zCLIShort, |
| 568 | + char dflt ){ |
| 569 | + char rc = -1; |
| 570 | + if(!g.isHTTP){ |
| 571 | + if(NULL != find_option(zCLILong ? zCLILong : zKey, |
| 572 | + zCLIShort, 0)){ |
| 573 | + rc = 1; |
| 574 | + } |
| 575 | + } |
| 576 | + if((-1==rc) && fossil_is_json()){ |
| 577 | + rc = json_getenv_bool(zKey,-1); |
| 578 | + } |
| 579 | + return (-1==rc) ? dflt : rc; |
| 580 | +} |
| 581 | + |
| 582 | +/* |
| 583 | +** The integer equivalent of json_find_option_cstr(). |
| 584 | +** If the option is not found, dftl is returned. |
| 585 | +*/ |
| 586 | +int json_find_option_int(char const * zKey, |
| 587 | + char const * zCLILong, |
| 588 | + char const * zCLIShort, |
| 589 | + int dflt ){ |
| 590 | + enum { Magic = -947 }; |
| 591 | + int rc = Magic; |
| 592 | + if(!g.isHTTP){ |
| 593 | + char const * opt = find_option(zCLILong ? zCLILong : zKey, |
| 594 | + zCLIShort, 1); |
| 595 | + if(NULL!=opt){ |
| 596 | + rc = atoi(opt); |
| 597 | + } |
| 598 | + } |
| 599 | + if(Magic==rc){ |
| 600 | + rc = json_getenv_int(zKey,Magic); |
| 601 | + } |
| 602 | + return (Magic==rc) ? dflt : rc; |
| 603 | +} |
| 506 | 604 | |
| 507 | 605 | |
| 508 | 606 | /* |
| 509 | 607 | ** Adds v to g.json.param.o using the given key. May cause any prior |
| 510 | 608 | ** item with that key to be destroyed (depends on current reference |
| | @@ -1006,45 +1104,26 @@ |
| 1006 | 1104 | if(cmd){ |
| 1007 | 1105 | json_string_split(cmd, '/', 0, g.json.cmd.a); |
| 1008 | 1106 | g.json.cmd.commandStr = cmd; |
| 1009 | 1107 | } |
| 1010 | 1108 | } |
| 1011 | | - |
| 1012 | | - if(!g.json.jsonp && g.json.post.o){ |
| 1013 | | - g.json.jsonp = |
| 1014 | | - json_getenv_cstr("jsonp") |
| 1015 | | - /*cson_string_cstr(cson_value_get_string(cson_object_get(g.json.post.o,"jsonp")))*/ |
| 1016 | | - ; |
| 1017 | | - } |
| 1018 | | - if( !g.isHTTP ){ |
| 1019 | | - g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/; |
| 1020 | | - if(!g.json.jsonp){ |
| 1021 | | - g.json.jsonp = find_option("jsonp",NULL,1); |
| 1022 | | - } |
| 1109 | + |
| 1110 | + |
| 1111 | + if(!g.json.jsonp){ |
| 1112 | + g.json.jsonp = json_find_option_cstr("jsonp",NULL,NULL); |
| 1113 | + } |
| 1114 | + if(!g.isHTTP){ |
| 1115 | + g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/; |
| 1023 | 1116 | } |
| 1024 | 1117 | |
| 1025 | 1118 | {/* set up JSON output formatting options. */ |
| 1026 | | - unsigned char indent = g.isHTTP ? 0 : 1; |
| 1119 | + int indent = -1; |
| 1027 | 1120 | char const * indentStr = NULL; |
| 1028 | | - char checkAgain = 1; |
| 1029 | | - if( g.json.post.v ){ |
| 1030 | | - cson_value const * check = json_getenv("indent"); |
| 1031 | | - if(check){ |
| 1032 | | - checkAgain = 0; |
| 1033 | | - indent = (unsigned char)json_getenv_int("indent",(int)indent); |
| 1034 | | - } |
| 1035 | | - } |
| 1036 | | - if(!g.isHTTP && checkAgain){/*CLI mode*/ |
| 1037 | | - indentStr = find_option("indent","I",1); |
| 1038 | | - if(indentStr){ |
| 1039 | | - int const n = atoi(indentStr); |
| 1040 | | - indent = (n>0) |
| 1041 | | - ? (unsigned char)n |
| 1042 | | - : 0; |
| 1043 | | - } |
| 1044 | | - } |
| 1045 | | - g.json.outOpt.indentation = indent; |
| 1121 | + indent = json_find_option_int("indent",NULL,"I",-1); |
| 1122 | + g.json.outOpt.indentation = (0>indent) |
| 1123 | + ? (g.isHTTP ? 0 : 1) |
| 1124 | + : (unsigned char)indent; |
| 1046 | 1125 | g.json.outOpt.addNewline = g.isHTTP |
| 1047 | 1126 | ? 0 |
| 1048 | 1127 | : (g.json.jsonp ? 0 : 1); |
| 1049 | 1128 | } |
| 1050 | 1129 | |
| | @@ -1565,15 +1644,11 @@ |
| 1565 | 1644 | if( !g.perm.Read ){ |
| 1566 | 1645 | json_set_err(FSL_JSON_E_DENIED, |
| 1567 | 1646 | "Requires 'o' permissions."); |
| 1568 | 1647 | return NULL; |
| 1569 | 1648 | } |
| 1570 | | - if( g.isHTTP ){ |
| 1571 | | - full = json_getenv_bool("full",0); |
| 1572 | | - }else{ |
| 1573 | | - full = (0!=find_option("full","f",0)); |
| 1574 | | - } |
| 1649 | + full = json_find_option_bool("full",NULL,"f",0); |
| 1575 | 1650 | #define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf))); |
| 1576 | 1651 | |
| 1577 | 1652 | jv = cson_value_new_object(); |
| 1578 | 1653 | jo = cson_value_get_object(jv); |
| 1579 | 1654 | |
| 1580 | 1655 | |