Fossil

Check-in [8a4304eae2]
Login

Check-in [8a4304eae2]

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

Overview
Comment:Initial work on a pikchr CLI command which integrates TH1 for programmatic pikchr generation. DO NOT MERGE: the required changes to TH1 need more testing to ensure they do not introduce fallout in the skin output. Also, output redirection is still very imcomplete and TH1 error reporting does not yet do the right thing.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | pikchr-th
Files: files | file ages | folders
SHA3-256: 8a4304eae23e796fa88fe60269a3a8157dafbbc66ce62f380826cfcd829c7748
User & Date: stephan 2020-09-13 16:35:10.218
Context
2020-09-13
18:26
Found a workaround for the th1 puts escaping, but am still wondering whether it's a viable long-term solution. ... (check-in: 18abb60d42 user: stephan tags: pikchr-th)
16:35
Initial work on a pikchr CLI command which integrates TH1 for programmatic pikchr generation. DO NOT MERGE: the required changes to TH1 need more testing to ensure they do not introduce fallout in the skin output. Also, output redirection is still very imcomplete and TH1 error reporting does not yet do the right thing. ... (check-in: 8a4304eae2 user: stephan tags: pikchr-th)
11:31
Update pikchr.c to a version that avoids using the " " entity. ... (check-in: 931f782ff3 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pikchrshow.c.
163
164
165
166
167
168
169




























































































    builtin_emit_fossil_js_apis("dom", "fetch", "copybutton",
                                "popupwidget", 0);
  }
  builtin_emit_fossil_js_apis("page.pikchrshow", 0);
  builtin_fulfill_js_requests();
  style_footer();
}



































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    builtin_emit_fossil_js_apis("dom", "fetch", "copybutton",
                                "popupwidget", 0);
  }
  builtin_emit_fossil_js_apis("page.pikchrshow", 0);
  builtin_fulfill_js_requests();
  style_footer();
}

static void pikchr_th_init(u32 fThInit){
  Th_FossilInit(fThInit);
}

/*
** COMMAND: pikchr
**
** Usage: %fossil pikchr [options] ?INFILE? ?OUTFILE?
**
** Options:
**
**    -div      On success, adds a DIV wrapper around the
**              resulting SVG output which limits its max-width.
**
**    -th       Process the input using TH1 before passing it to pikchr.
**
**    -th-novar Disable $var and $<var> TH1 processing. Only applies
**              with the -th flag.
**
**    -th-trace Trace TH1 execution (for debugging purposes)
**
** TH1 Caveats: the built-in TH1 commands make some assumptions about
** HTML escaping and output which do not apply via this
** command. e.g. some commands will output directly to stdout, rather
** than the output buffer this command requires. Improvements in that
** regard are under consideration/construction.
*/
void pikchr_cmd(void){
  Blob bIn = empty_blob;
  Blob bOut = empty_blob;
  const char * zInfile = "-";
  const char * zOutfile = "-";
  const int fWithDiv = find_option("div",0,0)!=0;
  const int fTh1 = find_option("th",0,0)!=0;
  const int fNoVar = find_option("th-novar",0,0)!=0;
  int isErr = 0;
  u32 fThInit = TH_INIT_DEFAULT;

  Th_InitTraceLog()/*processes -th-trace flag*/;
  verify_all_options();
  if(g.argc>4){
    usage("?INFILE? ?OUTFILE?");
  }
  if(g.argc>2){
    zInfile = g.argv[2];
  }
  if(g.argc>3){
    zOutfile = g.argv[3];
  }
  blob_read_from_file(&bIn, zInfile, ExtFILE);
  if(fTh1){
    Blob out = empty_blob;
    Blob * oldOut;
    db_find_and_open_repository(OPEN_ANY_SCHEMA | OPEN_OK_NOT_FOUND, 0)
      /* ^^^ needed for certain functions to work */;
    oldOut = Th_SetOutputBlob(&out);
    pikchr_th_init(fThInit);
    isErr = Th_RenderToBlob(blob_str(&bIn), &out,
                            fNoVar ? TH_R2B_NO_VARS : 0);
    blob_reset(&bIn);
    bIn = out;
    Th_SetOutputBlob(oldOut);
    /*fossil_print("th'd:\n%b\n", &bIn);*/
  }
  if(!isErr){
    int w = 0, h = 0;
    const char * zContent = blob_str(&bIn);
    char *zOut = pikchr(zContent, "pikchr", 0, &w, &h);
    if( w>0 && h>0 ){
      if(fWithDiv){
        blob_appendf(&bOut,"<div style='max-width:%dpx;'>\n", w);
      }
      blob_append(&bOut, zOut, -1);
      if(fWithDiv){
        blob_append(&bOut,"</div>\n", 7);
      }
    }else{
      isErr = 1;
      blob_append(&bOut, zOut, -1);
    }
    fossil_free(zOut);
  }
  if(isErr){
    fossil_fatal("ERROR: %b", &bOut);
  }else{
    blob_write_to_file(&bOut, zOutfile);
  }
  Th_PrintTraceLog();
  blob_reset(&bIn);
  blob_reset(&bOut);
}
Changes to src/th_main.c.
307
308
309
310
311
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
345
346
347
348
349
350
351
    default: {
      sqlite3_snprintf(sizeof(zRc), zRc, "TH1 return code %d", rc);
    }
  }
  return zRc;
}


