Fossil SCM

Started adding infrastructure to allow us to expand the ob handler support to include more types. Added another th1 test script.

stephan 2012-07-15 17:33 th1-query-api
Commit 726f998b5f6565800a9125bd788bbc70053a55e7
+64 -22
--- src/th.c
+++ src/th.c
@@ -26,13 +26,21 @@
2626
extern void *fossil_realloc(void *p, size_t n);
2727
static void * th_fossil_realloc(void *p, unsigned int n){
2828
return fossil_realloc( p, n );
2929
}
3030
static int Th_output_f_ob( char const * zData, int len, void * pState );
31
+static void Th_output_dispose_ob( void * pState );
3132
typedef struct Th_Command Th_Command;
3233
typedef struct Th_Frame Th_Frame;
3334
typedef struct Th_Variable Th_Variable;
35
+
36
+const Th_Vtab_Output Th_Vtab_Output_FILE = {
37
+ Th_output_f_FILE /* write() */,
38
+ Th_output_dispose_FILE /* dispose() */,
39
+ NULL /*pState*/,
40
+ 1/*enabled*/
41
+};
3442
3543
/*
3644
** Holds client-provided "garbage collected" data for
3745
** a Th_Interp instance.
3846
*/
@@ -1442,16 +1450,16 @@
14421450
return p;
14431451
}
14441452
14451453
14461454
int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){
1447
- if(!vTab->out.f){
1455
+ if(!vTab->out.write){
14481456
return -1;
14491457
}else if(!vTab->out.enabled){
14501458
return 0;
14511459
}else{
1452
- return vTab->out.f( zData, nData, vTab->out.pState );
1460
+ return vTab->out.write( zData, nData, vTab->out.pState );
14531461
}
14541462
}
14551463
14561464
14571465
int Th_output( Th_Interp *pInterp, char const * zData, int nData ){
@@ -1462,10 +1470,21 @@
14621470
FILE * dest = pState ? (FILE*)pState : stdout;
14631471
int rc = (int)fwrite(zData, 1, nData, dest);
14641472
fflush(dest);
14651473
return rc;
14661474
}
1475
+
1476
+void Th_output_dispose_FILE( void * pState ){
1477
+ FILE * f = pState ? (FILE*)pState : NULL;
1478
+ if(f
1479
+ && (f != stdout)
1480
+ && (f != stderr)
1481
+ && (f != stdin)){
1482
+ fflush(f);
1483
+ fclose(f);
1484
+ }
1485
+}
14671486
14681487
/*
14691488
** Install a new th1 command.
14701489
**
14711490
** If a command of the same name already exists, it is deleted automatically.
@@ -2772,17 +2791,23 @@
27722791
0/*nBuf*/, \
27732792
-1/*cursor*/, \
27742793
NULL/*interp*/, \
27752794
NULL/*aOutput*/ \
27762795
}
2796
+
2797
+/*
2798
+** Vtab impl for the ob buffering layer.
2799
+*/
27772800
#define Th_Vtab_Output_empty_m { \
2778
- Th_output_f_ob /*f*/, \
2801
+ NULL /* write() */, \
2802
+ NULL /* dispose() */, \
27792803
NULL /*pState*/,\
27802804
1/*enabled*/\
27812805
}
2782
-#define Th_Vtab_Output_ob_m { \
2783
- Th_output_f_ob /*f*/, \
2806
+#define Th_Vtab_Output_ob_m { \
2807
+ Th_output_f_ob /*write()*/, \
2808
+ Th_output_dispose_ob /* dispose() */, \
27842809
NULL /*pState*/,\
27852810
1/*enabled*/\
27862811
}
27872812
static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
27882813
static Th_Vtab_Output Th_Vtab_Output_ob = Th_Vtab_Output_ob_m;
@@ -2789,11 +2814,10 @@
27892814
static Th_Vtab_Output Th_Vtab_Output_empty = Th_Vtab_Output_empty_m;
27902815
#define Th_Ob_Man_KEY "Th_Ob_Man"
27912816
Th_Ob_Man * Th_ob_manager(Th_Interp *interp){
27922817
return (Th_Ob_Man*) Th_Data_Get(interp, Th_Ob_Man_KEY );
27932818
}
2794
-
27952819
27962820
Blob * Th_ob_current( Th_Ob_Man * pMan ){
27972821
return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
27982822
}
27992823
@@ -2809,24 +2833,32 @@
28092833
assert( b );
28102834
blob_append( b, zData, len );
28112835
return len;
28122836
}
28132837
2814
-/*
2815
-** Vtab impl for the ob buffering layer.
2816
-*/
2817
-static Th_Vtab Th_Vtab_Ob = { th_fossil_realloc,
2818
- {
2819
- Th_output_f_ob,
2820
- NULL,
2821
- 1
2822
- }
2823
-};
2824
-
2825
-int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut ){
2838
+static void Th_output_dispose_ob( void * pState ){
2839
+ /* possible todo: move the cleanup logic from
2840
+ Th_ob_pop() to here? */
2841
+ /*printf("disposing() ob vtab.\n"); */
2842
+#if 0
2843
+ Th_Ob_Man * pMan = (Th_Ob_Man*)pState;
2844
+ Blob * b = Th_ob_current( pMan );
2845
+ assert( NULL != pMan );
2846
+ assert( b );
2847
+#endif
2848
+}
2849
+
2850
+
2851
+
2852
+int Th_ob_push( Th_Ob_Man * pMan,
2853
+ Th_Vtab_Output const * pWriter,
2854
+ Blob ** pOut ){
28262855
Blob * pBlob;
28272856
int x, i;
2857
+ if( NULL == pWriter ){
2858
+ pWriter = &Th_Vtab_Output_ob;
2859
+ }
28282860
assert( NULL != pMan->interp );
28292861
pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob));
28302862
*pBlob = empty_blob;
28312863
28322864
if( pMan->cursor >= pMan->nBuf-2 ){
@@ -2855,11 +2887,11 @@
28552887
assert( pMan->nBuf > pMan->cursor );
28562888
assert( pMan->cursor >= -1 );
28572889
++pMan->cursor;
28582890
pMan->aBuf[pMan->cursor] = pBlob;
28592891
pMan->aOutput[pMan->cursor] = pMan->interp->pVtab->out;
2860
- pMan->interp->pVtab->out = Th_Vtab_Ob.out;
2892
+ pMan->interp->pVtab->out = *pWriter;
28612893
pMan->interp->pVtab->out.pState = pMan;
28622894
if( pOut ){
28632895
*pOut = pBlob;
28642896
}
28652897
/*printf( "push: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
@@ -2874,15 +2906,20 @@
28742906
Blob * Th_ob_pop( Th_Ob_Man * pMan ){
28752907
if( pMan->cursor < 0 ){
28762908
return NULL;
28772909
}else{
28782910
Blob * rc;
2911
+ Th_Vtab_Output * theOut;
28792912
/*printf( "pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
28802913
assert( pMan->nBuf > pMan->cursor );
28812914
rc = pMan->aBuf[pMan->cursor];
28822915
pMan->aBuf[pMan->cursor] = NULL;
2883
- pMan->interp->pVtab->out = pMan->aOutput[pMan->cursor];
2916
+ theOut = &pMan->aOutput[pMan->cursor];
2917
+ if( theOut->dispose ){
2918
+ theOut->dispose( theOut->pState );
2919
+ }
2920
+ pMan->interp->pVtab->out = *theOut;
28842921
pMan->aOutput[pMan->cursor] = Th_Vtab_Output_empty;
28852922
if(-1 == --pMan->cursor){
28862923
Th_Interp * interp = pMan->interp;
28872924
Th_Free( pMan->interp, pMan->aBuf );
28882925
Th_Free( pMan->interp, pMan->aOutput );
@@ -3071,23 +3108,28 @@
30713108
}
30723109
30733110
/*
30743111
** TH Syntax:
30753112
**
3076
-** ob start
3113
+** ob start|push
30773114
**
30783115
** Pushes a new level of buffering onto the buffer stack.
30793116
** Returns the new buffering level (1-based).
3117
+**
3118
+** TODO: take an optional final argument naming the output handler.
3119
+** e.g. "stdout" or "cgi" or "default"
3120
+**
30803121
*/
30813122
static int ob_start_command( Th_Interp *interp, void *ctx,
30823123
int argc, const char **argv, int *argl
30833124
){
30843125
Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
30853126
Blob * b = NULL;
30863127
int rc;
3128
+ Th_Vtab_Output const * pWriter = &Th_Vtab_Output_ob;
30873129
assert( pMan && (interp == pMan->interp) );
3088
- rc = Th_ob_push(pMan, &b);
3130
+ rc = Th_ob_push(pMan, NULL, &b);
30893131
if( TH_OK != rc ){
30903132
assert( NULL == b );
30913133
return rc;
30923134
}
30933135
assert( NULL != b );
30943136
--- src/th.c
+++ src/th.c
@@ -26,13 +26,21 @@
26 extern void *fossil_realloc(void *p, size_t n);
27 static void * th_fossil_realloc(void *p, unsigned int n){
28 return fossil_realloc( p, n );
29 }
30 static int Th_output_f_ob( char const * zData, int len, void * pState );
 
31 typedef struct Th_Command Th_Command;
32 typedef struct Th_Frame Th_Frame;
33 typedef struct Th_Variable Th_Variable;
 
 
 
 
 
 
 
34
35 /*
36 ** Holds client-provided "garbage collected" data for
37 ** a Th_Interp instance.
38 */
@@ -1442,16 +1450,16 @@
1442 return p;
1443 }
1444
1445
1446 int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){
1447 if(!vTab->out.f){
1448 return -1;
1449 }else if(!vTab->out.enabled){
1450 return 0;
1451 }else{
1452 return vTab->out.f( zData, nData, vTab->out.pState );
1453 }
1454 }
1455
1456
1457 int Th_output( Th_Interp *pInterp, char const * zData, int nData ){
@@ -1462,10 +1470,21 @@
1462 FILE * dest = pState ? (FILE*)pState : stdout;
1463 int rc = (int)fwrite(zData, 1, nData, dest);
1464 fflush(dest);
1465 return rc;
1466 }
 
 
 
 
 
 
 
 
 
 
 
