Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Started adding infrastructure to allow us to expand the ob handler support to include more types. Added another th1 test script. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | th1-query-api |
Files: | files | file ages | folders |
SHA1: |
726f998b5f6565800a9125bd788bbc70 |
User & Date: | stephan 2012-07-15 17:33:55.065 |
Context
2012-07-16
| ||
14:36 | Minor doc correction. ... (check-in: 42957281 user: stephan tags: th1-query-api) | |
2012-07-15
| ||
17:33 | Started adding infrastructure to allow us to expand the ob handler support to include more types. Added another th1 test script. ... (check-in: 726f998b user: stephan tags: th1-query-api) | |
15:28 | Added query reset, refactored bind commands to accept their indexes in the same way as the col commands do (and expanded the remaining col commands which did not do so). ... (check-in: f2ee33d4 user: stephan tags: th1-query-api) | |
Changes
Changes to src/th.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #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 ); } static int Th_output_f_ob( char const * zData, int len, void * pState ); typedef struct Th_Command Th_Command; typedef struct Th_Frame Th_Frame; typedef struct Th_Variable Th_Variable; /* ** Holds client-provided "garbage collected" data for ** a Th_Interp instance. */ struct Th_GcEntry { void * pData; /* arbitrary data */ | > > > > > > > > | 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 | #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 ); } static int Th_output_f_ob( char const * zData, int len, void * pState ); static void Th_output_dispose_ob( void * pState ); typedef struct Th_Command Th_Command; typedef struct Th_Frame Th_Frame; typedef struct Th_Variable Th_Variable; const Th_Vtab_Output Th_Vtab_Output_FILE = { Th_output_f_FILE /* write() */, Th_output_dispose_FILE /* dispose() */, NULL /*pState*/, 1/*enabled*/ }; /* ** Holds client-provided "garbage collected" data for ** a Th_Interp instance. */ struct Th_GcEntry { void * pData; /* arbitrary data */ |
︙ | ︙ | |||
1440 1441 1442 1443 1444 1445 1446 | void *Th_Realloc(Th_Interp *pInterp, void *z, int nByte){ void *p = pInterp->pVtab->xRealloc(z, nByte); return p; } int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){ | | | > > > > > > > > > > > | 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 | void *Th_Realloc(Th_Interp *pInterp, void *z, int nByte){ void *p = pInterp->pVtab->xRealloc(z, nByte); return p; } int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){ if(!vTab->out.write){ return -1; }else if(!vTab->out.enabled){ return 0; }else{ return vTab->out.write( 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; } void Th_output_dispose_FILE( void * pState ){ FILE * f = pState ? (FILE*)pState : NULL; if(f && (f != stdout) && (f != stderr) && (f != stdin)){ fflush(f); fclose(f); } } /* ** Install a new th1 command. ** ** If a command of the same name already exists, it is deleted automatically. */ int Th_CreateCommand( |
︙ | ︙ | |||
2770 2771 2772 2773 2774 2775 2776 2777 | #define Th_Ob_Man_empty_m { \ NULL/*aBuf*/, \ 0/*nBuf*/, \ -1/*cursor*/, \ NULL/*interp*/, \ NULL/*aOutput*/ \ } #define Th_Vtab_Output_empty_m { \ | > > > > | > | | > < | | | | < > > | | > > > | | < | > > > > > | 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 | #define Th_Ob_Man_empty_m { \ NULL/*aBuf*/, \ 0/*nBuf*/, \ -1/*cursor*/, \ NULL/*interp*/, \ NULL/*aOutput*/ \ } /* ** Vtab impl for the ob buffering layer. */ #define Th_Vtab_Output_empty_m { \ NULL /* write() */, \ NULL /* dispose() */, \ NULL /*pState*/,\ 1/*enabled*/\ } #define Th_Vtab_Output_ob_m { \ Th_output_f_ob /*write()*/, \ Th_output_dispose_ob /* dispose() */, \ NULL /*pState*/,\ 1/*enabled*/\ } static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m; static Th_Vtab_Output Th_Vtab_Output_ob = Th_Vtab_Output_ob_m; static Th_Vtab_Output Th_Vtab_Output_empty = Th_Vtab_Output_empty_m; #define Th_Ob_Man_KEY "Th_Ob_Man" Th_Ob_Man * Th_ob_manager(Th_Interp *interp){ return (Th_Ob_Man*) Th_Data_Get(interp, Th_Ob_Man_KEY ); } 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. */ int Th_output_f_ob( char const * zData, int len, void * pState ){ Th_Ob_Man * pMan = (Th_Ob_Man*)pState; Blob * b = Th_ob_current( pMan ); assert( NULL != pMan ); assert( b ); blob_append( b, zData, len ); return len; } static void Th_output_dispose_ob( void * pState ){ /* possible todo: move the cleanup logic from Th_ob_pop() to here? */ /*printf("disposing() ob vtab.\n"); */ #if 0 Th_Ob_Man * pMan = (Th_Ob_Man*)pState; Blob * b = Th_ob_current( pMan ); assert( NULL != pMan ); assert( b ); #endif } int Th_ob_push( Th_Ob_Man * pMan, Th_Vtab_Output const * pWriter, Blob ** pOut ){ Blob * pBlob; int x, i; if( NULL == pWriter ){ pWriter = &Th_Vtab_Output_ob; } assert( NULL != pMan->interp ); pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob)); *pBlob = empty_blob; if( pMan->cursor >= pMan->nBuf-2 ){ /* expand if needed */ x = pMan->nBuf + 5; |
︙ | ︙ | |||
2853 2854 2855 2856 2857 2858 2859 | pMan->nBuf = x; } assert( pMan->nBuf > pMan->cursor ); assert( pMan->cursor >= -1 ); ++pMan->cursor; pMan->aBuf[pMan->cursor] = pBlob; pMan->aOutput[pMan->cursor] = pMan->interp->pVtab->out; | | > > > > > | | 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 | pMan->nBuf = x; } assert( pMan->nBuf > pMan->cursor ); assert( pMan->cursor >= -1 ); ++pMan->cursor; pMan->aBuf[pMan->cursor] = pBlob; pMan->aOutput[pMan->cursor] = pMan->interp->pVtab->out; pMan->interp->pVtab->out = *pWriter; pMan->interp->pVtab->out.pState = pMan; if( pOut ){ *pOut = pBlob; } /*printf( "push: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/ return TH_OK; 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; Th_Vtab_Output * theOut; /*printf( "pop: pMan->nBuf=%d, pMan->cursor=%d\n", pMan->nBuf, pMan->cursor);*/ assert( pMan->nBuf > pMan->cursor ); rc = pMan->aBuf[pMan->cursor]; pMan->aBuf[pMan->cursor] = NULL; theOut = &pMan->aOutput[pMan->cursor]; if( theOut->dispose ){ theOut->dispose( theOut->pState ); } pMan->interp->pVtab->out = *theOut; pMan->aOutput[pMan->cursor] = Th_Vtab_Output_empty; if(-1 == --pMan->cursor){ Th_Interp * interp = pMan->interp; Th_Free( pMan->interp, pMan->aBuf ); Th_Free( pMan->interp, pMan->aOutput ); *pMan = Th_Ob_Man_empty; pMan->interp = interp; |
︙ | ︙ | |||
3069 3070 3071 3072 3073 3074 3075 | Th_SetResultInt( interp, 1 + pMan->cursor ); return TH_OK; } /* ** TH Syntax: ** | | > > > > > | | 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 | Th_SetResultInt( interp, 1 + pMan->cursor ); return TH_OK; } /* ** TH Syntax: ** ** ob start|push ** ** Pushes a new level of buffering onto the buffer stack. ** Returns the new buffering level (1-based). ** ** TODO: take an optional final argument naming the output handler. ** e.g. "stdout" or "cgi" or "default" ** */ static int ob_start_command( Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl ){ Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; Blob * b = NULL; int rc; Th_Vtab_Output const * pWriter = &Th_Vtab_Output_ob; assert( pMan && (interp == pMan->interp) ); rc = Th_ob_push(pMan, NULL, &b); if( TH_OK != rc ){ assert( NULL == b ); return rc; } assert( NULL != b ); Th_SetResultInt( interp, 1 + pMan->cursor ); return TH_OK; |
︙ | ︙ |
Changes to src/th.h.
︙ | ︙ | |||
38 39 40 41 42 43 44 45 | ** 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 ); struct Th_Vtab_Output { | > > > > > > | > | > > > > > | | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | ** 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 ); /* ** This structure defines the output state associated with a ** Th_Vtab. It is intended that a given Vtab be able to swap out ** output back-ends during its lifetime, e.g. to form a stack of ** buffers. */ struct Th_Vtab_Output { Th_output_f write; /* output handler */ void (*dispose)( void * pState ); void * pState; /* final argument for xOut() and dispose()*/ char enabled; /* if 0, Th_output() does nothing. */ }; typedef struct Th_Vtab_Output Th_Vtab_Output; /* ** Shared Th_Vtab_Output instance used for copy-initialization. */ extern const Th_Vtab_Output Th_Vtab_Output_FILE; /* ** 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 *(*xRealloc)(void *, unsigned int); /* Re/deallocation routine. */ Th_Vtab_Output out; /* output implementation */ }; typedef struct Th_Vtab Th_Vtab; /* ** Opaque handle for interpeter. */ |
︙ | ︙ | |||
258 259 260 261 262 263 264 265 266 267 268 269 270 271 | /* ** 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 ); typedef struct Th_Command_Reg Th_Command_Reg; /* ** A helper type for holding lists of function registration information. ** For use with Th_register_commands(). */ struct Th_Command_Reg { | > > > > > | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | /* ** 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 ); /* ** Th_Vtab_Output::dispose impl for FILE handles. If pState is not ** one of the standard streams then it is fclose()d. */ void Th_output_dispose_FILE( void * pState ); typedef struct Th_Command_Reg Th_Command_Reg; /* ** A helper type for holding lists of function registration information. ** For use with Th_register_commands(). */ struct Th_Command_Reg { |
︙ | ︙ | |||
337 338 339 340 341 342 343 | /* ** 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. */ | | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | /* ** 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, Th_Vtab_Output const * pWriter, 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 (but pMan is not ** freed). ** |
︙ | ︙ |
Changes to src/th_main.c.
︙ | ︙ | |||
63 64 65 66 67 68 69 | /* FIXME: try to find some reasonable nOutstandingMalloc heuristics, e.g. if !p then ++, if !n then --, etc. */; } } static Th_Vtab vtab = { xRealloc, { | | > | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | /* FIXME: try to find some reasonable nOutstandingMalloc heuristics, e.g. if !p then ++, if !n then --, etc. */; } } static Th_Vtab vtab = { xRealloc, { NULL /*write()*/, NULL/*dispose()*/, NULL/*pState*/, 1/*enabled*/ } }; /* ** Generate a TH1 trace message if debugging is enabled. */ void Th_Trace(const char *zFormat, ...){ |
︙ | ︙ | |||
2004 2005 2006 2007 2008 2009 2010 | {"wiki", wikiCmd, 0}, {0, 0, 0} }; if( g.interp==0 ){ int i; if(g.cgiOutput){ | | | | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 | {"wiki", wikiCmd, 0}, {0, 0, 0} }; if( g.interp==0 ){ int i; if(g.cgiOutput){ vtab.out.write = Th_output_f_cgi_content; }else{ vtab.out = Th_Vtab_Output_FILE; vtab.out.pState = stdout; } vtab.out.enabled = enableOutput; 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) ){ |
︙ | ︙ |
Added test/th1-ob-1.th1.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <th1> set i 0 set max 6 for {} {$i < $max} {incr i} { ob start puts "this is level " [ob level] set buf($i) [ob get] } for {set i [expr $max-1]} {$i >= 0} {incr i -1} { ob pop } for {set i [expr $max-1]} {$i >= 0} {incr i -1} { puts buf($i) = $buf($i) "\n" } puts "buffering level = " [ob level] \n </th1> |