/*











** Send text to the appropriate output:  Either to the console

** or to the CGI reply buffer.  Escape all characters with special
** meaning to HTML if the encode parameter is true.



*/
static void sendText(const char *z, int n, int encode){



  if( enableOutput && n ){
    if( n<0 ) n = strlen(z);
    if( encode ){
      z = htmlize(z, n);
      n = strlen(z);
    }


    if( g.cgiOutput ){
      cgi_append_content(z, n);
    }else{
      fwrite(z, 1, n, stdout);
      fflush(stdout);
    }
    if( encode ) free((char*)z);
  }
}




static void sendError(const char *z, int n, int forceCgi){
  int savedEnable = enableOutput;
  enableOutput = 1;
  if( forceCgi || g.cgiOutput ){
    sendText("<hr /><p class=\"thmainError\">", -1, 0);
  }
  sendText("ERROR: ", -1, 0);
  sendText((char*)z, n, 1);
  sendText(forceCgi || g.cgiOutput ? "</p>" : "\n", -1, 0);
  enableOutput = savedEnable;
}

/*
** Convert name to an rid.  This function was copied from name_to_typed_rid()
** in name.c; however, it has been modified to report TH1 script errors instead
** of "fatal errors".







>

>
>
>
>
>
>
>
>
>
>
>
|
>
|
|
>
>
>

|
>
>
>






>
>
|









>
>
>
|



|

|
|
|







307
308
309
310
311
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
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
    default: {
      sqlite3_snprintf(sizeof(zRc), zRc, "TH1 return code %d", rc);
    }
  }
  return zRc;
}

static Blob * pThOut = 0;
/*
** Sets the th1-internal output-redirection blob and returns the
** previous value. That blob is used by certain output-generation
** routines to emit its output.
*/
Blob * Th_SetOutputBlob(Blob * pOut){
  Blob * tmp = pThOut;
  pThOut = pOut;
  return tmp;
}

/*
** Send text to the appropriate output: If pOut is not NULL, it is
** appended there, else to the console or to the CGI reply buffer.
** Escape all characters with special meaning to HTML if the encode
** parameter is true.
**
** If pOut is NULL and the global pThOut is not then that blob
** is used for output.
*/
static void sendText(Blob * pOut, const char *z, int n, int encode){
  if(0==pOut && pThOut!=0){
    pOut = pThOut;
  }
  if( enableOutput && n ){
    if( n<0 ) n = strlen(z);
    if( encode ){
      z = htmlize(z, n);
      n = strlen(z);
    }
    if(pOut!=0){
      blob_append(pOut, z, n);
    }else if( g.cgiOutput ){
      cgi_append_content(z, n);
    }else{
      fwrite(z, 1, n, stdout);
      fflush(stdout);
    }
    if( encode ) free((char*)z);
  }
}

