Fossil

Check-in [3c0209f5]
Login

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

Overview
Comment:Refactored th1's output mechanism: moved output API to Th_Vtab to support arbitrary output destinations, the intention being to be able to support an output buffer stack analog to PHP's ob_start(), ob_get_clean() and friends.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | th1-query-api
Files: files | file ages | folders
SHA1:3c0209f5dcdc4e7505d1fb072bded0ca638ec187
User & Date: stephan 2012-07-14 11:54:45
Context
2012-07-14
12:02
Refactored sendText() to use the new output abstraction layer. check-in: d3a62349 user: stephan tags: th1-query-api
11:54
Refactored th1's output mechanism: moved output API to Th_Vtab to support arbitrary output destinations, the intention being to be able to support an output buffer stack analog to PHP's ob_start(), ob_get_clean() and friends. check-in: 3c0209f5 user: stephan tags: th1-query-api
11:15
Cleanups in the th1 query statement finalization. check-in: 4fdf0ac2 user: stephan tags: th1-query-api
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/th.c.

3
4
5
6
7
8
9

10
11
12
13
14
15
16
....
1386
1387
1388
1389
1390
1391
1392























1393
1394
1395
1396
1397
1398
1399
** The implementation of the TH core. This file contains the parser, and 
** the implementation of the interface in th.h.
*/

#include "th.h"
#include <string.h>
#include <assert.h>


typedef struct Th_Command   Th_Command;
typedef struct Th_Frame     Th_Frame;
typedef struct Th_Variable  Th_Variable;

/*
** Interpreter structure.
................................................................................
}
void Th_Free(Th_Interp *pInterp, void *z){
  if( z ){
    pInterp->pVtab->xFree(z);
  }
}
























/*
** Install a new th1 command. 
**
** If a command of the same name already exists, it is deleted automatically.
*/
int Th_CreateCommand(
  Th_Interp *interp, 







>







 







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







3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
....
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
** The implementation of the TH core. This file contains the parser, and 
** the implementation of the interface in th.h.
*/

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

typedef struct Th_Command   Th_Command;
typedef struct Th_Frame     Th_Frame;
typedef struct Th_Variable  Th_Variable;

/*
** Interpreter structure.
................................................................................
}
void Th_Free(Th_Interp *pInterp, void *z){
  if( z ){
    pInterp->pVtab->xFree(z);
  }
}


int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){
  if(!vTab->out.f){
    return -1;
  }else if(!vTab->out.enabled){
    return 0;
  }else{
    return vTab->out.f( zData, nData, vTab->out.pState );
  }
}


int Th_output( Th_Interp *pInterp, char const * zData, int nData ){
  return Th_Vtab_output( pInterp->pVtab, zData, nData );
}

int Th_output_f_FILE( char const * zData, int nData, void * pState ){
  FILE * dest = pState ? (FILE*)pState : stdout;
  int rc = (int)fwrite(zData, 1, nData, dest);
  fflush(dest);
  return rc;
}

/*
** Install a new th1 command. 
**
** If a command of the same name already exists, it is deleted automatically.
*/
int Th_CreateCommand(
  Th_Interp *interp, 

Changes to src/th.h.

10
11
12
13
14
15
16











17
18
19
20
21
22
23
24





25
26

27
28
29
30
31

32
33
34
35
36
37
38
...
187
188
189
190
191
192
193





















194
195
196
197
198
199
200
#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.
*/












/*
** Before creating an interpreter, the application must allocate and
** populate an instance of the following structure. It must remain valid
** for the lifetime of the interpreter.
*/
struct Th_Vtab {
  void *(*xMalloc)(unsigned int);
  void (*xFree)(void *);





};
typedef struct Th_Vtab Th_Vtab;


/*
** Opaque handle for interpeter.
*/
typedef struct Th_Interp Th_Interp;


/* 
** Create and delete interpreters. 
*/
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
void Th_DeleteInterp(Th_Interp *);

................................................................................
/*
** Useful functions from th_lang.c.
*/
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);

typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*);






















#ifdef TH_USE_SQLITE
#include "stddef.h" /* size_t */
extern void *fossil_realloc(void *p, size_t n);

/*
** Adds the given prepared statement to the interpreter. Returns the







>
>
>
>
>
>
>
>
>
>
>








>
>
>
>
>


>





>







 







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







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
...
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
#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.
*/

/*
** Th_output_f() specifies a generic output routine for use by Th_Vtab
** and friends. Its first argument is the data to write, the second is
** the number of bytes to write, and the 3rd is an
** implementation-specific state pointer (may be NULL, depending on
** the implementation). The return value is the number of bytes output
** (which may differ from len due to encoding and whatnot).  On error
** a negative value must be returned.
*/
typedef int (*Th_output_f)( char const * zData, int len, void * pState );

/*
** Before creating an interpreter, the application must allocate and
** populate an instance of the following structure. It must remain valid
** for the lifetime of the interpreter.
*/
struct Th_Vtab {
  void *(*xMalloc)(unsigned int);
  void (*xFree)(void *);
  struct {
    Th_output_f f;   /* output handler */
    void * pState;   /* final argument for xOut() */
    char enabled;    /* if 0, Th_output() does nothing. */
  } out;
};
typedef struct Th_Vtab Th_Vtab;


/*
** Opaque handle for interpeter.
*/
typedef struct Th_Interp Th_Interp;


/* 
** Create and delete interpreters. 
*/
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
void Th_DeleteInterp(Th_Interp *);

................................................................................
/*
** Useful functions from th_lang.c.
*/
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);

typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*);

