Fossil

Check-in [3ab06e89]
Login

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

Overview
Comment:Added flags arg to Th_Render to allow us to eventually customize its output a bit.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | th1-query-api
Files: files | file ages | folders
SHA1:3ab06e8962024e0457ceb9f3c1ca73a9c493313e
User & Date: stephan 2012-07-15 00:39:29
Context
2012-07-15
00:57
Fixed a missing NUL terminator. check-in: 66da00e9 user: stephan tags: th1-query-api
00:39
Added flags arg to Th_Render to allow us to eventually customize its output a bit. check-in: 3ab06e89 user: stephan tags: th1-query-api
2012-07-14
22:38
Added strftime support to the th1 query API. check-in: 6e2f9edc user: stephan tags: th1-query-api
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/report.c.

17
18
19
20
21
22
23

24
25
26
27
28
29
30
..
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
**  
** Code to generate the ticket listings
*/
#include "config.h"
#include <time.h>
#include "report.h"
#include <assert.h>


/* Forward references to static routines */
static void report_format_hints(void);

/*
** WEBPAGE: /reportlist
*/
................................................................................
                         href("%R/rptsql?rn=%d", rn));
    }
    blob_appendf(&ril, "</li>\n");
  }

  Th_Store("report_items", blob_str(&ril));
  
  Th_Render(zScript);
  
  blob_reset(&ril);
  if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1);

  style_footer();
}








>







 







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
**  
** Code to generate the ticket listings
*/
#include "config.h"
#include <time.h>
#include "report.h"
#include <assert.h>
#include "th.h"

/* Forward references to static routines */
static void report_format_hints(void);

/*
** WEBPAGE: /reportlist
*/
................................................................................
                         href("%R/rptsql?rn=%d", rn));
    }
    blob_appendf(&ril, "</li>\n");
  }

  Th_Store("report_items", blob_str(&ril));
  
  Th_Render(zScript, Th_Render_Flags_DEFAULT);
  
  blob_reset(&ril);
  if( g.thTrace ) Th_Trace("END_REPORTLIST<br />\n", -1);

  style_footer();
}

Changes to src/style.c.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
...
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
*******************************************************************************
**
** This file contains code to implement the basic web page look and feel.
**
*/
#include "config.h"
#include "style.h"


/*
** Elements of the submenu are collected into the following
** structure and displayed below the main menu by style_header().
**
** Populate this structure with calls to style_submenu_element()
** prior to calling style_header().
................................................................................
  Th_Store("manifest_version", MANIFEST_VERSION);
  Th_Store("manifest_date", MANIFEST_DATE);
  Th_Store("compiler_name", COMPILER_NAME);
  if( g.zLogin ){
    Th_Store("login", g.zLogin);
  }
  if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1);
  Th_Render(zHeader);
  if( g.thTrace ) Th_Trace("END_HEADER<br />\n", -1);
  Th_Unstore("title");   /* Avoid collisions with ticket field names */
  cgi_destination(CGI_BODY);
  g.cgiOutput = 1;
  headerHasBeenGenerated = 1;
  sideboxUsed = 0;
}
................................................................................

  /* Set the href= field on hyperlinks.  Do this before the footer since
  ** the footer will be generating </html> */
  style_resolve_href();

  zFooter = db_get("footer", (char*)zDefaultFooter);
  if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
  Th_Render(zFooter);
  if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
  
  /* Render trace log if TH1 tracing is enabled. */
  if( g.thTrace ){
    cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
    cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
    cgi_append_content("</span>\n", -1);
................................................................................
  }

  /* Process through TH1 in order to give an opportunity to substitute
  ** variables such as $baseurl.
  */
  Th_Store("baseurl", g.zBaseURL);
  Th_Store("home", g.zTop);
  Th_Render(blob_str(&css));

  /* Tell CGI that the content returned by this page is considered cacheable */
  g.isConst = 1;
}

/*
** WEBPAGE: test_env







|







 







|







 







|







 







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
...
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
*******************************************************************************
**
** This file contains code to implement the basic web page look and feel.
**
*/
#include "config.h"
#include "style.h"
#include "th.h"