/*
** error-reporting counterpart of sendText().
*/
static void sendError(Blob * pOut, const char *z, int n, int forceCgi){
  int savedEnable = enableOutput;
  enableOutput = 1;
  if( forceCgi || g.cgiOutput ){
    sendText(pOut, "<hr /><p class=\"thmainError\">", -1, 0);
  }
  sendText(pOut,"ERROR: ", -1, 0);
  sendText(pOut,(char*)z, n, 1);
  sendText(pOut,forceCgi || g.cgiOutput ? "</p>" : "\n", -1, 0);
  enableOutput = savedEnable;
}

/*
** Convert name to an rid.  This function was copied from name_to_typed_rid()
** in name.c; however, it has been modified to report TH1 script errors instead
** of "fatal errors".
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
  int argc,
  const char **argv,
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "puts STRING");
  }
  sendText((char*)argv[1], argl[1], *(unsigned int*)pConvert);
  return TH_OK;
}

/*
** TH1 command: redirect URL ?withMethod?
**
** Issues an HTTP redirect to the specified URL and then exits the process.







|







472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  int argc,
  const char **argv,
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "puts STRING");
  }
  sendText(0,(char*)argv[1], argl[1], *(unsigned int*)pConvert);
  return TH_OK;
}

/*
** TH1 command: redirect URL ?withMethod?
**
** Issues an HTTP redirect to the specified URL and then exits the process.
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
    if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
    Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
    blob_init(&name, (char*)argv[1], argl[1]);
    zValue = Th_Fetch(blob_str(&name), &nValue);
    zH = htmlize(blob_buffer(&name), blob_size(&name));
    z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height);
    free(zH);
    sendText(z, -1, 0);
    free(z);
    blob_reset(&name);
    for(i=0; i<nElem; i++){
      zH = htmlize((char*)azElem[i], aszElem[i]);
      if( zValue && aszElem[i]==nValue
             && memcmp(zValue, azElem[i], nValue)==0 ){
        z = mprintf("<option value=\"%s\" selected=\"selected\">%s</option>",
                     zH, zH);
      }else{
        z = mprintf("<option value=\"%s\">%s</option>", zH, zH);
      }
      free(zH);
      sendText(z, -1, 0);
      free(z);
    }
    sendText("</select>", -1, 0);
    Th_Free(interp, azElem);
  }
  return TH_OK;
}

/*
** TH1 command: copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?







|












|


|







1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
    if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
    Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
    blob_init(&name, (char*)argv[1], argl[1]);
    zValue = Th_Fetch(blob_str(&name), &nValue);
    zH = htmlize(blob_buffer(&name), blob_size(&name));
    z = mprintf("<select id=\"%s\" name=\"%s\" size=\"%d\">", zH, zH, height);
    free(zH);
    sendText(0,z, -1, 0);
    free(z);
    blob_reset(&name);
    for(i=0; i<nElem; i++){
      zH = htmlize((char*)azElem[i], aszElem[i]);
      if( zValue && aszElem[i]==nValue
             && memcmp(zValue, azElem[i], nValue)==0 ){
        z = mprintf("<option value=\"%s\" selected=\"selected\">%s</option>",
                     zH, zH);
      }else{
        z = mprintf("<option value=\"%s\">%s</option>", zH, zH);
      }
      free(zH);
      sendText(0,z, -1, 0);
      free(z);
    }
    sendText(0,"</select>", -1, 0);
    Th_Free(interp, azElem);
  }
  return TH_OK;
}

/*
** TH1 command: copybtn TARGETID FLIPPED TEXT ?COPYLENGTH?
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
    if( Th_ToInt(interp, argv[2], argl[2], &flipped) ) return TH_ERROR;
    if( argc==5 ){
      if( Th_ToInt(interp, argv[4], argl[4], &copylength) ) return TH_ERROR;
    }
    zResult = style_copy_button(
                /*bOutputCGI==*/0, /*TARGETID==*/(char*)argv[1],
                flipped, copylength, "%h", /*TEXT==*/(char*)argv[3]);
    sendText(zResult, -1, 0);
    free(zResult);
  }
  return TH_OK;
}