1467
1468 /*
1469 ** Install a new th1 command.
1470 **
1471 ** If a command of the same name already exists, it is deleted automatically.
@@ -2772,17 +2791,23 @@
2772 0/*nBuf*/, \
2773 -1/*cursor*/, \
2774 NULL/*interp*/, \
2775 NULL/*aOutput*/ \
2776 }
 
 
 
 
2777 #define Th_Vtab_Output_empty_m { \
2778 Th_output_f_ob /*f*/, \
 
2779 NULL /*pState*/,\
2780 1/*enabled*/\
2781 }
2782 #define Th_Vtab_Output_ob_m { \
2783 Th_output_f_ob /*f*/, \
 
2784 NULL /*pState*/,\
2785 1/*enabled*/\
2786 }
2787 static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
2788 static Th_Vtab_Output Th_Vtab_Output_ob = Th_Vtab_Output_ob_m;
@@ -2789,11 +2814,10 @@
2789 static Th_Vtab_Output Th_Vtab_Output_empty = Th_Vtab_Output_empty_m;
2790 #define Th_Ob_Man_KEY "Th_Ob_Man"
2791 Th_Ob_Man * Th_ob_manager(Th_Interp *interp){
2792 return (Th_Ob_Man*) Th_Data_Get(interp, Th_Ob_Man_KEY );
2793 }
2794
2795
2796 Blob * Th_ob_current( Th_Ob_Man * pMan ){
2797 return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
2798 }
2799
@@ -2809,24 +2833,32 @@
2809 assert( b );
2810 blob_append( b, zData, len );
2811 return len;
2812 }
2813
2814 /*
2815 ** Vtab impl for the ob buffering layer.
2816 */
2817 static Th_Vtab Th_Vtab_Ob = { th_fossil_realloc,
2818 {
2819 Th_output_f_ob,
2820 NULL,
2821 1
2822 }
2823 };
2824
2825 int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut ){
 
 
 
 
 
2826 Blob * pBlob;
2827 int x, i;
 
 
 
2828 assert( NULL != pMan->interp );
2829 pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob));
2830 *pBlob = empty_blob;
2831
2832 if( pMan->cursor >= pMan->nBuf-2 ){
@@ -2855,11 +2887,11 @@
2855 assert( pMan->nBuf > pMan->cursor );
2856 assert( pMan->cursor >= -1 );
2857 ++pMan->cursor;
2858 pMan->aBuf[pMan->cursor] = pBlob;
2859 pMan->aOutput[pMan->cursor] = pMan->interp->pVtab->out;
2860 pMan->interp->pVtab->out = Th_Vtab_Ob.out;
2861 pMan->interp->pVtab->out.pState = pMan;
2862 if( pOut ){
2863 *pOut = pBlob;
2864 }
2865 /*printf( "push: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
@@ -2874,15 +2906,20 @@
2874 Blob * Th_ob_pop( Th_Ob_Man * pMan ){
2875 if( pMan->cursor < 0 ){
2876 return NULL;
2877 }else{
2878 Blob * rc;
 
2879 /*printf( "pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
2880 assert( pMan->nBuf > pMan->cursor );
2881 rc = pMan->aBuf[pMan->cursor];
2882 pMan->aBuf[pMan->cursor] = NULL;
2883 pMan->interp->pVtab->out = pMan->aOutput[pMan->cursor];
 
 
 
 
2884 pMan->aOutput[pMan->cursor] = Th_Vtab_Output_empty;
2885 if(-1 == --pMan->cursor){
2886 Th_Interp * interp = pMan->interp;
2887 Th_Free( pMan->interp, pMan->aBuf );
2888 Th_Free( pMan->interp, pMan->aOutput );
@@ -3071,23 +3108,28 @@
3071 }
3072
3073 /*
3074 ** TH Syntax:
3075 **
3076 ** ob start
3077 **
3078 ** Pushes a new level of buffering onto the buffer stack.
3079 ** Returns the new buffering level (1-based).
 
 
 
 
3080 */
3081 static int ob_start_command( Th_Interp *interp, void *ctx,
3082 int argc, const char **argv, int *argl
3083 ){
3084 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
3085 Blob * b = NULL;
3086 int rc;
 
3087 assert( pMan && (interp == pMan->interp) );
3088 rc = Th_ob_push(pMan, &b);
3089 if( TH_OK != rc ){
3090 assert( NULL == b );
3091 return rc;
3092 }
3093 assert( NULL != b );
3094
--- src/th.c
+++ src/th.c
@@ -26,13 +26,21 @@
26 extern void *fossil_realloc(void *p, size_t n);
27 static void * th_fossil_realloc(void *p, unsigned int n){
28 return fossil_realloc( p, n );
29 }
30 static int Th_output_f_ob( char const * zData, int len, void * pState );
31 static void Th_output_dispose_ob( void * pState );
32 typedef struct Th_Command Th_Command;
33 typedef struct Th_Frame Th_Frame;
34 typedef struct Th_Variable Th_Variable;
35
36 const Th_Vtab_Output Th_Vtab_Output_FILE = {
37 Th_output_f_FILE /* write() */,
38 Th_output_dispose_FILE /* dispose() */,
39 NULL /*pState*/,
40 1/*enabled*/
41 };
42
43 /*
44 ** Holds client-provided "garbage collected" data for
45 ** a Th_Interp instance.
46 */
@@ -1442,16 +1450,16 @@
1450 return p;
1451 }
1452
1453
1454 int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){
1455 if(!vTab->out.write){
1456 return -1;
1457 }else if(!vTab->out.enabled){
1458 return 0;
1459 }else{
1460 return vTab->out.write( zData, nData, vTab->out.pState );
1461 }
1462 }
1463
1464
1465 int Th_output( Th_Interp *pInterp, char const * zData, int nData ){
@@ -1462,10 +1470,21 @@
1470 FILE * dest = pState ? (FILE*)pState : stdout;
1471 int rc = (int)fwrite(zData, 1, nData, dest);
1472 fflush(dest);
1473 return rc;
1474 }
1475
1476 void Th_output_dispose_FILE( void * pState ){
1477 FILE * f = pState ? (FILE*)pState : NULL;
1478 if(f
1479 && (f != stdout)
1480 && (f != stderr)
1481 && (f != stdin)){
1482 fflush(f);
1483 fclose(f);
1484 }
1485 }
1486
1487 /*
1488 ** Install a new th1 command.
1489 **
1490 ** If a command of the same name already exists, it is deleted automatically.
@@ -2772,17 +2791,23 @@
2791 0/*nBuf*/, \
2792 -1/*cursor*/, \
2793 NULL/*interp*/, \
2794 NULL/*aOutput*/ \
2795 }
2796
2797 /*
2798 ** Vtab impl for the ob buffering layer.
2799 */
2800 #define Th_Vtab_Output_empty_m { \
2801 NULL /* write() */, \
2802 NULL /* dispose() */, \
2803 NULL /*pState*/,\
2804 1/*enabled*/\
2805 }
2806 #define Th_Vtab_Output_ob_m { \
2807 Th_output_f_ob /*write()*/, \
2808 Th_output_dispose_ob /* dispose() */, \
2809 NULL /*pState*/,\
2810 1/*enabled*/\
2811 }
2812 static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
2813 static Th_Vtab_Output Th_Vtab_Output_ob = Th_Vtab_Output_ob_m;
@@ -2789,11 +2814,10 @@
2814 static Th_Vtab_Output Th_Vtab_Output_empty = Th_Vtab_Output_empty_m;
2815 #define Th_Ob_Man_KEY "Th_Ob_Man"
2816 Th_Ob_Man * Th_ob_manager(Th_Interp *interp){
2817 return (Th_Ob_Man*) Th_Data_Get(interp, Th_Ob_Man_KEY );
2818 }
 