/*
** Elements of the submenu are collected into the following
** structure and displayed below the main menu by style_header().
**
** Populate this structure with calls to style_submenu_element()
** prior to calling style_header().
................................................................................
  Th_Store("manifest_version", MANIFEST_VERSION);
  Th_Store("manifest_date", MANIFEST_DATE);
  Th_Store("compiler_name", COMPILER_NAME);
  if( g.zLogin ){
    Th_Store("login", g.zLogin);
  }
  if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1);
  Th_Render(zHeader, Th_Render_Flags_DEFAULT);
  if( g.thTrace ) Th_Trace("END_HEADER<br />\n", -1);
  Th_Unstore("title");   /* Avoid collisions with ticket field names */
  cgi_destination(CGI_BODY);
  g.cgiOutput = 1;
  headerHasBeenGenerated = 1;
  sideboxUsed = 0;
}
................................................................................

  /* Set the href= field on hyperlinks.  Do this before the footer since
  ** the footer will be generating </html> */
  style_resolve_href();

  zFooter = db_get("footer", (char*)zDefaultFooter);
  if( g.thTrace ) Th_Trace("BEGIN_FOOTER<br />\n", -1);
  Th_Render(zFooter, Th_Render_Flags_DEFAULT);
  if( g.thTrace ) Th_Trace("END_FOOTER<br />\n", -1);
  
  /* Render trace log if TH1 tracing is enabled. */
  if( g.thTrace ){
    cgi_append_content("<span class=\"thTrace\"><hr />\n", -1);
    cgi_append_content(blob_str(&g.thLog), blob_size(&g.thLog));
    cgi_append_content("</span>\n", -1);
................................................................................
  }

  /* Process through TH1 in order to give an opportunity to substitute
  ** variables such as $baseurl.
  */
  Th_Store("baseurl", g.zBaseURL);
  Th_Store("home", g.zTop);
  Th_Render(blob_str(&css), Th_Render_Flags_DEFAULT);

  /* Tell CGI that the content returned by this page is considered cacheable */
  g.isConst = 1;
}

/*
** WEBPAGE: test_env

Changes to src/th.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786

2787
2788
2789
2790
2791
2792
2793
....
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
....
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
*/

#include "th.h"
#include <string.h>
#include <assert.h>
#include <stdio.h> /* FILE class */
#ifdef TH_USE_OUTBUF
#ifndef INTERFACE
#include "blob.h"
#endif
#endif

extern void *fossil_realloc(void *p, size_t n);
static void * th_fossil_realloc(void *p, unsigned int n){
  return fossil_realloc( p, n );
}

................................................................................

#ifdef TH_USE_OUTBUF
/* Reminder: the ob code "really" belongs in th_lang.c,
   but we need access to Th_Interp internals in order to
   swap out Th_Vtab parts for purposes of stacking layers
   of buffers.
*/
/*
** Manager of a stack of Blob objects for output buffering.
*/
struct Th_Ob_Man {
  Blob ** aBuf;        /* Stack of Blobs */
  int nBuf;            /* Number of blobs */
  int cursor;          /* Current level (-1=not active) */
  Th_Interp * interp;  /* The associated interpreter */
  Th_Vtab ** aVtab;    /* Stack of Vtabs (they get restored
                          when a buffering level is popped).
                          Has nBuf entries.

                          FIXME? Only swap out the "out" members?
                       */
};

typedef struct Th_Ob_Man Th_Ob_Man;
#define Th_Ob_Man_empty_m { NULL, 0, -1, NULL, NULL }
static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
static Th_Ob_Man Th_Ob_Man_instance = Th_Ob_Man_empty_m;

/*
** Returns the top-most Blob in pMan's stack, or NULL
** if buffering is not active.
*/
static Blob * Th_ob_current( Th_Ob_Man * pMan ){

  return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
}