/*
** TH1 command: linecount STRING MAX MIN







|







1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
    if( Th_ToInt(interp, argv[2], argl[2], &flipped) ) return TH_ERROR;
    if( argc==5 ){
      if( Th_ToInt(interp, argv[4], argl[4], &copylength) ) return TH_ERROR;
    }
    zResult = style_copy_button(
                /*bOutputCGI==*/0, /*TARGETID==*/(char*)argv[1],
                flipped, copylength, "%h", /*TEXT==*/(char*)argv[3]);
    sendText(0,zResult, -1, 0);
    free(zResult);
  }
  return TH_OK;
}

/*
** TH1 command: linecount STRING MAX MIN
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
      g.th1Setup = db_get("th1-setup", 0); /* Grab TH1 setup script. */
    }
    if( g.th1Setup ){
      rc = Th_Eval(g.interp, 0, g.th1Setup, -1);
      if( rc==TH_ERROR ){
        int nResult = 0;
        char *zResult = (char*)Th_GetResult(g.interp, &nResult);
        sendError(zResult, nResult, 0);
      }
    }
    if( g.thTrace ){
      Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup,
               Th_ReturnCodeName(rc, 0));
    }
  }







|







2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
      g.th1Setup = db_get("th1-setup", 0); /* Grab TH1 setup script. */
    }
    if( g.th1Setup ){
      rc = Th_Eval(g.interp, 0, g.th1Setup, -1);
      if( rc==TH_ERROR ){
        int nResult = 0;
        char *zResult = (char*)Th_GetResult(g.interp, &nResult);
        sendError(0,zResult, nResult, 0);
      }
    }
    if( g.thTrace ){
      Th_Trace("th1-setup {%h} => %h<br />\n", g.th1Setup,
               Th_ReturnCodeName(rc, 0));
    }
  }
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
    int nResult = 0;
    char *zResult = (char*)Th_GetResult(g.interp, &nResult);
    /*
    ** Make sure that the TH1 script error was not caused by a "missing"
    ** command hook handler as that is not actually an error condition.
    */
    if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){
      sendError(zResult, nResult, 0);
    }else{
      /*
      ** There is no command hook handler "installed".  This situation
      ** is NOT actually an error.
      */
      rc = TH_OK;
    }







|







2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
    int nResult = 0;
    char *zResult = (char*)Th_GetResult(g.interp, &nResult);
    /*
    ** Make sure that the TH1 script error was not caused by a "missing"
    ** command hook handler as that is not actually an error condition.
    */
    if( memcmp(zResult, NO_COMMAND_HOOK_ERROR, nResult)!=0 ){
      sendError(0,zResult, nResult, 0);
    }else{
      /*
      ** There is no command hook handler "installed".  This situation
      ** is NOT actually an error.
      */
      rc = TH_OK;
    }
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
    int nResult = 0;
    char *zResult = (char*)Th_GetResult(g.interp, &nResult);
    /*
    ** Make sure that the TH1 script error was not caused by a "missing"
    ** webpage hook handler as that is not actually an error condition.
    */
    if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){
      sendError(zResult, nResult, 1);
    }else{
      /*
      ** There is no webpage hook handler "installed".  This situation
      ** is NOT actually an error.
      */
      rc = TH_OK;
    }