2819
2820 Blob * Th_ob_current( Th_Ob_Man * pMan ){
2821 return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
2822 }
2823
@@ -2809,24 +2833,32 @@
2833 assert( b );
2834 blob_append( b, zData, len );
2835 return len;
2836 }
2837
2838 static void Th_output_dispose_ob( void * pState ){
2839 /* possible todo: move the cleanup logic from
2840 Th_ob_pop() to here? */
2841 /*printf("disposing() ob vtab.\n"); */
2842 #if 0
2843 Th_Ob_Man * pMan = (Th_Ob_Man*)pState;
2844 Blob * b = Th_ob_current( pMan );
2845 assert( NULL != pMan );
2846 assert( b );
2847 #endif
2848 }
2849
2850
2851
2852 int Th_ob_push( Th_Ob_Man * pMan,
2853 Th_Vtab_Output const * pWriter,
2854 Blob ** pOut ){
2855 Blob * pBlob;
2856 int x, i;
2857 if( NULL == pWriter ){
2858 pWriter = &Th_Vtab_Output_ob;
2859 }
2860 assert( NULL != pMan->interp );
2861 pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob));
2862 *pBlob = empty_blob;
2863
2864 if( pMan->cursor >= pMan->nBuf-2 ){
@@ -2855,11 +2887,11 @@
2887 assert( pMan->nBuf > pMan->cursor );
2888 assert( pMan->cursor >= -1 );
2889 ++pMan->cursor;
2890 pMan->aBuf[pMan->cursor] = pBlob;
2891 pMan->aOutput[pMan->cursor] = pMan->interp->pVtab->out;
2892 pMan->interp->pVtab->out = *pWriter;
2893 pMan->interp->pVtab->out.pState = pMan;
2894 if( pOut ){
2895 *pOut = pBlob;
2896 }
2897 /*printf( "push: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
@@ -2874,15 +2906,20 @@
2906 Blob * Th_ob_pop( Th_Ob_Man * pMan ){
2907 if( pMan->cursor < 0 ){
2908 return NULL;
2909 }else{
2910 Blob * rc;
2911 Th_Vtab_Output * theOut;
2912 /*printf( "pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/
2913 assert( pMan->nBuf > pMan->cursor );
2914 rc = pMan->aBuf[pMan->cursor];
2915 pMan->aBuf[pMan->cursor] = NULL;
2916 theOut = &pMan->aOutput[pMan->cursor];
2917 if( theOut->dispose ){
2918 theOut->dispose( theOut->pState );
2919 }
2920 pMan->interp->pVtab->out = *theOut;
2921 pMan->aOutput[pMan->cursor] = Th_Vtab_Output_empty;
2922 if(-1 == --pMan->cursor){
2923 Th_Interp * interp = pMan->interp;
2924 Th_Free( pMan->interp, pMan->aBuf );
2925 Th_Free( pMan->interp, pMan->aOutput );
@@ -3071,23 +3108,28 @@
3108 }
3109
3110 /*
3111 ** TH Syntax:
3112 **
3113 ** ob start|push
3114 **
3115 ** Pushes a new level of buffering onto the buffer stack.
3116 ** Returns the new buffering level (1-based).
3117 **
3118 ** TODO: take an optional final argument naming the output handler.
3119 ** e.g. "stdout" or "cgi" or "default"
3120 **
3121 */
3122 static int ob_start_command( Th_Interp *interp, void *ctx,
3123 int argc, const char **argv, int *argl
3124 ){
3125 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
3126 Blob * b = NULL;
3127 int rc;
3128 Th_Vtab_Output const * pWriter = &Th_Vtab_Output_ob;
3129 assert( pMan && (interp == pMan->interp) );
3130 rc = Th_ob_push(pMan, NULL, &b);
3131 if( TH_OK != rc ){
3132 assert( NULL == b );
3133 return rc;
3134 }
3135 assert( NULL != b );
3136
+22 -5
--- src/th.h
+++ src/th.h
@@ -40,25 +40,37 @@
4040
** (which may differ from len due to encoding and whatnot). On error
4141
** a negative value must be returned.
4242
*/
4343
typedef int (*Th_output_f)( char const * zData, int len, void * pState );
4444
45
+/*
46
+** This structure defines the output state associated with a
47
+** Th_Vtab. It is intended that a given Vtab be able to swap out
48
+** output back-ends during its lifetime, e.g. to form a stack of
49
+** buffers.
50
+*/
4551
struct Th_Vtab_Output {
46
- Th_output_f f; /* output handler */
47
- void * pState; /* final argument for xOut() */
52
+ Th_output_f write; /* output handler */
53
+ void (*dispose)( void * pState );
54
+ void * pState; /* final argument for xOut() and dispose()*/
4855
char enabled; /* if 0, Th_output() does nothing. */
4956
};
5057
typedef struct Th_Vtab_Output Th_Vtab_Output;
5158
59
+/*
60
+** Shared Th_Vtab_Output instance used for copy-initialization.
61
+*/
62
+extern const Th_Vtab_Output Th_Vtab_Output_FILE;
63
+
5264
/*
5365
** Before creating an interpreter, the application must allocate and
5466
** populate an instance of the following structure. It must remain valid
5567
** for the lifetime of the interpreter.
5668
*/
5769
struct Th_Vtab {
58
- void *(*xRealloc)(void *, unsigned int);
59
- Th_Vtab_Output out;
70
+ void *(*xRealloc)(void *, unsigned int); /* Re/deallocation routine. */
71
+ Th_Vtab_Output out; /* output implementation */
6072
};
6173
typedef struct Th_Vtab Th_Vtab;
6274
6375
6476
/*
@@ -260,10 +272,15 @@
260272
** Th_output_f() implementation which sends its output to either
261273
** pState (which must be NULL or a (FILE*)) or stdout (if pState is
262274
** NULL).
263275
*/
264276
int Th_output_f_FILE( char const * zData, int len, void * pState );
277
+/*
278
+** Th_Vtab_Output::dispose impl for FILE handles. If pState is not
279
+** one of the standard streams then it is fclose()d.
280
+*/
281
+void Th_output_dispose_FILE( void * pState );
265282
266283
typedef struct Th_Command_Reg Th_Command_Reg;
267284
/*
268285
** A helper type for holding lists of function registration information.
269286
** For use with Th_register_commands().
@@ -339,11 +356,11 @@
339356
** Pushes a new blob onto pMan's stack. On success
340357
** returns TH_OK and assigns *pOut (if pOut is not NULL)
341358
** to the new blob (which is owned by pMan). On error
342359
** pOut is not modified and non-0 is returned.
343360
*/
344
-int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut );
361
+int Th_ob_push( Th_Ob_Man * pMan, Th_Vtab_Output const * pWriter, Blob ** pOut );
345362
346363
/*
347364
** Pops the top-most output buffer off the stack and returns
348365
** it. Returns NULL if there is no current buffer. When the last
349366
** buffer is popped, pMan's internals are cleaned up (but pMan is not
350367
--- src/th.h
+++ src/th.h
@@ -40,25 +40,37 @@
40 ** (which may differ from len due to encoding and whatnot). On error
41 ** a negative value must be returned.
42 */
43 typedef int (*Th_output_f)( char const * zData, int len, void * pState );
44
 
 
 
 
 
 
45 struct Th_Vtab_Output {
46 Th_output_f f; /* output handler */
47 void * pState; /* final argument for xOut() */
 
48 char enabled; /* if 0, Th_output() does nothing. */
49 };
50 typedef struct Th_Vtab_Output Th_Vtab_Output;
51
 
 
 
 
 
52 /*
53 ** Before creating an interpreter, the application must allocate and
54 ** populate an instance of the following structure. It must remain valid
55 ** for the lifetime of the interpreter.
56 */
57 struct Th_Vtab {
58 void *(*xRealloc)(void *, unsigned int);
59 Th_Vtab_Output out;
60 };
61 typedef struct Th_Vtab Th_Vtab;
62
63
64 /*
@@ -260,10 +272,15 @@
260 ** Th_output_f() implementation which sends its output to either
261 ** pState (which must be NULL or a (FILE*)) or stdout (if pState is
262 ** NULL).
263 */
264 int Th_output_f_FILE( char const * zData, int len, void * pState );
 
 
 
 
 
265
266 typedef struct Th_Command_Reg Th_Command_Reg;
267 /*
268 ** A helper type for holding lists of function registration information.
269 ** For use with Th_register_commands().
@@ -339,11 +356,11 @@
339 ** Pushes a new blob onto pMan's stack. On success
340 ** returns TH_OK and assigns *pOut (if pOut is not NULL)
341 ** to the new blob (which is owned by pMan). On error
342 ** pOut is not modified and non-0 is returned.
343 */
344 int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut );
345
346 /*
347 ** Pops the top-most output buffer off the stack and returns
348 ** it. Returns NULL if there is no current buffer. When the last
349 ** buffer is popped, pMan's internals are cleaned up (but pMan is not
350
--- src/th.h
+++ src/th.h
@@ -40,25 +40,37 @@
40 ** (which may differ from len due to encoding and whatnot). On error
41 ** a negative value must be returned.
42 */
43 typedef int (*Th_output_f)( char const * zData, int len, void * pState );
44
45 /*
46 ** This structure defines the output state associated with a
47 ** Th_Vtab. It is intended that a given Vtab be able to swap out
48 ** output back-ends during its lifetime, e.g. to form a stack of
49 ** buffers.
50 */
51 struct Th_Vtab_Output {
52 Th_output_f write; /* output handler */
53 void (*dispose)( void * pState );
54 void * pState; /* final argument for xOut() and dispose()*/
55 char enabled; /* if 0, Th_output() does nothing. */
56 };
57 typedef struct Th_Vtab_Output Th_Vtab_Output;
58
59 /*
60 ** Shared Th_Vtab_Output instance used for copy-initialization.
61 */
62 extern const Th_Vtab_Output Th_Vtab_Output_FILE;
63
64 /*
65 ** Before creating an interpreter, the application must allocate and
66 ** populate an instance of the following structure. It must remain valid
67 ** for the lifetime of the interpreter.
68 */
69 struct Th_Vtab {
70 void *(*xRealloc)(void *, unsigned int); /* Re/deallocation routine. */
71 Th_Vtab_Output out; /* output implementation */
72 };
73 typedef struct Th_Vtab Th_Vtab;
74
75
76 /*
@@ -260,10 +272,15 @@
272 ** Th_output_f() implementation which sends its output to either
273 ** pState (which must be NULL or a (FILE*)) or stdout (if pState is
274 ** NULL).
275 */
276 int Th_output_f_FILE( char const * zData, int len, void * pState );
277 /*
278 ** Th_Vtab_Output::dispose impl for FILE handles. If pState is not
279 ** one of the standard streams then it is fclose()d.
280 */
281 void Th_output_dispose_FILE( void * pState );
282
283 typedef struct Th_Command_Reg Th_Command_Reg;
284 /*
285 ** A helper type for holding lists of function registration information.
286 ** For use with Th_register_commands().
@@ -339,11 +356,11 @@
356 ** Pushes a new blob onto pMan's stack. On success
357 ** returns TH_OK and assigns *pOut (if pOut is not NULL)
358 ** to the new blob (which is owned by pMan). On error
359 ** pOut is not modified and non-0 is returned.
360 */
361 int Th_ob_push( Th_Ob_Man * pMan, Th_Vtab_Output const * pWriter, Blob ** pOut );
362
363 /*
364 ** Pops the top-most output buffer off the stack and returns
365 ** it. Returns NULL if there is no current buffer. When the last
366 ** buffer is popped, pMan's internals are cleaned up (but pMan is not
367
+6 -5
--- src/th_main.c
+++ src/th_main.c
@@ -65,13 +65,14 @@
6565
*/;
6666
}
6767
}
6868
6969
static Th_Vtab vtab = { xRealloc, {
70
- NULL,
71
- NULL,
72
- 1
70
+ NULL /*write()*/,
71
+ NULL/*dispose()*/,
72
+ NULL/*pState*/,
73
+ 1/*enabled*/
7374
}
7475
};
7576
7677
/*
7778
** Generate a TH1 trace message if debugging is enabled.
@@ -2006,13 +2007,13 @@
20062007
{0, 0, 0}
20072008
};
20082009
if( g.interp==0 ){
20092010
int i;
20102011
if(g.cgiOutput){
2011
- vtab.out.f = Th_output_f_cgi_content;
2012
+ vtab.out.write = Th_output_f_cgi_content;
20122013
}else{
2013
- vtab.out.f = Th_output_f_FILE;
2014
+ vtab.out = Th_Vtab_Output_FILE;
20142015
vtab.out.pState = stdout;
20152016
}
20162017
vtab.out.enabled = enableOutput;
20172018
g.interp = Th_CreateInterp(&vtab);
20182019
th_register_language(g.interp); /* Basic scripting commands. */
20192020
20202021
ADDED test/th1-ob-1.th1
--- src/th_main.c
+++ src/th_main.c
@@ -65,13 +65,14 @@
65 */;
66 }
67 }
68
69 static Th_Vtab vtab = { xRealloc, {
70 NULL,
71 NULL,
72 1
 
73 }
74 };
75
76 /*
77 ** Generate a TH1 trace message if debugging is enabled.
@@ -2006,13 +2007,13 @@
2006 {0, 0, 0}
2007 };
2008 if( g.interp==0 ){
2009 int i;
2010 if(g.cgiOutput){
2011 vtab.out.f = Th_output_f_cgi_content;
2012 }else{
2013 vtab.out.f = Th_output_f_FILE;
2014 vtab.out.pState = stdout;
2015 }
2016 vtab.out.enabled = enableOutput;
2017 g.interp = Th_CreateInterp(&vtab);
2018 th_register_language(g.interp); /* Basic scripting commands. */
2019
2020 DDED test/th1-ob-1.th1
--- src/th_main.c
+++ src/th_main.c
@@ -65,13 +65,14 @@
65 */;
66 }
67 }
68
69 static Th_Vtab vtab = { xRealloc, {
70 NULL /*write()*/,
71 NULL/*dispose()*/,
72 NULL/*pState*/,
73 1/*enabled*/
74 }
75 };
76
77 /*
78 ** Generate a TH1 trace message if debugging is enabled.
@@ -2006,13 +2007,13 @@
2007 {0, 0, 0}
2008 };
2009 if( g.interp==0 ){
2010 int i;
2011 if(g.cgiOutput){
2012 vtab.out.write = Th_output_f_cgi_content;
2013 }else{
2014 vtab.out = Th_Vtab_Output_FILE;
2015 vtab.out.pState = stdout;
2016 }
2017 vtab.out.enabled = enableOutput;
2018 g.interp = Th_CreateInterp(&vtab);
2019 th_register_language(g.interp); /* Basic scripting commands. */
2020
2021 DDED test/th1-ob-1.th1
--- a/test/th1-ob-1.th1
+++ b/test/th1-ob-1.th1
@@ -0,0 +1,17 @@
1
+<th1>
2
+set i 0
3
+set max 6
4
+for {} {$i < $max} {incr i} {
5
+ ob start
6
+ puts "this is level " [ob level]
7
+ set buf($i) [ob get]
8
+}
9
+
10
+for {set i [expr $max-1]} {$i >= 0} {incr i -1} {
11
+ ob pop
12
+}
13
+for {set i [expr $max-1]} {$i >= 0} {incr i -1} {
14
+ puts buf($i) = $buf($i) "\n"
15
+}
16
+puts "buffering level = " [ob level] \n
17
+</th1>
--- a/test/th1-ob-1.th1
+++ b/test/th1-ob-1.th1
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/th1-ob-1.th1
+++ b/test/th1-ob-1.th1
@@ -0,0 +1,17 @@
1 <th1>
2 set i 0
3 set max 6
4 for {} {$i < $max} {incr i} {
5 ob start
6 puts "this is level " [ob level]
7 set buf($i) [ob get]
8 }
9
10 for {set i [expr $max-1]} {$i >= 0} {incr i -1} {
11 ob pop
12 }
13 for {set i [expr $max-1]} {$i >= 0} {incr i -1} {
14 puts buf($i) = $buf($i) "\n"
15 }
16 puts "buffering level = " [ob level] \n
17 </th1>

Keyboard Shortcuts

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