/*
** Th_output_f() impl which expects pState to be (Th_Ob_Man*).
** (zData,len) are appended to pState's current output buffer.
................................................................................
  {
    Th_output_f_ob,
    NULL,
    1
  }
};

/*
** Pushes a new blob onto pMan's stack. On success
** returns TH_OK and assigns *pOut (if pOut is not NULL)
** to the new blob (which is owned by pMan). On error
** pOut is not modified and non-0 is returned.
*/
int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut ){
  Blob * pBlob;
  int x, i;
  assert( NULL != pMan->interp );
  pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob));
  *pBlob = empty_blob;

................................................................................
  error:
  if( pBlob ){
    Th_Free( pMan->interp, pBlob );
  }
  return TH_ERROR;
}

/*
** Pops the top-most output buffer off the stack and returns
** it. Returns NULL if there is no current buffer.  When the last
** buffer is popped, pMan's internals are cleaned up.
**
** The caller owns the returned object and must eventually call
** blob_reset() on it.
*/
Blob * Th_ob_pop( Th_Ob_Man * pMan ){
  if( pMan->cursor < 0 ){
    return NULL;
  }else{
    Blob * rc;
    assert( pMan->nBuf > pMan->cursor );
    rc = pMan->aBuf[pMan->cursor];







<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




|
|
|
|
|
>







 







<
<
<
<
<
<







 







<
<
<
<
<
<
<
<







5
6
7
8
9
10
11



12
13
14
15
16
17
18
....
2751
2752
2753
2754
2755
2756
2757

















2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
....
2789
2790
2791
2792
2793
2794
2795






2796
2797
2798
2799
2800
2801
2802
....
2835
2836
2837
2838
2839
2840
2841








2842
2843
2844
2845
2846
2847
2848
*/

#include "th.h"
#include <string.h>
#include <assert.h>
#include <stdio.h> /* FILE class */
#ifdef TH_USE_OUTBUF



#endif

extern void *fossil_realloc(void *p, size_t n);
static void * th_fossil_realloc(void *p, unsigned int n){
  return fossil_realloc( p, n );
}

................................................................................

#ifdef TH_USE_OUTBUF
/* Reminder: the ob code "really" belongs in th_lang.c,
   but we need access to Th_Interp internals in order to
   swap out Th_Vtab parts for purposes of stacking layers
   of buffers.
*/

















#define Th_Ob_Man_empty_m { NULL, 0, -1, NULL, NULL }
static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
static Th_Ob_Man Th_Ob_Man_instance = Th_Ob_Man_empty_m;

Th_Ob_Man * Th_ob_manager(Th_Interp *ignored){
  return &Th_Ob_Man_instance;
}
  

Blob * Th_ob_current( Th_Ob_Man * pMan ){
  return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
}


/*
** Th_output_f() impl which expects pState to be (Th_Ob_Man*).
** (zData,len) are appended to pState's current output buffer.
................................................................................
  {
    Th_output_f_ob,
    NULL,
    1
  }
};







int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut ){
  Blob * pBlob;
  int x, i;
  assert( NULL != pMan->interp );
  pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob));
  *pBlob = empty_blob;

................................................................................
  error:
  if( pBlob ){
    Th_Free( pMan->interp, pBlob );
  }
  return TH_ERROR;
}









Blob * Th_ob_pop( Th_Ob_Man * pMan ){
  if( pMan->cursor < 0 ){
    return NULL;
  }else{
    Blob * rc;
    assert( pMan->nBuf > pMan->cursor );
    rc = pMan->aBuf[pMan->cursor];

Changes to src/th.h.

8
9
10
11
12
13
14



15
16
17
18
19
20
21
...
258
259
260
261
262
263
264







265
266
267
268
269
270
271
...
297
298
299
300
301
302
303





















































/*
** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
** They are functionally similar to PHP's ob_start(), ob_end(), etc.
** family of functions, providing output capturing/buffering.
*/
#define TH_USE_OUTBUF
/*#undef TH_USE_OUTBUF*/





/* This header file defines the external interface to the custom Scripting
** Language (TH) interpreter.  TH is very similar to TCL but is not an
** exact clone.
*/

................................................................................
*/
struct Th_Command_Reg {
  const char *zName;     /* Function name. */
  Th_CommandProc xProc;  /* Callback function */
  void *pContext;        /* Arbitrary data for the callback. */
};








/*
** Registers a list of commands with the interpreter. pList must be a non-NULL
** pointer to an array of Th_Command_Reg objects, the last one of which MUST
** have a NULL zName field (that is the end-of-list marker).
** Returns TH_OK on success, "something else" on error.
*/
int Th_register_commands( Th_Interp * interp, Th_Command_Reg const * pList );
................................................................................
** Fetches the statement with the given ID, as returned by
** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer
** refers) to a statement added via Th_AddStmt().
*/
sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId);
#endif





























