/*
** Sends the given data through vTab->out.f() if vTab->out.enabled is
** true, otherwise this is a no-op. Returns 0 or higher on success, *
** a negative value if vTab->out.f is NULL.
*/
int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int len );

/*
** Sends the given output through pInterp's v-table's output
** implementation. See Th_Vtab_output() for the argument and
** return value semantics.
*/
int Th_output( Th_Interp *pInterp, char const * zData, int len );

/*
** Th_output_f() implementation which sends its output to either pState
** (which must be NULL or a (FILE*)) or stdout (if pState is NULL).
*/
int Th_output_f_FILE( char const * zData, int len, void * pState );


#ifdef TH_USE_SQLITE
#include "stddef.h" /* size_t */
extern void *fossil_realloc(void *p, size_t n);

/*
** Adds the given prepared statement to the interpreter. Returns the

Changes to src/th_main.c.

40
41
42
43
44
45
46


47





48
49
50
51
52
53
54
..
72
73
74
75
76
77
78
79
80


81







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
....
1271
1272
1273
1274
1275
1276
1277






1278
1279
1280
1281
1282
1283
1284
}
static void xFree(void *p){
  if( p ){
    nOutstandingMalloc--;
  }
  free(p);
}


static Th_Vtab vtab = { xMalloc, xFree };






/*
** Generate a TH1 trace message if debugging is enabled.
*/
void Th_Trace(const char *zFormat, ...){
  va_list ap;
  va_start(ap, zFormat);
................................................................................
  void *p, 
  int argc, 
  const char **argv, 
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
  }
  return Th_ToInt(interp, argv[1], argl[1], &enableOutput);


}








/*
** Send text to the appropriate output:  Either to the console
** or to the CGI reply buffer.
*/
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 ) fossil_free((char*)z);
  }
}

struct PutsCmdData {
  char escapeHtml;
................................................................................
    {"query_step",        queryStepCmd,      0},
#endif

    {0, 0, 0}
  };
  if( g.interp==0 ){
    int i;






    g.interp = Th_CreateInterp(&vtab);
    th_register_language(g.interp);       /* Basic scripting commands. */
#ifdef FOSSIL_ENABLE_TCL
    if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
      th_register_tcl(g.interp, &g.tcl);  /* Tcl integration commands. */
    }
#endif







>
>
|
>
>
>
>
>







 







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













|

|
<







 







>
>
>
>
>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

114
115
116
117
118
119
120
....
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
}
static void xFree(void *p){
  if( p ){
    nOutstandingMalloc--;
  }
  free(p);
}


static Th_Vtab vtab = { xMalloc, xFree, {
  Th_output_f_FILE,
  NULL,
  1
  }
};

/*
** Generate a TH1 trace message if debugging is enabled.
*/
void Th_Trace(const char *zFormat, ...){
  va_list ap;
  va_start(ap, zFormat);
................................................................................
  void *p, 
  int argc, 
  const char **argv, 
  int *argl
){
  if( argc!=2 ){
    return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
  }else{
    int rc = Th_ToInt(interp, argv[1], argl[1], &enableOutput);
    vtab.out.enabled = enableOutput;
    return rc;
  }
}

int Th_output_f_cgi_content( char const * zData, int nData, void * pState ){
  cgi_append_content(zData, nData);
  return nData;
}


/*
** Send text to the appropriate output:  Either to the console
** or to the CGI reply buffer.
*/
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 ){
      Th_output_f_cgi_content(z, n, NULL);
    }else{
      Th_output_f_FILE( z, n, stdout );

    }
    if( encode ) fossil_free((char*)z);
  }
}

struct PutsCmdData {
  char escapeHtml;
................................................................................
    {"query_step",        queryStepCmd,      0},
#endif

    {0, 0, 0}
  };
  if( g.interp==0 ){
    int i;
    if(g.cgiOutput){
      vtab.out.f = Th_output_f_cgi_content;
    }else{
      vtab.out.f = Th_output_f_FILE;
      vtab.out.pState = stdout;
    }
    g.interp = Th_CreateInterp(&vtab);
    th_register_language(g.interp);       /* Basic scripting commands. */
#ifdef FOSSIL_ENABLE_TCL
    if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
      th_register_tcl(g.interp, &g.tcl);  /* Tcl integration commands. */
    }
#endif

Changes to test/th1-query-api-1.th1.

130
131
132
133
134
135
136

137
138
139
140
141
142
143
...
165
166
167
168
169
170
171

172
173

set exception 0
catch {
    argv_getint noSuchOptionAndNoDefault
} exception
puts exception = $exception "\n"



proc multiStmt {} {
    set max 5
    set i 0
    set s(0) 0
    for {set i 0} {$i < $max} {incr i} {
       set s($i) [query_prepare "SELECT $i"]
................................................................................
    for {set i 0} {$i < $max} {incr i} {
       puts "closing stmt $s($i)\n"
       query_finalize $s($i)
    }
}
multiStmt


puts "If you got this far, you win!\n"
</th1>







>







 







>


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
166
167
168
169
170
171
172
173
174
175

set exception 0
catch {
    argv_getint noSuchOptionAndNoDefault
} exception
puts exception = $exception "\n"

enable_output 1

proc multiStmt {} {
    set max 5
    set i 0
    set s(0) 0
    for {set i 0} {$i < $max} {incr i} {
       set s($i) [query_prepare "SELECT $i"]
................................................................................
    for {set i 0} {$i < $max} {incr i} {
       puts "closing stmt $s($i)\n"
       query_finalize $s($i)
    }
}
multiStmt

enable_output 1
puts "If you got this far, you win!\n"
</th1>