Fossil SCM

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.

stephan 2012-07-14 11:54 th1-query-api
Commit 3c0209f5dcdc4e7505d1fb072bded0ca638ec187
+24
--- src/th.c
+++ src/th.c
@@ -5,10 +5,11 @@
55
*/
66
77
#include "th.h"
88
#include <string.h>
99
#include <assert.h>
10
+#include <stdio.h> /* FILE class */
1011
1112
typedef struct Th_Command Th_Command;
1213
typedef struct Th_Frame Th_Frame;
1314
typedef struct Th_Variable Th_Variable;
1415
@@ -1388,10 +1389,33 @@
13881389
if( z ){
13891390
pInterp->pVtab->xFree(z);
13901391
}
13911392
}
13921393
1394
+
1395
+int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){
1396
+ if(!vTab->out.f){
1397
+ return -1;
1398
+ }else if(!vTab->out.enabled){
1399
+ return 0;
1400
+ }else{
1401
+ return vTab->out.f( zData, nData, vTab->out.pState );
1402
+ }
1403
+}
1404
+
1405
+
1406
+int Th_output( Th_Interp *pInterp, char const * zData, int nData ){
1407
+ return Th_Vtab_output( pInterp->pVtab, zData, nData );
1408
+}
1409
+
1410
+int Th_output_f_FILE( char const * zData, int nData, void * pState ){
1411
+ FILE * dest = pState ? (FILE*)pState : stdout;
1412
+ int rc = (int)fwrite(zData, 1, nData, dest);
1413
+ fflush(dest);
1414
+ return rc;
1415
+}
1416
+
13931417
/*
13941418
** Install a new th1 command.
13951419
**
13961420
** If a command of the same name already exists, it is deleted automatically.
13971421
*/
13981422
--- src/th.c
+++ src/th.c
@@ -5,10 +5,11 @@
5 */
6
7 #include "th.h"
8 #include <string.h>
9 #include <assert.h>
 
10
11 typedef struct Th_Command Th_Command;
12 typedef struct Th_Frame Th_Frame;
13 typedef struct Th_Variable Th_Variable;
14
@@ -1388,10 +1389,33 @@
1388 if( z ){
1389 pInterp->pVtab->xFree(z);
1390 }
1391 }
1392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1393 /*
1394 ** Install a new th1 command.
1395 **
1396 ** If a command of the same name already exists, it is deleted automatically.
1397 */
1398
--- src/th.c
+++ src/th.c
@@ -5,10 +5,11 @@
5 */
6
7 #include "th.h"
8 #include <string.h>
9 #include <assert.h>
10 #include <stdio.h> /* FILE class */
11
12 typedef struct Th_Command Th_Command;
13 typedef struct Th_Frame Th_Frame;
14 typedef struct Th_Variable Th_Variable;
15
@@ -1388,10 +1389,33 @@
1389 if( z ){
1390 pInterp->pVtab->xFree(z);
1391 }
1392 }
1393
1394
1395 int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){
1396 if(!vTab->out.f){
1397 return -1;
1398 }else if(!vTab->out.enabled){
1399 return 0;
1400 }else{
1401 return vTab->out.f( zData, nData, vTab->out.pState );
1402 }
1403 }
1404
1405
1406 int Th_output( Th_Interp *pInterp, char const * zData, int nData ){
1407 return Th_Vtab_output( pInterp->pVtab, zData, nData );
1408 }
1409
1410 int Th_output_f_FILE( char const * zData, int nData, void * pState ){
1411 FILE * dest = pState ? (FILE*)pState : stdout;
1412 int rc = (int)fwrite(zData, 1, nData, dest);
1413 fflush(dest);
1414 return rc;
1415 }
1416
1417 /*
1418 ** Install a new th1 command.
1419 **
1420 ** If a command of the same name already exists, it is deleted automatically.
1421 */
1422
+39
--- src/th.h
+++ src/th.h
@@ -12,25 +12,43 @@
1212
/* This header file defines the external interface to the custom Scripting
1313
** Language (TH) interpreter. TH is very similar to TCL but is not an
1414
** exact clone.
1515
*/
1616
17
+/*
18
+** Th_output_f() specifies a generic output routine for use by Th_Vtab
19
+** and friends. Its first argument is the data to write, the second is
20
+** the number of bytes to write, and the 3rd is an
21
+** implementation-specific state pointer (may be NULL, depending on
22
+** the implementation). The return value is the number of bytes output
23
+** (which may differ from len due to encoding and whatnot). On error
24
+** a negative value must be returned.
25
+*/
26
+typedef int (*Th_output_f)( char const * zData, int len, void * pState );
27
+
1728
/*
1829
** Before creating an interpreter, the application must allocate and
1930
** populate an instance of the following structure. It must remain valid
2031
** for the lifetime of the interpreter.
2132
*/
2233
struct Th_Vtab {
2334
void *(*xMalloc)(unsigned int);
2435
void (*xFree)(void *);
36
+ struct {
37
+ Th_output_f f; /* output handler */
38
+ void * pState; /* final argument for xOut() */
39
+ char enabled; /* if 0, Th_output() does nothing. */
40
+ } out;
2541
};
2642
typedef struct Th_Vtab Th_Vtab;
43
+
2744
2845
/*
2946
** Opaque handle for interpeter.
3047
*/
3148
typedef struct Th_Interp Th_Interp;
49
+
3250
3351
/*
3452
** Create and delete interpreters.
3553
*/
3654
Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
@@ -189,10 +207,31 @@
189207
*/
190208
int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);
191209
192210
typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
193211
int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*);
212
+
213
+/*
214
+** Sends the given data through vTab->out.f() if vTab->out.enabled is
215
+** true, otherwise this is a no-op. Returns 0 or higher on success, *
216
+** a negative value if vTab->out.f is NULL.
217
+*/
218
+int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int len );
219
+
220
+/*
221
+** Sends the given output through pInterp's v-table's output
222
+** implementation. See Th_Vtab_output() for the argument and
223
+** return value semantics.
224
+*/
225
+int Th_output( Th_Interp *pInterp, char const * zData, int len );
226
+
227
+/*
228
+** Th_output_f() implementation which sends its output to either pState
229
+** (which must be NULL or a (FILE*)) or stdout (if pState is NULL).
230
+*/
231
+int Th_output_f_FILE( char const * zData, int len, void * pState );
232
+
194233
195234
#ifdef TH_USE_SQLITE
196235
#include "stddef.h" /* size_t */
197236
extern void *fossil_realloc(void *p, size_t n);
198237
199238
--- src/th.h
+++ src/th.h
@@ -12,25 +12,43 @@
12 /* This header file defines the external interface to the custom Scripting
13 ** Language (TH) interpreter. TH is very similar to TCL but is not an
14 ** exact clone.
15 */
16
 
 
 
 
 
 
 
 
 
 
 
