| | @@ -6,10 +6,20 @@ |
| 6 | 6 | |
| 7 | 7 | #include "th.h" |
| 8 | 8 | #include <string.h> |
| 9 | 9 | #include <assert.h> |
| 10 | 10 | #include <stdio.h> /* FILE class */ |
| 11 | +#ifdef TH_USE_OUTBUF |
| 12 | +#ifndef INTERFACE |
| 13 | +#include "blob.h" |
| 14 | +#endif |
| 15 | +#endif |
| 16 | + |
| 17 | +extern void *fossil_realloc(void *p, size_t n); |
| 18 | +static void * th_fossil_realloc(void *p, unsigned int n){ |
| 19 | + return fossil_realloc( p, n ); |
| 20 | +} |
| 11 | 21 | |
| 12 | 22 | typedef struct Th_Command Th_Command; |
| 13 | 23 | typedef struct Th_Frame Th_Frame; |
| 14 | 24 | typedef struct Th_Variable Th_Variable; |
| 15 | 25 | |
| | @@ -1377,20 +1387,26 @@ |
| 1377 | 1387 | |
| 1378 | 1388 | /* |
| 1379 | 1389 | ** Wrappers around the supplied malloc() and free() |
| 1380 | 1390 | */ |
| 1381 | 1391 | void *Th_Malloc(Th_Interp *pInterp, int nByte){ |
| 1382 | | - void *p = pInterp->pVtab->xMalloc(nByte); |
| 1392 | + void * p = pInterp->pVtab->xRealloc(NULL, nByte); |
| 1383 | 1393 | if( p ){ |
| 1384 | 1394 | memset(p, 0, nByte); |
| 1395 | + }else{ |
| 1396 | + assert( 0 == nByte ); |
| 1385 | 1397 | } |
| 1386 | 1398 | return p; |
| 1387 | 1399 | } |
| 1388 | 1400 | void Th_Free(Th_Interp *pInterp, void *z){ |
| 1389 | 1401 | if( z ){ |
| 1390 | | - pInterp->pVtab->xFree(z); |
| 1402 | + pInterp->pVtab->xRealloc(z, 0); |
| 1391 | 1403 | } |
| 1404 | +} |
| 1405 | +void *Th_Realloc(Th_Interp *pInterp, void *z, int nByte){ |
| 1406 | + void *p = pInterp->pVtab->xRealloc(z, nByte); |
| 1407 | + return p; |
| 1392 | 1408 | } |
| 1393 | 1409 | |
| 1394 | 1410 | |
| 1395 | 1411 | int Th_Vtab_output( Th_Vtab *vTab, char const * zData, int nData ){ |
| 1396 | 1412 | if(!vTab->out.f){ |
| | @@ -1707,11 +1723,11 @@ |
| 1707 | 1723 | */ |
| 1708 | 1724 | Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){ |
| 1709 | 1725 | Th_Interp *p; |
| 1710 | 1726 | |
| 1711 | 1727 | /* Allocate and initialise the interpreter and the global frame */ |
| 1712 | | - p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame)); |
| 1728 | + p = pVtab->xRealloc(NULL, sizeof(Th_Interp) + sizeof(Th_Frame)); |
| 1713 | 1729 | memset(p, 0, sizeof(Th_Interp)); |
| 1714 | 1730 | p->pVtab = pVtab; |
| 1715 | 1731 | p->paCmd = Th_HashNew(p); |
| 1716 | 1732 | thPushFrame(p, (Th_Frame *)&p[1]); |
| 1717 | 1733 | |
| | @@ -2383,11 +2399,11 @@ |
| 2383 | 2399 | } |
| 2384 | 2400 | |
| 2385 | 2401 | #ifndef LONGDOUBLE_TYPE |
| 2386 | 2402 | # define LONGDOUBLE_TYPE long double |
| 2387 | 2403 | #endif |
| 2388 | | -typedef char u8; |
| 2404 | +/*typedef char u8;*/ |
| 2389 | 2405 | |
| 2390 | 2406 | |
| 2391 | 2407 | /* |
| 2392 | 2408 | ** Return TRUE if z is a pure numeric string. Return FALSE if the |
| 2393 | 2409 | ** string contains any character which is not part of a number. If |
| | @@ -2686,11 +2702,10 @@ |
| 2686 | 2702 | return Th_SetResult(interp, zBuf, -1); |
| 2687 | 2703 | } |
| 2688 | 2704 | |
| 2689 | 2705 | |
| 2690 | 2706 | #ifdef TH_USE_SQLITE |
| 2691 | | -extern void *fossil_realloc(void *p, size_t n); |
| 2692 | 2707 | int Th_AddStmt(Th_Interp *interp, sqlite3_stmt * pStmt){ |
| 2693 | 2708 | int i, x; |
| 2694 | 2709 | sqlite3_stmt * s; |
| 2695 | 2710 | sqlite3_stmt ** list = interp->stmt.aStmt; |
| 2696 | 2711 | for( i = 0; i < interp->stmt.nStmt; ++i ){ |
| | @@ -2733,5 +2748,257 @@ |
| 2733 | 2748 | : interp->stmt.aStmt[stmtId-1]; |
| 2734 | 2749 | } |
| 2735 | 2750 | |
| 2736 | 2751 | #endif |
| 2737 | 2752 | /* end TH_USE_SQLITE */ |
| 2753 | + |
| 2754 | + |
| 2755 | +#ifdef TH_USE_OUTBUF |
| 2756 | +struct Th_Ob_Man { |
| 2757 | + Blob ** aBuf; |
| 2758 | + int nBuf; |
| 2759 | + int cursor; |
| 2760 | + Th_Interp * interp; |
| 2761 | + Th_Vtab ** aVtab; |
| 2762 | +}; |
| 2763 | + |
| 2764 | +typedef struct Th_Ob_Man Th_Ob_Man; |
| 2765 | +#define Th_Ob_Man_empty_m { NULL, 0, -1, NULL, NULL } |
| 2766 | +static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m; |
| 2767 | +static Th_Ob_Man Th_Ob_Man_instance = Th_Ob_Man_empty_m; |
| 2768 | + |
| 2769 | +static Blob * Th_ob_current( Th_Ob_Man * pMan ){ |
| 2770 | + return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0; |
| 2771 | +} |
| 2772 | + |
| 2773 | + |
| 2774 | +static int Th_output_ob( char const * zData, int len, void * pState ){ |
| 2775 | + Th_Ob_Man * pMan = (Th_Ob_Man*)pState; |
| 2776 | + Blob * b = Th_ob_current( pMan ); |
| 2777 | + assert( NULL != pMan ); |
| 2778 | + assert( b ); |
| 2779 | + blob_append( b, zData, len ); |
| 2780 | + return len; |
| 2781 | +} |
| 2782 | + |
| 2783 | +static Th_Vtab Th_Vtab_Ob = { th_fossil_realloc, |
| 2784 | + { |
| 2785 | + Th_output_ob, |
| 2786 | + NULL, |
| 2787 | + 1 |
| 2788 | + } |
| 2789 | +}; |
| 2790 | + |
| 2791 | +#if 0 |
| 2792 | +#define OB_MALLOC(I,N) malloc((N)) |
| 2793 | +#define OB_REALLOC(I,P,N) realloc((P),(N)) |
| 2794 | +#define OB_FREE(I,P) free((P)) |
| 2795 | +#else |
| 2796 | +#define OB_MALLOC(I,N) Th_Malloc((I),(N)) |
| 2797 | +#define OB_REALLOC(I,P,N) Th_Realloc((I),(P),(N)) |
| 2798 | +#define OB_FREE(I,P) Th_Free((I),(P)) |
| 2799 | +#endif |
| 2800 | +int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut ){ |
| 2801 | + Blob * pBlob; |
| 2802 | + int x, i; |
| 2803 | + assert( NULL != pMan->interp ); |
| 2804 | + pBlob = (Blob *)OB_MALLOC(pMan->interp, sizeof(Blob)); |
| 2805 | + *pBlob = empty_blob; |
| 2806 | + |
| 2807 | + if( pMan->cursor <= pMan->nBuf ){ |
| 2808 | + /* expand if needed */ |
| 2809 | + x = (pMan->cursor>0 ? pMan->cursor : 1) * 2; |
| 2810 | + /*fprintf(stderr,"OB EXPAND x=%d\n",x);*/ |
| 2811 | + void * re = OB_REALLOC( pMan->interp, pMan->aBuf, x * sizeof(Blob*) ); |
| 2812 | + if(NULL==re){ |
| 2813 | + goto error; |
| 2814 | + } |
| 2815 | + pMan->aBuf = (Blob **)re; |
| 2816 | + re = OB_REALLOC( pMan->interp, pMan->aVtab, x * sizeof(Th_Vtab*) ); |
| 2817 | + if(NULL==re){ |
| 2818 | + goto error; |
| 2819 | + } |
| 2820 | + pMan->aVtab = (Th_Vtab**)re; |
| 2821 | + for( i = pMan->nBuf; i < x; ++i ){ |
| 2822 | + pMan->aVtab[i] = NULL; |
| 2823 | + pMan->aBuf[i] = NULL; |
| 2824 | + } |
| 2825 | + pMan->nBuf = x; |
| 2826 | + } |
| 2827 | + assert( pMan->nBuf > pMan->cursor ); |
| 2828 | + assert( pMan->cursor >= -1 ); |
| 2829 | + ++pMan->cursor; |
| 2830 | + pMan->aBuf[pMan->cursor] = pBlob; |
| 2831 | + pMan->aVtab[pMan->cursor] = pMan->interp->pVtab; |
| 2832 | + pMan->interp->pVtab = &Th_Vtab_Ob; |
| 2833 | + Th_Vtab_Ob.out.pState = pMan; |
| 2834 | + if( pOut ){ |
| 2835 | + *pOut = pBlob; |
| 2836 | + } |
| 2837 | + /*fprintf(stderr,"OB PUSH: %p\n", pBlob);*/ |
| 2838 | + return TH_OK; |
| 2839 | + error: |
| 2840 | + if( pBlob ){ |
| 2841 | + OB_FREE( pMan->interp, pBlob ); |
| 2842 | + } |
| 2843 | + return TH_ERROR; |
| 2844 | +} |
| 2845 | + |
| 2846 | +Blob * Th_ob_pop( Th_Ob_Man * pMan ){ |
| 2847 | + if( pMan->cursor < 0 ){ |
| 2848 | + return NULL; |
| 2849 | + }else{ |
| 2850 | + Blob * rc; |
| 2851 | + assert( pMan->nBuf > pMan->cursor ); |
| 2852 | + rc = pMan->aBuf[pMan->cursor]; |
| 2853 | + pMan->aBuf[pMan->cursor] = NULL; |
| 2854 | + pMan->interp->pVtab = pMan->aVtab[pMan->cursor]; |
| 2855 | + pMan->aVtab[pMan->cursor] = NULL; |
| 2856 | + if(-1 == --pMan->cursor){ |
| 2857 | + OB_FREE( pMan->interp, pMan->aBuf ); |
| 2858 | + OB_FREE( pMan->interp, pMan->aVtab ); |
| 2859 | + *pMan = Th_Ob_Man_empty; |
| 2860 | + } |
| 2861 | + /*fprintf(stderr,"OB pop: %p level=%d\n", rc, pMan->cursor-1);*/ |
| 2862 | + return rc; |
| 2863 | + } |
| 2864 | +} |
| 2865 | + |
| 2866 | +static int ob_clean_command( Th_Interp *interp, void *ctx, |
| 2867 | + int argc, const char **argv, int *argl |
| 2868 | +){ |
| 2869 | + Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2870 | + Blob * b; |
| 2871 | + assert( pMan && (interp == pMan->interp) ); |
| 2872 | + b = pMan ? Th_ob_current(pMan) : NULL; |
| 2873 | + if(!b){ |
| 2874 | + Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2875 | + return TH_ERROR; |
| 2876 | + }else{ |
| 2877 | + blob_reset(b); |
| 2878 | + } |
| 2879 | + return TH_OK; |
| 2880 | +} |
| 2881 | + |
| 2882 | +static int ob_end_command( Th_Interp *interp, void *ctx, |
| 2883 | + int argc, const char **argv, int *argl ){ |
| 2884 | + Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2885 | + Blob * b; |
| 2886 | + assert( pMan && (interp == pMan->interp) ); |
| 2887 | + b = Th_ob_pop(pMan); |
| 2888 | + if(!b){ |
| 2889 | + Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2890 | + return TH_ERROR; |
| 2891 | + }else{ |
| 2892 | + blob_reset(b); |
| 2893 | + OB_FREE( interp, b ); |
| 2894 | + } |
| 2895 | + return TH_OK; |
| 2896 | +} |
| 2897 | + |
| 2898 | +static int ob_flush_command( Th_Interp *interp, void *ctx, |
| 2899 | + int argc, const char **argv, int *argl ){ |
| 2900 | + Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2901 | + Blob * b = NULL; |
| 2902 | + Th_Vtab * oldVtab; |
| 2903 | + assert( pMan && (interp == pMan->interp) ); |
| 2904 | + b = Th_ob_current(pMan); |
| 2905 | + if( NULL == b ){ |
| 2906 | + Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2907 | + return TH_ERROR; |
| 2908 | + } |
| 2909 | + oldVtab = interp->pVtab; |
| 2910 | + interp->pVtab = pMan->aVtab[pMan->cursor]; |
| 2911 | + Th_output( interp, blob_str(b), b->nUsed ); |
| 2912 | + interp->pVtab = oldVtab; |
| 2913 | + blob_reset(b); |
| 2914 | + return TH_OK; |
| 2915 | +} |
| 2916 | + |
| 2917 | +static int ob_get_command( Th_Interp *interp, void *ctx, |
| 2918 | + int argc, const char **argv, int *argl){ |
| 2919 | + Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2920 | + Blob * b = NULL; |
| 2921 | + assert( pMan && (interp == pMan->interp) ); |
| 2922 | + b = Th_ob_current(pMan); |
| 2923 | + if( NULL == b ){ |
| 2924 | + Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2925 | + return TH_ERROR; |
| 2926 | + }else{ |
| 2927 | + int argPos = 2; |
| 2928 | + char const * sub; |
| 2929 | + int subL; |
| 2930 | + int rc = TH_OK; |
| 2931 | + Th_SetResult( interp, blob_str(b), b->nUsed ); |
| 2932 | + if(argc>=argPos){ |
| 2933 | + sub = argv[argPos]; |
| 2934 | + subL = argl[argPos]; |
| 2935 | + /* "ob get clean" */ |
| 2936 | + if(!rc && th_strlen(sub)==5 && 0==memcmp("clean", sub, subL)){ |
| 2937 | + rc |= ob_clean_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2938 | + }/* "ob get end" */ |
| 2939 | + else if(!rc && th_strlen(sub)==3 && 0==memcmp("end", sub, subL)){ |
| 2940 | + rc |= ob_end_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2941 | + } |
| 2942 | + } |
| 2943 | + return rc; |
| 2944 | + } |
| 2945 | +} |
| 2946 | + |
| 2947 | +static int ob_start_command( Th_Interp *interp, void *ctx, |
| 2948 | + int argc, const char **argv, int *argl |
| 2949 | +){ |
| 2950 | + Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2951 | + Blob * b = NULL; |
| 2952 | + int rc; |
| 2953 | + assert( pMan && (interp == pMan->interp) ); |
| 2954 | + rc = Th_ob_push(pMan, &b); |
| 2955 | + if( TH_OK != rc ){ |
| 2956 | + assert( NULL == b ); |
| 2957 | + return rc; |
| 2958 | + } |
| 2959 | + assert( NULL != b ); |
| 2960 | + /*fprintf(stderr,"OB STARTED: %p level=%d\n", b, pMan->cursor);*/ |
| 2961 | + Th_SetResultInt( interp, pMan->cursor ); |
| 2962 | + return TH_OK; |
| 2963 | +} |
| 2964 | + |
| 2965 | +static int ob_cmd( |
| 2966 | + Th_Interp *interp, |
| 2967 | + void *ignored, |
| 2968 | + int argc, |
| 2969 | + const char **argv, |
| 2970 | + int *argl |
| 2971 | +){ |
| 2972 | + static Th_Ob_Man * pMan = &Th_Ob_Man_instance; |
| 2973 | + Th_SubCommand aSub[] = { |
| 2974 | + { "clean", ob_clean_command }, |
| 2975 | + { "end", ob_end_command }, |
| 2976 | + { "flush", ob_flush_command }, |
| 2977 | + { "get", ob_get_command }, |
| 2978 | + { "start", ob_start_command }, |
| 2979 | + { 0, 0 } |
| 2980 | + }; |
| 2981 | + if(NULL == pMan->interp){ |
| 2982 | + pMan->interp = interp; |
| 2983 | + /* |
| 2984 | + FIXME: add rudamentary at-finalization GC to Th_Interp and clean |
| 2985 | + this up there. |
| 2986 | + */ |
| 2987 | + } |
| 2988 | + return Th_CallSubCommand(interp, pMan, argc, argv, argl, aSub); |
| 2989 | + |
| 2990 | +} |
| 2991 | + |
| 2992 | +int th_register_ob(Th_Interp * interp){ |
| 2993 | + static Th_Command_Reg aCommand[] = { |
| 2994 | + {"ob", ob_cmd, 0}, |
| 2995 | + {0,0,0} |
| 2996 | + }; |
| 2997 | + return Th_register_commands( interp, aCommand ); |
| 2998 | +} |
| 2999 | +#undef OB_MALLOC |
| 3000 | +#undef OB_REALLOC |
| 3001 | +#undef OB_FREE |
| 3002 | +#endif |
| 3003 | +/* end TH_USE_OUTBUF */ |
| 3004 | + |
| 2738 | 3005 | |