|







2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
    int nResult = 0;
    char *zResult = (char*)Th_GetResult(g.interp, &nResult);
    /*
    ** Make sure that the TH1 script error was not caused by a "missing"
    ** webpage hook handler as that is not actually an error condition.
    */
    if( memcmp(zResult, NO_WEBPAGE_HOOK_ERROR, nResult)!=0 ){
      sendError(0,zResult, nResult, 1);
    }else{
      /*
      ** There is no webpage hook handler "installed".  This situation
      ** is NOT actually an error.
      */
      rc = TH_OK;
    }
2608
2609
2610
2611
2612
2613
2614

2615
2616
2617
2618
2619
2620
2621


2622
2623





2624
2625
2626
2627
2628
2629




2630
2631

2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
    return 1;
  }
  return db_get_boolean("th1-docs", 0);
}
#endif



/*
** The z[] input contains text mixed with TH1 scripts.
** The TH1 scripts are contained within <th1>...</th1>.
** TH1 variables are $aaa or $<aaa>.  The first form of
** variable is literal.  The second is run through htmlize
** before being inserted.
**


** This routine processes the template and writes the results
** on either stdout or into CGI.





*/
int Th_Render(const char *z){
  int i = 0;
  int n;
  int rc = TH_OK;
  char *zResult;




  Th_FossilInit(TH_INIT_DEFAULT);
  while( z[i] ){

    if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
      const char *zVar;
      int nVar;
      int encode = 1;
      sendText(z, i, 0);
      if( z[i+1]=='<' ){
        /* Variables of the form $<aaa> are html escaped */
        zVar = &z[i+2];
        nVar = n-2;
      }else{
        /* Variables of the form $aaa are output raw */
        zVar = &z[i+1];
        nVar = n;
        encode = 0;
      }
      rc = Th_GetVar(g.interp, (char*)zVar, nVar);
      z += i+1+n;
      i = 0;
      zResult = (char*)Th_GetResult(g.interp, &n);
      sendText((char*)zResult, n, encode);
    }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(z, i, 0);
      z += i+5;
      for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
      if( g.thTrace ){
        Th_Trace("render_eval {<pre>%#h</pre>}<br />\n", i, z);
      }
      rc = Th_Eval(g.interp, 0, (const char*)z, i);
      if( g.thTrace ){







>

|
<
<
<
|
|
>
>
|
|
>
>
>
>
>

|




>
>
>
>
|

>
|



|














|

|







2632
2633
2634
2635
2636
2637
2638
2639
2640
2641



2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
    return 1;
  }
  return db_get_boolean("th1-docs", 0);
}
#endif


#if INTERFACE
/*
** Flags for use with Th_RenderToBlob. These must not overlap with



** TH_INIT_MASK.
*/
#define TH_R2B_MASK    ((u32)0xff0000)
#define TH_R2B_NO_VARS ((u32)0x010000) /* Disables eval of $vars and $<vars> */
#endif