17 /*
18 ** Before creating an interpreter, the application must allocate and
19 ** populate an instance of the following structure. It must remain valid
20 ** for the lifetime of the interpreter.
21 */
22 struct Th_Vtab {
23 void *(*xMalloc)(unsigned int);
24 void (*xFree)(void *);
 
 
 
 
 
25 };
26 typedef struct Th_Vtab Th_Vtab;
 
27
28 /*
29 ** Opaque handle for interpeter.
30 */
31 typedef struct Th_Interp Th_Interp;
 
32
33 /*
34 ** Create and delete interpreters.
35 */
36 Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
@@ -189,10 +207,31 @@
189 */
190 int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);
191
192 typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
193 int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
195 #ifdef TH_USE_SQLITE
196 #include "stddef.h" /* size_t */
197 extern void *fossil_realloc(void *p, size_t n);
198
199
--- src/th.h
+++ src/th.h
@@ -12,25 +12,43 @@
12 /* This header file defines the external interface to the custom Scripting
13 ** Language (TH) interpreter. TH is very similar to TCL but is not an
14 ** exact clone.
15 */
16
17 /*
18 ** Th_output_f() specifies a generic output routine for use by Th_Vtab
19 ** and friends. Its first argument is the data to write, the second is
20 ** the number of bytes to write, and the 3rd is an
21 ** implementation-specific state pointer (may be NULL, depending on
22 ** the implementation). The return value is the number of bytes output
23 ** (which may differ from len due to encoding and whatnot). On error
24 ** a negative value must be returned.
25 */
26 typedef int (*Th_output_f)( char const * zData, int len, void * pState );
27
28 /*
29 ** Before creating an interpreter, the application must allocate and
30 ** populate an instance of the following structure. It must remain valid
31 ** for the lifetime of the interpreter.
32 */
33 struct Th_Vtab {
34 void *(*xMalloc)(unsigned int);
35 void (*xFree)(void *);
36 struct {
37 Th_output_f f; /* output handler */
38 void * pState; /* final argument for xOut() */
39 char enabled; /* if 0, Th_output() does nothing. */
40 } out;
41 };
42 typedef struct Th_Vtab Th_Vtab;
43
44
45 /*
46 ** Opaque handle for interpeter.
47 */
48 typedef struct Th_Interp Th_Interp;
49
50
51 /*
52 ** Create and delete interpreters.
53 */
54 Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
@@ -189,10 +207,31 @@
207 */
208 int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);
209
210 typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
211 int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*);
212
213 /*
214 ** Sends the given data through vTab->out.f() if vTab->out.enabled is
215 ** true, otherwise this is a no-op. Returns 0 or higher on success, *
216 ** a negative value if vTab->out.f is NULL.
217 */
218 int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int len );
219
220 /*
221 ** Sends the given output through pInterp's v-table's output
222 ** implementation. See Th_Vtab_output() for the argument and
223 ** return value semantics.
224 */
225 int Th_output( Th_Interp *pInterp, char const * zData, int len );
226
227 /*
228 ** Th_output_f() implementation which sends its output to either pState
229 ** (which must be NULL or a (FILE*)) or stdout (if pState is NULL).
230 */
231 int Th_output_f_FILE( char const * zData, int len, void * pState );
232
233
234 #ifdef TH_USE_SQLITE
235 #include "stddef.h" /* size_t */
236 extern void *fossil_realloc(void *p, size_t n);
237
238
+26 -5
--- src/th_main.c
+++ src/th_main.c
@@ -42,11 +42,18 @@
4242
if( p ){
4343
nOutstandingMalloc--;
4444
}
4545
free(p);
4646
}
47
-static Th_Vtab vtab = { xMalloc, xFree };
47
+
48
+
49
+static Th_Vtab vtab = { xMalloc, xFree, {
50
+ Th_output_f_FILE,
51
+ NULL,
52
+ 1
53
+ }
54
+};
4855
4956
/*
5057
** Generate a TH1 trace message if debugging is enabled.
5158
*/
5259
void Th_Trace(const char *zFormat, ...){
@@ -74,13 +81,22 @@
7481
const char **argv,
7582
int *argl
7683
){
7784
if( argc!=2 ){
7885
return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
86
+ }else{
87
+ int rc = Th_ToInt(interp, argv[1], argl[1], &enableOutput);
88
+ vtab.out.enabled = enableOutput;
89
+ return rc;
7990
}
80
- return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
91
+}
92
+
93
+int Th_output_f_cgi_content( char const * zData, int nData, void * pState ){
94
+ cgi_append_content(zData, nData);
95
+ return nData;
8196
}
97
+
8298
8399
/*
84100
** Send text to the appropriate output: Either to the console
85101
** or to the CGI reply buffer.
86102
*/
@@ -90,14 +106,13 @@
90106
if( encode ){
91107
z = htmlize(z, n);
92108
n = strlen(z);
93109
}
94110
if( g.cgiOutput ){
95
- cgi_append_content(z, n);
111
+ Th_output_f_cgi_content(z, n, NULL);
96112
}else{
97
- fwrite(z, 1, n, stdout);
98
- fflush(stdout);
113
+ Th_output_f_FILE( z, n, stdout );
99114
}
100115
if( encode ) fossil_free((char*)z);
101116
}
102117
}
103118
@@ -1273,10 +1288,16 @@
12731288
12741289
{0, 0, 0}
12751290
};
12761291
if( g.interp==0 ){
12771292
int i;
1293
+ if(g.cgiOutput){
1294
+ vtab.out.f = Th_output_f_cgi_content;
1295
+ }else{
1296
+ vtab.out.f = Th_output_f_FILE;
1297
+ vtab.out.pState = stdout;
1298
+ }
12781299
g.interp = Th_CreateInterp(&vtab);
12791300
th_register_language(g.interp); /* Basic scripting commands. */
12801301
#ifdef FOSSIL_ENABLE_TCL
12811302
if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
12821303
th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
12831304
--- src/th_main.c
+++ src/th_main.c
@@ -42,11 +42,18 @@
42 if( p ){
43 nOutstandingMalloc--;
44 }
45 free(p);
46 }
47 static Th_Vtab vtab = { xMalloc, xFree };
 
 
 
 
 
 
 