>
>
>







 







>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
...
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
/*
** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
** They are functionally similar to PHP's ob_start(), ob_end(), etc.
** family of functions, providing output capturing/buffering.
*/
#define TH_USE_OUTBUF
/*#undef TH_USE_OUTBUF*/
#ifndef INTERFACE
#include "blob.h"
#endif


/* This header file defines the external interface to the custom Scripting
** Language (TH) interpreter.  TH is very similar to TCL but is not an
** exact clone.
*/

................................................................................
*/
struct Th_Command_Reg {
  const char *zName;     /* Function name. */
  Th_CommandProc xProc;  /* Callback function */
  void *pContext;        /* Arbitrary data for the callback. */
};

/* mkindex cannot do enums enum Th_Render_Flags { */
#define Th_Render_Flags_DEFAULT 0
#define Th_Render_Flags_NO_DOLLAR_DEREF (1 << 1)
/*};*/

int Th_Render(const char *z, int flags);

/*
** Registers a list of commands with the interpreter. pList must be a non-NULL
** pointer to an array of Th_Command_Reg objects, the last one of which MUST
** have a NULL zName field (that is the end-of-list marker).
** Returns TH_OK on success, "something else" on error.
*/
int Th_register_commands( Th_Interp * interp, Th_Command_Reg const * pList );
................................................................................
** Fetches the statement with the given ID, as returned by
** Th_AddStmt(). Returns NULL if stmtId does not refer (or no longer
** refers) to a statement added via Th_AddStmt().
*/
sqlite3_stmt * Th_GetStmt(Th_Interp *interp, int stmtId);
#endif

#ifdef TH_USE_OUTBUF
/*
** Manager of a stack of Blob objects for output buffering.
*/
struct Th_Ob_Man {
  Blob ** aBuf;        /* Stack of Blobs */
  int nBuf;            /* Number of blobs */
  int cursor;          /* Current level (-1=not active) */
  Th_Interp * interp;  /* The associated interpreter */
  Th_Vtab ** aVtab;    /* Stack of Vtabs (they get restored
                          when a buffering level is popped).
                          Has nBuf entries.

                          FIXME? Only swap out the "out" members, and
                          not xRealloc (that could get us into
                          trouble, but we currently only use one
                          realloc impl).
                       */
};

typedef struct Th_Ob_Man Th_Ob_Man;

/*
** Returns the ob manager for the given interpreter.
*/
Th_Ob_Man * Th_ob_manager(Th_Interp *ignored);

/*
** Returns the top-most Blob in pMan's stack, or NULL
** if buffering is not active.
*/
Blob * Th_ob_current( Th_Ob_Man * pMan );

/*
** Pushes a new blob onto pMan's stack. On success
** returns TH_OK and assigns *pOut (if pOut is not NULL)
** to the new blob (which is owned by pMan). On error
** pOut is not modified and non-0 is returned.
*/
int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut );

/*
** Pops the top-most output buffer off the stack and returns
** it. Returns NULL if there is no current buffer.  When the last
** buffer is popped, pMan's internals are cleaned up.
**
** The caller owns the returned object and must eventually call
** blob_reset() on it and Th_Free() it.
*/
Blob * Th_ob_pop( Th_Ob_Man * pMan );

#endif
/* TH_USE_OUTBUF */