/*
** If pOut is NULL, this works identically to Th_Render(), else it
** works just like that function but appends any TH1-generated output
** to the given blob. A bitmask of TH_R2B_xxx and/or TH_INIT_xxx flags
** may be passed as the 3rd argument, or 0 for default options.
*/
int Th_RenderToBlob(const char *z, Blob * pOut, u32 mFlags){
  int i = 0;
  int n;
  int rc = TH_OK;
  char *zResult;
  Blob * const origOut = pThOut;

  assert(0==(TH_R2B_MASK & TH_INIT_MASK) && "init/r2b mask conflict");
  pThOut = pOut;
  Th_FossilInit(mFlags & TH_INIT_MASK);
  while( z[i] ){
    if( !(TH_R2B_NO_VARS & mFlags)
        && z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
      const char *zVar;
      int nVar;
      int encode = 1;
      sendText(pOut,z, i, 0);
      if( z[i+1]=='<' ){
        /* Variables of the form $<aaa> are html escaped */
        zVar = &z[i+2];
        nVar = n-2;
      }else{
        /* Variables of the form $aaa are output raw */
        zVar = &z[i+1];
        nVar = n;
        encode = 0;
      }
      rc = Th_GetVar(g.interp, (char*)zVar, nVar);
      z += i+1+n;
      i = 0;
      zResult = (char*)Th_GetResult(g.interp, &n);
      sendText(pOut,(char*)zResult, n, encode);
    }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(pOut,z, i, 0);
      z += i+5;
      for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
      if( g.thTrace ){
        Th_Trace("render_eval {<pre>%#h</pre>}<br />\n", i, z);
      }
      rc = Th_Eval(g.interp, 0, (const char*)z, i);
      if( g.thTrace ){
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679

2680
2681
















2682
2683
2684
2685
2686
2687
2688
      i = 0;
    }else{
      i++;
    }
  }
  if( rc==TH_ERROR ){
    zResult = (char*)Th_GetResult(g.interp, &n);
    sendError(zResult, n, 1);
  }else{
    sendText(z, i, 0);
  }

  return rc;
}

















/*
** COMMAND: test-th-render
**
** Usage: %fossil test-th-render FILE
**
** Read the content of the file named "FILE" as if it were a header or







|

|

>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
      i = 0;
    }else{
      i++;
    }
  }
  if( rc==TH_ERROR ){
    zResult = (char*)Th_GetResult(g.interp, &n);
    sendError(pOut,zResult, n, 1);
  }else{
    sendText(pOut,z, i, 0);
  }
  pThOut = origOut;
  return rc;
}

/*
** The z[] input contains text mixed with TH1 scripts.
** The TH1 scripts are contained within <th1>...</th1>.
** TH1 variables are $aaa or $<aaa>.  The first form of
** variable is literal.  The second is run through htmlize
** before being inserted.
**
** This routine processes the template and writes the results on
** either stdout, into CGI, or to an internal blob which was set up
** via a recursive call to this routine.
*/
int Th_Render(const char *z){
  return Th_RenderToBlob(z, pThOut, 0);
}


/*
** COMMAND: test-th-render
**
** Usage: %fossil test-th-render FILE
**
** Read the content of the file named "FILE" as if it were a header or
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
    rc = Th_WebpageNotify(g.argv[3], (unsigned int)atoi(g.argv[4]));
  }else{
    fossil_fatal("Unknown TH1 hook %s", g.argv[2]);
  }
  if( g.interp ){
    zResult = (char*)Th_GetResult(g.interp, &nResult);
  }
  sendText("RESULT (", -1, 0);
  sendText(Th_ReturnCodeName(rc, 0), -1, 0);
  sendText(")", -1, 0);
  if( zResult && nResult>0 ){
    sendText(": ", -1, 0);
    sendText(zResult, nResult, 0);
  }
  sendText("\n", -1, 0);
  Th_PrintTraceLog();
  if( forceCgi ) cgi_reply();
}
#endif







|
|
|

|
|

|




2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
    rc = Th_WebpageNotify(g.argv[3], (unsigned int)atoi(g.argv[4]));
  }else{
    fossil_fatal("Unknown TH1 hook %s", g.argv[2]);
  }
  if( g.interp ){
    zResult = (char*)Th_GetResult(g.interp, &nResult);
  }
  sendText(0,"RESULT (", -1, 0);
  sendText(0,Th_ReturnCodeName(rc, 0), -1, 0);
  sendText(0,")", -1, 0);
  if( zResult && nResult>0 ){
    sendText(0,": ", -1, 0);
    sendText(0,zResult, nResult, 0);
  }
  sendText(0,"\n", -1, 0);
  Th_PrintTraceLog();
  if( forceCgi ) cgi_reply();
}
#endif