Fossil SCM
Added push/pop as aliases for start/end in the ob API. Fixed a horrible size calculation bug which triggered an assert() for ob nesting levels deeper than 2.
Commit
9b3a11e16095e2ce9ab1db03d0ada3a02f5046a1
Parent
dc3c8ac3deb06a8…
1 file changed
+35
-11
M
src/th.c
+35
-11
| --- src/th.c | ||
| +++ src/th.c | ||
| @@ -2798,13 +2798,17 @@ | ||
| 2798 | 2798 | int x, i; |
| 2799 | 2799 | assert( NULL != pMan->interp ); |
| 2800 | 2800 | pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob)); |
| 2801 | 2801 | *pBlob = empty_blob; |
| 2802 | 2802 | |
| 2803 | - if( pMan->cursor <= pMan->nBuf ){ | |
| 2803 | + if( pMan->cursor >= pMan->nBuf-2 ){ | |
| 2804 | 2804 | /* expand if needed */ |
| 2805 | - x = (pMan->cursor>0 ? pMan->cursor : 1) * 2; | |
| 2805 | + x = pMan->nBuf + 5; | |
| 2806 | + if( pMan->cursor >= x ) { | |
| 2807 | + assert( 0 && "This really should not happen." ); | |
| 2808 | + x = pMan->cursor + 5; | |
| 2809 | + } | |
| 2806 | 2810 | /*fprintf(stderr,"OB EXPAND x=%d\n",x);*/ |
| 2807 | 2811 | void * re = Th_Realloc( pMan->interp, pMan->aBuf, x * sizeof(Blob*) ); |
| 2808 | 2812 | if(NULL==re){ |
| 2809 | 2813 | goto error; |
| 2810 | 2814 | } |
| @@ -2877,12 +2881,13 @@ | ||
| 2877 | 2881 | if(!b){ |
| 2878 | 2882 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2879 | 2883 | return TH_ERROR; |
| 2880 | 2884 | }else{ |
| 2881 | 2885 | blob_reset(b); |
| 2886 | + Th_SetResultInt( interp, 0 ); | |
| 2887 | + return TH_OK; | |
| 2882 | 2888 | } |
| 2883 | - return TH_OK; | |
| 2884 | 2889 | } |
| 2885 | 2890 | |
| 2886 | 2891 | /* |
| 2887 | 2892 | ** TH Syntax: |
| 2888 | 2893 | ** |
| @@ -2901,31 +2906,33 @@ | ||
| 2901 | 2906 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2902 | 2907 | return TH_ERROR; |
| 2903 | 2908 | }else{ |
| 2904 | 2909 | blob_reset(b); |
| 2905 | 2910 | Th_Free( interp, b ); |
| 2911 | + Th_SetResultInt( interp, 0 ); | |
| 2912 | + return TH_OK; | |
| 2906 | 2913 | } |
| 2907 | - return TH_OK; | |
| 2908 | 2914 | } |
| 2909 | 2915 | |
| 2910 | 2916 | /* |
| 2911 | 2917 | ** TH Syntax: |
| 2912 | 2918 | ** |
| 2913 | -** ob flush | |
| 2914 | -** | |
| 2915 | -** UNTESTED! Maybe not needed. | |
| 2919 | +** ob flush ?pop|end? | |
| 2916 | 2920 | ** |
| 2917 | 2921 | ** Briefly reverts the output layer to the next-lower |
| 2918 | 2922 | ** level, flushes the current buffer to that output layer, |
| 2919 | 2923 | ** and clears out the current buffer. Does not change the |
| 2920 | -** buffering level. | |
| 2924 | +** buffering level unless "end" is specified, in which case | |
| 2925 | +** it behaves as if "ob end" had been called (after flushing | |
| 2926 | +** the buffer). | |
| 2921 | 2927 | */ |
| 2922 | 2928 | static int ob_flush_command( Th_Interp *interp, void *ctx, |
| 2923 | 2929 | int argc, const char **argv, int *argl ){ |
| 2924 | 2930 | Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2925 | 2931 | Blob * b = NULL; |
| 2926 | 2932 | Th_Vtab * oldVtab; |
| 2933 | + int rc = TH_OK; | |
| 2927 | 2934 | assert( pMan && (interp == pMan->interp) ); |
| 2928 | 2935 | b = Th_ob_current(pMan); |
| 2929 | 2936 | if( NULL == b ){ |
| 2930 | 2937 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2931 | 2938 | return TH_ERROR; |
| @@ -2933,17 +2940,30 @@ | ||
| 2933 | 2940 | oldVtab = interp->pVtab; |
| 2934 | 2941 | interp->pVtab = pMan->aVtab[pMan->cursor]; |
| 2935 | 2942 | Th_output( interp, blob_str(b), b->nUsed ); |
| 2936 | 2943 | interp->pVtab = oldVtab; |
| 2937 | 2944 | blob_reset(b); |
| 2938 | - return TH_OK; | |
| 2945 | + | |
| 2946 | + if(!rc && argc>2){ | |
| 2947 | + int argPos = 2; | |
| 2948 | + char const * sub = argv[argPos]; | |
| 2949 | + int subL = argl[argPos]; | |
| 2950 | + /* "flush end" */ | |
| 2951 | + if(th_strlen(sub)==3 && | |
| 2952 | + ((0==memcmp("end", sub, subL) | |
| 2953 | + || (0==memcmp("pop", sub, subL))))){ | |
| 2954 | + rc |= ob_end_command(interp, ctx, argc-1, argv+1, argl+1); | |
| 2955 | + } | |
| 2956 | + } | |
| 2957 | + Th_SetResultInt( interp, 0 ); | |
| 2958 | + return rc; | |
| 2939 | 2959 | } |
| 2940 | 2960 | |
| 2941 | 2961 | /* |
| 2942 | 2962 | ** TH Syntax: |
| 2943 | 2963 | ** |
| 2944 | -** ob get ?clean|end? | |
| 2964 | +** ob get ?clean|end|pop? | |
| 2945 | 2965 | ** |
| 2946 | 2966 | ** Fetches the contents of the current buffer level. If either |
| 2947 | 2967 | ** 'clean' or 'end' are specified then the effect is as if "ob clean" |
| 2948 | 2968 | ** or "ob end", respectively, are called after fetching the |
| 2949 | 2969 | ** value. Calling "ob get end" is functionality equivalent to "ob get" |
| @@ -2969,11 +2989,13 @@ | ||
| 2969 | 2989 | subL = argl[argPos]; |
| 2970 | 2990 | /* "ob get clean" */ |
| 2971 | 2991 | if(!rc && th_strlen(sub)==5 && 0==memcmp("clean", sub, subL)){ |
| 2972 | 2992 | rc |= ob_clean_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2973 | 2993 | }/* "ob get end" */ |
| 2974 | - else if(!rc && th_strlen(sub)==3 && 0==memcmp("end", sub, subL)){ | |
| 2994 | + else if(!rc && th_strlen(sub)==3 && | |
| 2995 | + ((0==memcmp("end", sub, subL)) | |
| 2996 | + || (0==memcmp("pop", sub, subL)))){ | |
| 2975 | 2997 | rc |= ob_end_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2976 | 2998 | } |
| 2977 | 2999 | } |
| 2978 | 3000 | return rc; |
| 2979 | 3001 | } |
| @@ -3041,10 +3063,12 @@ | ||
| 3041 | 3063 | { "clean", ob_clean_command }, |
| 3042 | 3064 | { "end", ob_end_command }, |
| 3043 | 3065 | { "flush", ob_flush_command }, |
| 3044 | 3066 | { "get", ob_get_command }, |
| 3045 | 3067 | { "level", ob_level_command }, |
| 3068 | + { "pop", ob_end_command }, | |
| 3069 | + { "push", ob_start_command }, | |
| 3046 | 3070 | { "start", ob_start_command }, |
| 3047 | 3071 | { 0, 0 } |
| 3048 | 3072 | }; |
| 3049 | 3073 | if(NULL == pMan->interp){ |
| 3050 | 3074 | pMan->interp = interp; |
| 3051 | 3075 |
| --- src/th.c | |
| +++ src/th.c | |
| @@ -2798,13 +2798,17 @@ | |
| 2798 | int x, i; |
| 2799 | assert( NULL != pMan->interp ); |
| 2800 | pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob)); |
| 2801 | *pBlob = empty_blob; |
| 2802 | |
| 2803 | if( pMan->cursor <= pMan->nBuf ){ |
| 2804 | /* expand if needed */ |
| 2805 | x = (pMan->cursor>0 ? pMan->cursor : 1) * 2; |
| 2806 | /*fprintf(stderr,"OB EXPAND x=%d\n",x);*/ |
| 2807 | void * re = Th_Realloc( pMan->interp, pMan->aBuf, x * sizeof(Blob*) ); |
| 2808 | if(NULL==re){ |
| 2809 | goto error; |
| 2810 | } |
| @@ -2877,12 +2881,13 @@ | |
| 2877 | if(!b){ |
| 2878 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2879 | return TH_ERROR; |
| 2880 | }else{ |
| 2881 | blob_reset(b); |
| 2882 | } |
| 2883 | return TH_OK; |
| 2884 | } |
| 2885 | |
| 2886 | /* |
| 2887 | ** TH Syntax: |
| 2888 | ** |
| @@ -2901,31 +2906,33 @@ | |
| 2901 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2902 | return TH_ERROR; |
| 2903 | }else{ |
| 2904 | blob_reset(b); |
| 2905 | Th_Free( interp, b ); |
| 2906 | } |
| 2907 | return TH_OK; |
| 2908 | } |
| 2909 | |
| 2910 | /* |
| 2911 | ** TH Syntax: |
| 2912 | ** |
| 2913 | ** ob flush |
| 2914 | ** |
| 2915 | ** UNTESTED! Maybe not needed. |
| 2916 | ** |
| 2917 | ** Briefly reverts the output layer to the next-lower |
| 2918 | ** level, flushes the current buffer to that output layer, |
| 2919 | ** and clears out the current buffer. Does not change the |
| 2920 | ** buffering level. |
| 2921 | */ |
| 2922 | static int ob_flush_command( Th_Interp *interp, void *ctx, |
| 2923 | int argc, const char **argv, int *argl ){ |
| 2924 | Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2925 | Blob * b = NULL; |
| 2926 | Th_Vtab * oldVtab; |
| 2927 | assert( pMan && (interp == pMan->interp) ); |
| 2928 | b = Th_ob_current(pMan); |
| 2929 | if( NULL == b ){ |
| 2930 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2931 | return TH_ERROR; |
| @@ -2933,17 +2940,30 @@ | |
| 2933 | oldVtab = interp->pVtab; |
| 2934 | interp->pVtab = pMan->aVtab[pMan->cursor]; |
| 2935 | Th_output( interp, blob_str(b), b->nUsed ); |
| 2936 | interp->pVtab = oldVtab; |
| 2937 | blob_reset(b); |
| 2938 | return TH_OK; |
| 2939 | } |
| 2940 | |
| 2941 | /* |
| 2942 | ** TH Syntax: |
| 2943 | ** |
| 2944 | ** ob get ?clean|end? |
| 2945 | ** |
| 2946 | ** Fetches the contents of the current buffer level. If either |
| 2947 | ** 'clean' or 'end' are specified then the effect is as if "ob clean" |
| 2948 | ** or "ob end", respectively, are called after fetching the |
| 2949 | ** value. Calling "ob get end" is functionality equivalent to "ob get" |
| @@ -2969,11 +2989,13 @@ | |
| 2969 | subL = argl[argPos]; |
| 2970 | /* "ob get clean" */ |
| 2971 | if(!rc && th_strlen(sub)==5 && 0==memcmp("clean", sub, subL)){ |
| 2972 | rc |= ob_clean_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2973 | }/* "ob get end" */ |
| 2974 | else if(!rc && th_strlen(sub)==3 && 0==memcmp("end", sub, subL)){ |
| 2975 | rc |= ob_end_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2976 | } |
| 2977 | } |
| 2978 | return rc; |
| 2979 | } |
| @@ -3041,10 +3063,12 @@ | |
| 3041 | { "clean", ob_clean_command }, |
| 3042 | { "end", ob_end_command }, |
| 3043 | { "flush", ob_flush_command }, |
| 3044 | { "get", ob_get_command }, |
| 3045 | { "level", ob_level_command }, |
| 3046 | { "start", ob_start_command }, |
| 3047 | { 0, 0 } |
| 3048 | }; |
| 3049 | if(NULL == pMan->interp){ |
| 3050 | pMan->interp = interp; |
| 3051 |
| --- src/th.c | |
| +++ src/th.c | |
| @@ -2798,13 +2798,17 @@ | |
| 2798 | int x, i; |
| 2799 | assert( NULL != pMan->interp ); |
| 2800 | pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob)); |
| 2801 | *pBlob = empty_blob; |
| 2802 | |
| 2803 | if( pMan->cursor >= pMan->nBuf-2 ){ |
| 2804 | /* expand if needed */ |
| 2805 | x = pMan->nBuf + 5; |
| 2806 | if( pMan->cursor >= x ) { |
| 2807 | assert( 0 && "This really should not happen." ); |
| 2808 | x = pMan->cursor + 5; |
| 2809 | } |
| 2810 | /*fprintf(stderr,"OB EXPAND x=%d\n",x);*/ |
| 2811 | void * re = Th_Realloc( pMan->interp, pMan->aBuf, x * sizeof(Blob*) ); |
| 2812 | if(NULL==re){ |
| 2813 | goto error; |
| 2814 | } |
| @@ -2877,12 +2881,13 @@ | |
| 2881 | if(!b){ |
| 2882 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2883 | return TH_ERROR; |
| 2884 | }else{ |
| 2885 | blob_reset(b); |
| 2886 | Th_SetResultInt( interp, 0 ); |
| 2887 | return TH_OK; |
| 2888 | } |
| 2889 | } |
| 2890 | |
| 2891 | /* |
| 2892 | ** TH Syntax: |
| 2893 | ** |
| @@ -2901,31 +2906,33 @@ | |
| 2906 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2907 | return TH_ERROR; |
| 2908 | }else{ |
| 2909 | blob_reset(b); |
| 2910 | Th_Free( interp, b ); |
| 2911 | Th_SetResultInt( interp, 0 ); |
| 2912 | return TH_OK; |
| 2913 | } |
| 2914 | } |
| 2915 | |
| 2916 | /* |
| 2917 | ** TH Syntax: |
| 2918 | ** |
| 2919 | ** ob flush ?pop|end? |
| 2920 | ** |
| 2921 | ** Briefly reverts the output layer to the next-lower |
| 2922 | ** level, flushes the current buffer to that output layer, |
| 2923 | ** and clears out the current buffer. Does not change the |
| 2924 | ** buffering level unless "end" is specified, in which case |
| 2925 | ** it behaves as if "ob end" had been called (after flushing |
| 2926 | ** the buffer). |
| 2927 | */ |
| 2928 | static int ob_flush_command( Th_Interp *interp, void *ctx, |
| 2929 | int argc, const char **argv, int *argl ){ |
| 2930 | Th_Ob_Man * pMan = (Th_Ob_Man *)ctx; |
| 2931 | Blob * b = NULL; |
| 2932 | Th_Vtab * oldVtab; |
| 2933 | int rc = TH_OK; |
| 2934 | assert( pMan && (interp == pMan->interp) ); |
| 2935 | b = Th_ob_current(pMan); |
| 2936 | if( NULL == b ){ |
| 2937 | Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 ); |
| 2938 | return TH_ERROR; |
| @@ -2933,17 +2940,30 @@ | |
| 2940 | oldVtab = interp->pVtab; |
| 2941 | interp->pVtab = pMan->aVtab[pMan->cursor]; |
| 2942 | Th_output( interp, blob_str(b), b->nUsed ); |
| 2943 | interp->pVtab = oldVtab; |
| 2944 | blob_reset(b); |
| 2945 | |
| 2946 | if(!rc && argc>2){ |
| 2947 | int argPos = 2; |
| 2948 | char const * sub = argv[argPos]; |
| 2949 | int subL = argl[argPos]; |
| 2950 | /* "flush end" */ |
| 2951 | if(th_strlen(sub)==3 && |
| 2952 | ((0==memcmp("end", sub, subL) |
| 2953 | || (0==memcmp("pop", sub, subL))))){ |
| 2954 | rc |= ob_end_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2955 | } |
| 2956 | } |
| 2957 | Th_SetResultInt( interp, 0 ); |
| 2958 | return rc; |
| 2959 | } |
| 2960 | |
| 2961 | /* |
| 2962 | ** TH Syntax: |
| 2963 | ** |
| 2964 | ** ob get ?clean|end|pop? |
| 2965 | ** |
| 2966 | ** Fetches the contents of the current buffer level. If either |
| 2967 | ** 'clean' or 'end' are specified then the effect is as if "ob clean" |
| 2968 | ** or "ob end", respectively, are called after fetching the |
| 2969 | ** value. Calling "ob get end" is functionality equivalent to "ob get" |
| @@ -2969,11 +2989,13 @@ | |
| 2989 | subL = argl[argPos]; |
| 2990 | /* "ob get clean" */ |
| 2991 | if(!rc && th_strlen(sub)==5 && 0==memcmp("clean", sub, subL)){ |
| 2992 | rc |= ob_clean_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2993 | }/* "ob get end" */ |
| 2994 | else if(!rc && th_strlen(sub)==3 && |
| 2995 | ((0==memcmp("end", sub, subL)) |
| 2996 | || (0==memcmp("pop", sub, subL)))){ |
| 2997 | rc |= ob_end_command(interp, ctx, argc-1, argv+1, argl+1); |
| 2998 | } |
| 2999 | } |
| 3000 | return rc; |
| 3001 | } |
| @@ -3041,10 +3063,12 @@ | |
| 3063 | { "clean", ob_clean_command }, |
| 3064 | { "end", ob_end_command }, |
| 3065 | { "flush", ob_flush_command }, |
| 3066 | { "get", ob_get_command }, |
| 3067 | { "level", ob_level_command }, |
| 3068 | { "pop", ob_end_command }, |
| 3069 | { "push", ob_start_command }, |
| 3070 | { "start", ob_start_command }, |
| 3071 | { 0, 0 } |
| 3072 | }; |
| 3073 | if(NULL == pMan->interp){ |
| 3074 | pMan->interp = interp; |
| 3075 |