Changes to src/th_lang.c.

1050
1051
1052
1053
1054
1055
1056
















1057
1058
1059
1060
1061
1062
1063
  int argc, 
  const char **argv, 
  int *argl
){
  int cnt = 0;
  cnt++;
  return TH_OK;
















}

/*
** Register the built-in th1 language commands with interpreter interp.
** Usually this is called soon after interpreter creation.
*/
int th_register_language(Th_Interp *interp){







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







1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  int argc, 
  const char **argv, 
  int *argl
){
  int cnt = 0;
  cnt++;
  return TH_OK;
}

static int call_command(
  Th_Interp *interp, 
  void *ctx, 
  int argc, 
  const char **argv, 
  int *argl
){
  if( argc<2 ){
    return Th_WrongNumArgs2(interp,
                            argv[0], argl[0],
                           "funcName ?args...?");
  }
  

}

/*
** Register the built-in th1 language commands with interpreter interp.
** Usually this is called soon after interpreter creation.
*/
int th_register_language(Th_Interp *interp){

Changes to src/th_main.c.

15
16
17
18
19
20
21

22
23

24
25
26
27
28
29
30
...
218
219
220
221
222
223
224





















































225
226
227
228
229
230
231
....
1569
1570
1571
1572
1573
1574
1575

1576
1577
1578
1579

1580
1581
1582
1583

1584

1585

1586
1587
1588
1589
1590
1591
1592
....
1703
1704
1705
1706
1707
1708
1709
1710


1711
1712
1713
1714
1715
1716

1717
1718
1719
1720
1721
1722

1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
....
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
....
1785
1786
1787
1788
1789
1790
1791
1792
1793
**
*******************************************************************************
**
** This file contains an interface between the TH scripting language
** (an independent project) and fossil.
*/
#include "config.h"

#include "th_main.h"


/*
** Global variable counting the number of outstanding calls to malloc()
** made by the th1 implementation. This is used to catch memory leaks
** in the interpreter. Obviously, it also means th1 is not threadsafe.
*/
static int nOutstandingMalloc = 0;

................................................................................
  }
  zOut = htmlize((char*)argv[1], argl[1]);
  Th_SetResult(interp, zOut, -1);
  free(zOut);
  return TH_OK;
}






















































/*
** TH command:      date
**
** Return a string which is the current time and date.  If the
** -local option is used, the date appears using localtime instead
** of UTC.
*/
................................................................................
*/
void Th_FossilInit(void){
  static PutsCmdData puts_Html = {0, 0, 0};
  static PutsCmdData puts_Normal = {1, 0, 0};
  static Th_Command_Reg aCommand[] = {
    {"anycap",        anycapCmd,            0},
    {"combobox",      comboboxCmd,          0},

    {"enable_output", enableOutputCmd,      0},
    {"linecount",     linecntCmd,           0},
    {"hascap",        hascapCmd,            0},
    {"hasfeature",    hasfeatureCmd,        0},

    {"htmlize",       htmlizeCmd,           0},
    {"date",          dateCmd,              0},
    {"html",          putsCmd,     &puts_Html},
    {"puts",          putsCmd,   &puts_Normal},

    {"wiki",          wikiCmd,              0},

    {"repository",    repositoryCmd,        0},


    {0, 0, 0}
  };
  if( g.interp==0 ){
    int i;
    if(g.cgiOutput){
      vtab.out.f = Th_output_f_cgi_content;
................................................................................
    i += 2;
  }
  return i;
}

/*
** 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();
  while( z[i] ){
    if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
      const char *zVar;
      int nVar;
      int encode = 1;
      sendText(g.interp, 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(g.interp, (char*)zResult, n, encode);
    }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(g.interp, z, i, 0);
      z += i+5;
      for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
      rc = Th_Eval(g.interp, 0, (const char*)z, i);
      if( rc!=TH_OK ) break;
      z += i;
................................................................................
  }
  blob_zero(&in);
  db_open_config(0); /* Needed for global "tcl" setting. */
#ifdef TH_USE_SQLITE
  db_find_and_open_repository(OPEN_ANY_SCHEMA,0) /* for query_xxx API. */;
#endif
  blob_read_from_file(&in, g.argv[2]);
  Th_Render(blob_str(&in));
}