48
49 /*
50 ** Generate a TH1 trace message if debugging is enabled.
51 */
52 void Th_Trace(const char *zFormat, ...){
@@ -74,13 +81,22 @@
74 const char **argv,
75 int *argl
76 ){
77 if( argc!=2 ){
78 return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
 
 
 
 
79 }
80 return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
 
 
 
 
81 }
 
82
83 /*
84 ** Send text to the appropriate output: Either to the console
85 ** or to the CGI reply buffer.
86 */
@@ -90,14 +106,13 @@
90 if( encode ){
91 z = htmlize(z, n);
92 n = strlen(z);
93 }
94 if( g.cgiOutput ){
95 cgi_append_content(z, n);
96 }else{
97 fwrite(z, 1, n, stdout);
98 fflush(stdout);
99 }
100 if( encode ) fossil_free((char*)z);
101 }
102 }
103
@@ -1273,10 +1288,16 @@
1273
1274 {0, 0, 0}
1275 };
1276 if( g.interp==0 ){
1277 int i;
 
 
 
 
 
 
1278 g.interp = Th_CreateInterp(&vtab);
1279 th_register_language(g.interp); /* Basic scripting commands. */
1280 #ifdef FOSSIL_ENABLE_TCL
1281 if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
1282 th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
1283
--- src/th_main.c
+++ src/th_main.c
@@ -42,11 +42,18 @@
42 if( p ){
43 nOutstandingMalloc--;
44 }
45 free(p);
46 }
47
48
49 static Th_Vtab vtab = { xMalloc, xFree, {
50 Th_output_f_FILE,
51 NULL,
52 1
53 }
54 };
55
56 /*
57 ** Generate a TH1 trace message if debugging is enabled.
58 */
59 void Th_Trace(const char *zFormat, ...){
@@ -74,13 +81,22 @@
81 const char **argv,
82 int *argl
83 ){
84 if( argc!=2 ){
85 return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
86 }else{
87 int rc = Th_ToInt(interp, argv[1], argl[1], &enableOutput);
88 vtab.out.enabled = enableOutput;
89 return rc;
90 }
91 }
92
93 int Th_output_f_cgi_content( char const * zData, int nData, void * pState ){
94 cgi_append_content(zData, nData);
95 return nData;
96 }
97
98
99 /*
100 ** Send text to the appropriate output: Either to the console
101 ** or to the CGI reply buffer.
102 */
@@ -90,14 +106,13 @@
106 if( encode ){
107 z = htmlize(z, n);
108 n = strlen(z);
109 }
110 if( g.cgiOutput ){
111 Th_output_f_cgi_content(z, n, NULL);
112 }else{
113 Th_output_f_FILE( z, n, stdout );
 
114 }
115 if( encode ) fossil_free((char*)z);
116 }
117 }
118
@@ -1273,10 +1288,16 @@
1288
1289 {0, 0, 0}
1290 };
1291 if( g.interp==0 ){
1292 int i;
1293 if(g.cgiOutput){
1294 vtab.out.f = Th_output_f_cgi_content;
1295 }else{
1296 vtab.out.f = Th_output_f_FILE;
1297 vtab.out.pState = stdout;
1298 }
1299 g.interp = Th_CreateInterp(&vtab);
1300 th_register_language(g.interp); /* Basic scripting commands. */
1301 #ifdef FOSSIL_ENABLE_TCL
1302 if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
1303 th_register_tcl(g.interp, &g.tcl); /* Tcl integration commands. */
1304
--- test/th1-query-api-1.th1
+++ test/th1-query-api-1.th1
@@ -132,10 +132,11 @@
132132
catch {
133133
argv_getint noSuchOptionAndNoDefault
134134
} exception
135135
puts exception = $exception "\n"
136136
137
+enable_output 1
137138
138139
proc multiStmt {} {
139140
set max 5
140141
set i 0
141142
set s(0) 0
@@ -167,7 +168,8 @@
167168
query_finalize $s($i)
168169
}
169170
}
170171
multiStmt
171172
173
+enable_output 1
172174
puts "If you got this far, you win!\n"
173175
</th1>
174176
--- test/th1-query-api-1.th1
+++ test/th1-query-api-1.th1
@@ -132,10 +132,11 @@
132 catch {
133 argv_getint noSuchOptionAndNoDefault
134 } exception
135 puts exception = $exception "\n"
136
 
137
138 proc multiStmt {} {
139 set max 5
140 set i 0
141 set s(0) 0
@@ -167,7 +168,8 @@
167 query_finalize $s($i)
168 }
169 }
170 multiStmt
171
 
172 puts "If you got this far, you win!\n"
173 </th1>
174
--- test/th1-query-api-1.th1
+++ test/th1-query-api-1.th1
@@ -132,10 +132,11 @@
132 catch {
133 argv_getint noSuchOptionAndNoDefault
134 } exception
135 puts exception = $exception "\n"
136
137 enable_output 1
138
139 proc multiStmt {} {
140 set max 5
141 set i 0
142 set s(0) 0
@@ -167,7 +168,8 @@
168 query_finalize $s($i)
169 }
170 }
171 multiStmt
172
173 enable_output 1
174 puts "If you got this far, you win!\n"
175 </th1>
176

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button