>


>







 







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







 







>

<


>

<
|

>
|
>

>







 







|
>
>
|
|
|


<
>

|



|
>


|







 







|


|
|







 







|

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
....
1624
1625
1626
1627
1628
1629
1630
1631
1632

1633
1634
1635
1636

1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
....
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775

1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
....
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
....
1846
1847
1848
1849
1850
1851
1852
1853
1854
**
*******************************************************************************
**
** This file contains an interface between the TH scripting language
** (an independent project) and fossil.
*/
#include "config.h"

#include "th_main.h"

/*#include "th_main.h"*/
/*
** Global variable counting the number of outstanding calls to malloc()
** made by the th1 implementation. This is used to catch memory leaks
** in the interpreter. Obviously, it also means th1 is not threadsafe.
*/
static int nOutstandingMalloc = 0;

................................................................................
  }
  zOut = htmlize((char*)argv[1], argl[1]);
  Th_SetResult(interp, zOut, -1);
  free(zOut);
  return TH_OK;
}

#if 0
/* i'm not sure we need this */
/*
** TH command:      render STRING
**
** Render the input string as TH1.
*/
static int renderCmd(
  Th_Interp *interp, 
  void *p, 
  int argc, 
  const char **argv, 
  int *argl
){
  if( argc<2 ){
    return Th_WrongNumArgs2(interp,
                            argv[0], argl[0],
                            "STRING ?STRING...?");
  }else{
    Th_Ob_Man * man = Th_ob_manager(interp);
    Blob * b = NULL;
    Blob buf = empty_blob;
    int rc, i;
    /*FIXME: assert(NULL != man && man->interp==interp);*/
    man->interp = interp;
    /* Combine all inputs into one buffer so that we can use that to
       embed TH1 tags across argument boundaries.

       FIX:E optimize away buf for the 1-arg case.
     */
    for( i = 1; TH_OK==rc && i < argc; ++i ){
      char const * str = argv[i];
      blob_append( &buf, str, argl[i] );
      /*rc = Th_Render( str, Th_Render_Flags_NO_DOLLAR_DEREF );*/
    }
    rc = Th_ob_push( man, &b );
    if(rc){
      blob_reset( &buf );
      return rc;
    }
    rc = Th_Render( buf.aData, Th_Render_Flags_DEFAULT );
    blob_reset(&buf);
    b = Th_ob_pop( man );
    if(TH_OK==rc){
      Th_SetResult( interp, b->aData, b->nUsed );
    }
    blob_reset( b );
    Th_Free( interp, b );
    return rc;
  }
}/* renderCmd() */
#endif

/*
** TH command:      date
**
** Return a string which is the current time and date.  If the
** -local option is used, the date appears using localtime instead
** of UTC.
*/
................................................................................
*/
void Th_FossilInit(void){
  static PutsCmdData puts_Html = {0, 0, 0};
  static PutsCmdData puts_Normal = {1, 0, 0};
  static Th_Command_Reg aCommand[] = {
    {"anycap",        anycapCmd,            0},
    {"combobox",      comboboxCmd,          0},
    {"date",          dateCmd,              0},
    {"enable_output", enableOutputCmd,      0},

    {"hascap",        hascapCmd,            0},
    {"hasfeature",    hasfeatureCmd,        0},
    {"html",          putsCmd,     &puts_Html},
    {"htmlize",       htmlizeCmd,           0},

    {"linecount",     linecntCmd,           0},
    {"puts",          putsCmd,   &puts_Normal},
#if 0
    {"render",        renderCmd,            0},
#endif
    {"repository",    repositoryCmd,        0},
    {"wiki",          wikiCmd,              0},

    {0, 0, 0}
  };
  if( g.interp==0 ){
    int i;
    if(g.cgiOutput){
      vtab.out.f = Th_output_f_cgi_content;
................................................................................
    i += 2;
  }
  return i;
}

/*
** The z[] input contains text mixed with TH1 scripts.
** The TH1 scripts are contained within <th1>...</th1>.
**
** If flags does NOT contain the Th_Render_Flags_NO_DOLLAR_DEREF bit
** then 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

** via Th_output().
*/
int Th_Render(const char *z, int flags){
  int i = 0;
  int n;
  int rc = TH_OK;
  char const *zResult;
  char doDollar = !(flags & Th_Render_Flags_NO_DOLLAR_DEREF);
  Th_FossilInit();
  while( z[i] ){
    if( doDollar && z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
      const char *zVar;
      int nVar;
      int encode = 1;
      sendText(g.interp, 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, zVar, nVar);
      z += i+1+n;
      i = 0;
      zResult = Th_GetResult(g.interp, &n);
      sendText(g.interp, zResult, n, encode);
    }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
      sendText(g.interp, z, i, 0);
      z += i+5;
      for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
      rc = Th_Eval(g.interp, 0, (const char*)z, i);
      if( rc!=TH_OK ) break;
      z += i;
................................................................................
  }
  blob_zero(&in);
  db_open_config(0); /* Needed for global "tcl" setting. */
#ifdef TH_USE_SQLITE
  db_find_and_open_repository(OPEN_ANY_SCHEMA,0) /* for query_xxx API. */;
#endif
  blob_read_from_file(&in, g.argv[2]);
  Th_Render(blob_str(&in), Th_Render_Flags_DEFAULT);
}

Changes to src/tkt.c.

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  }
  style_header("View Ticket");
  if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
  ticket_init();
  initializeVariablesFromDb();
  zScript = ticket_viewpage_code();
  if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1);
  Th_Render(zScript);
  if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);

  zFullName = db_text(0, 
       "SELECT tkt_uuid FROM ticket"
       " WHERE tkt_uuid GLOB '%q*'", zUuid);
  if( zFullName ){
    int cnt = 0;
................................................................................
  @ </p>
  zScript = ticket_newpage_code();
  Th_Store("login", g.zLogin);
  Th_Store("date", db_text(0, "SELECT datetime('now')"));
  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
                   (void*)&zNewUuid, 0);
  if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
  if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
    cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
    return;
  }
  @ </form>
  if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
  style_footer();
}
................................................................................
  @ </p>
  zScript = ticket_editpage_code();
  Th_Store("login", g.zLogin);
  Th_Store("date", db_text(0, "SELECT datetime('now')"));
  Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
  if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
  if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
    cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
    return;
  }
  @ </form>
  if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
  style_footer();
}







|







 







|







 







|







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  }
  style_header("View Ticket");
  if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br />\n", -1);
  ticket_init();
  initializeVariablesFromDb();
  zScript = ticket_viewpage_code();
  if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br />\n", -1);
  Th_Render(zScript, Th_Render_Flags_DEFAULT );
  if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);

  zFullName = db_text(0, 
       "SELECT tkt_uuid FROM ticket"
       " WHERE tkt_uuid GLOB '%q*'", zUuid);
  if( zFullName ){
    int cnt = 0;
................................................................................
  @ </p>
  zScript = ticket_newpage_code();
  Th_Store("login", g.zLogin);
  Th_Store("date", db_text(0, "SELECT datetime('now')"));
  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
                   (void*)&zNewUuid, 0);
  if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
  if( Th_Render(zScript, Th_Render_Flags_DEFAULT)==TH_RETURN && !g.thTrace && zNewUuid ){
    cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
    return;
  }
  @ </form>
  if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
  style_footer();
}
................................................................................
  @ </p>
  zScript = ticket_editpage_code();
  Th_Store("login", g.zLogin);
  Th_Store("date", db_text(0, "SELECT datetime('now')"));
  Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
  if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
  if( Th_Render(zScript, Th_Render_Flags_DEFAULT)==TH_RETURN && !g.thTrace && zName ){
    cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
    return;
  }
  @ </form>
  if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
  style_footer();
}