Fossil SCM

Documented the "ob" API, added "ob level".

stephan 2012-07-14 19:19 th1-query-api
Commit 66104f8b5d8278cd7a15cdd4f8ea09437ae53c31
2 files changed +129 -28 +2
+129 -28
--- src/th.c
+++ src/th.c
@@ -2751,71 +2751,92 @@
27512751
#endif
27522752
/* end TH_USE_SQLITE */
27532753
27542754
27552755
#ifdef TH_USE_OUTBUF
2756
+/* Reminder: the ob code "really" belongs in th_lang.c,
2757
+ but we need access to Th_Interp internals in order to
2758
+ swap out Th_Vtab parts for purposes of stacking layers
2759
+ of buffers.
2760
+*/
2761
+/*
2762
+** Manager of a stack of Blob objects for output buffering.
2763
+*/
27562764
struct Th_Ob_Man {
2757
- Blob ** aBuf;
2758
- int nBuf;
2759
- int cursor;
2760
- Th_Interp * interp;
2761
- Th_Vtab ** aVtab;
2765
+ Blob ** aBuf; /* Stack of Blobs */
2766
+ int nBuf; /* Number of blobs */
2767
+ int cursor; /* Current level (-1=not active) */
2768
+ Th_Interp * interp; /* The associated interpreter */
2769
+ Th_Vtab ** aVtab; /* Stack of Vtabs (they get restored
2770
+ when a buffering level is popped).
2771
+ Has nBuf entries.
2772
+
2773
+ FIXME? Only swap out the "out" members?
2774
+ */
27622775
};
27632776
27642777
typedef struct Th_Ob_Man Th_Ob_Man;
27652778
#define Th_Ob_Man_empty_m { NULL, 0, -1, NULL, NULL }
27662779
static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
27672780
static Th_Ob_Man Th_Ob_Man_instance = Th_Ob_Man_empty_m;
27682781
2782
+/*
2783
+** Returns the top-most Blob in pMan's stack, or NULL
2784
+** if buffering is not active.
2785
+*/
27692786
static Blob * Th_ob_current( Th_Ob_Man * pMan ){
27702787
return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
27712788
}
27722789
27732790
2774
-static int Th_output_ob( char const * zData, int len, void * pState ){
2791
+/*
2792
+** Th_output_f() impl which expects pState to be (Th_Ob_Man*).
2793
+** (zData,len) are appended to pState's current output buffer.
2794
+*/
2795
+static int Th_output_f_ob( char const * zData, int len, void * pState ){
27752796
Th_Ob_Man * pMan = (Th_Ob_Man*)pState;
27762797
Blob * b = Th_ob_current( pMan );
27772798
assert( NULL != pMan );
27782799
assert( b );
27792800
blob_append( b, zData, len );
27802801
return len;
27812802
}
27822803
2804
+/*
2805
+** Vtab impl for the ob buffering layer.
2806
+*/
27832807
static Th_Vtab Th_Vtab_Ob = { th_fossil_realloc,
27842808
{
2785
- Th_output_ob,
2809
+ Th_output_f_ob,
27862810
NULL,
27872811
1
27882812
}
27892813
};
27902814
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
2815
+/*
2816
+** Pushes a new blob onto pMan's stack. On success
2817
+** returns TH_OK and assigns *pOut (if pOut is not NULL)
2818
+** to the new blob (which is owned by pMan). On error
2819
+** pOut is not modified and non-0 is returned.
2820
+*/
28002821
int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut ){
28012822
Blob * pBlob;
28022823
int x, i;
28032824
assert( NULL != pMan->interp );
2804
- pBlob = (Blob *)OB_MALLOC(pMan->interp, sizeof(Blob));
2825
+ pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob));
28052826
*pBlob = empty_blob;
28062827
28072828
if( pMan->cursor <= pMan->nBuf ){
28082829
/* expand if needed */
28092830
x = (pMan->cursor>0 ? pMan->cursor : 1) * 2;
28102831
/*fprintf(stderr,"OB EXPAND x=%d\n",x);*/
2811
- void * re = OB_REALLOC( pMan->interp, pMan->aBuf, x * sizeof(Blob*) );
2832
+ void * re = Th_Realloc( pMan->interp, pMan->aBuf, x * sizeof(Blob*) );
28122833
if(NULL==re){
28132834
goto error;
28142835
}
28152836
pMan->aBuf = (Blob **)re;
2816
- re = OB_REALLOC( pMan->interp, pMan->aVtab, x * sizeof(Th_Vtab*) );
2837
+ re = Th_Realloc( pMan->interp, pMan->aVtab, x * sizeof(Th_Vtab*) );
28172838
if(NULL==re){
28182839
goto error;
28192840
}
28202841
pMan->aVtab = (Th_Vtab**)re;
28212842
for( i = pMan->nBuf; i < x; ++i ){
@@ -2836,15 +2857,23 @@
28362857
}
28372858
/*fprintf(stderr,"OB PUSH: %p\n", pBlob);*/
28382859
return TH_OK;
28392860
error:
28402861
if( pBlob ){
2841
- OB_FREE( pMan->interp, pBlob );
2862
+ Th_Free( pMan->interp, pBlob );
28422863
}
28432864
return TH_ERROR;
28442865
}
28452866
2867
+/*
2868
+** Pops the top-most output buffer off the stack and returns
2869
+** it. Returns NULL if there is no current buffer. When the last
2870
+** buffer is popped, pMan's internals are cleaned up.
2871
+**
2872
+** The caller owns the returned object and must eventually call
2873
+** blob_reset() on it.
2874
+*/
28462875
Blob * Th_ob_pop( Th_Ob_Man * pMan ){
28472876
if( pMan->cursor < 0 ){
28482877
return NULL;
28492878
}else{
28502879
Blob * rc;
@@ -2852,19 +2881,27 @@
28522881
rc = pMan->aBuf[pMan->cursor];
28532882
pMan->aBuf[pMan->cursor] = NULL;
28542883
pMan->interp->pVtab = pMan->aVtab[pMan->cursor];
28552884
pMan->aVtab[pMan->cursor] = NULL;
28562885
if(-1 == --pMan->cursor){
2857
- OB_FREE( pMan->interp, pMan->aBuf );
2858
- OB_FREE( pMan->interp, pMan->aVtab );
2886
+ Th_Free( pMan->interp, pMan->aBuf );
2887
+ Th_Free( pMan->interp, pMan->aVtab );
28592888
*pMan = Th_Ob_Man_empty;
28602889
}
28612890
/*fprintf(stderr,"OB pop: %p level=%d\n", rc, pMan->cursor-1);*/
28622891
return rc;
28632892
}
28642893
}
28652894
2895
+/*
2896
+** TH Syntax:
2897
+**
2898
+** ob clean
2899
+**
2900
+** Erases any currently buffered contents but does not modify
2901
+** the buffering level.
2902
+*/
28662903
static int ob_clean_command( Th_Interp *interp, void *ctx,
28672904
int argc, const char **argv, int *argl
28682905
){
28692906
Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
28702907
Blob * b;
@@ -2877,10 +2914,18 @@
28772914
blob_reset(b);
28782915
}
28792916
return TH_OK;
28802917
}
28812918
2919
+/*
2920
+** TH Syntax:
2921
+**
2922
+** ob end
2923
+**
2924
+** Erases any currently buffered contents and pops the current buffer
2925
+** from the stack.
2926
+*/
28822927
static int ob_end_command( Th_Interp *interp, void *ctx,
28832928
int argc, const char **argv, int *argl ){
28842929
Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
28852930
Blob * b;
28862931
assert( pMan && (interp == pMan->interp) );
@@ -2888,15 +2933,27 @@
28882933
if(!b){
28892934
Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 );
28902935
return TH_ERROR;
28912936
}else{
28922937
blob_reset(b);
2893
- OB_FREE( interp, b );
2938
+ Th_Free( interp, b );
28942939
}
28952940
return TH_OK;
28962941
}
28972942
2943
+/*
2944
+** TH Syntax:
2945
+**
2946
+** ob flush
2947
+**
2948
+** UNTESTED! Maybe not needed.
2949
+**
2950
+** Briefly reverts the output layer to the next-lower
2951
+** level, flushes the current buffer to that output layer,
2952
+** and clears out the current buffer. Does not change the
2953
+** buffering level.
2954
+*/
28982955
static int ob_flush_command( Th_Interp *interp, void *ctx,
28992956
int argc, const char **argv, int *argl ){
29002957
Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
29012958
Blob * b = NULL;
29022959
Th_Vtab * oldVtab;
@@ -2912,10 +2969,21 @@
29122969
interp->pVtab = oldVtab;
29132970
blob_reset(b);
29142971
return TH_OK;
29152972
}
29162973
2974
+/*
2975
+** TH Syntax:
2976
+**
2977
+** ob get ?clean|end?
2978
+**
2979
+** Fetches the contents of the current buffer level. If either
2980
+** 'clean' or 'end' are specified then the effect is as if "ob clean"
2981
+** or "ob end", respectively, are called after fetching the
2982
+** value. Calling "ob get end" is functionality equivalent to "ob get"
2983
+** followed by "ob end".
2984
+*/
29172985
static int ob_get_command( Th_Interp *interp, void *ctx,
29182986
int argc, const char **argv, int *argl){
29192987
Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
29202988
Blob * b = NULL;
29212989
assert( pMan && (interp == pMan->interp) );
@@ -2942,10 +3010,34 @@
29423010
}
29433011
return rc;
29443012
}
29453013
}
29463014
3015
+/*
3016
+** TH Syntax:
3017
+**
3018
+** ob level
3019
+**
3020
+** Returns the buffering level, where 0 means no buffering is
3021
+** active, 1 means 1 level is active, etc.
3022
+*/
3023
+static int ob_level_command( Th_Interp *interp, void *ctx,
3024
+ int argc, const char **argv, int *argl
3025
+){
3026
+ Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
3027
+ Th_SetResultInt( interp, 1 + pMan->cursor );
3028
+ return TH_OK;
3029
+}
3030
+
3031
+/*
3032
+** TH Syntax:
3033
+**
3034
+** ob start
3035
+**
3036
+** Pushes a new level of buffering onto the buffer stack.
3037
+** Returns the new buffering level (1-based).
3038
+*/
29473039
static int ob_start_command( Th_Interp *interp, void *ctx,
29483040
int argc, const char **argv, int *argl
29493041
){
29503042
Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
29513043
Blob * b = NULL;
@@ -2956,14 +3048,22 @@
29563048
assert( NULL == b );
29573049
return rc;
29583050
}
29593051
assert( NULL != b );
29603052
/*fprintf(stderr,"OB STARTED: %p level=%d\n", b, pMan->cursor);*/
2961
- Th_SetResultInt( interp, pMan->cursor );
3053
+ Th_SetResultInt( interp, 1 + pMan->cursor );
29623054
return TH_OK;
29633055
}
29643056
3057
+/*
3058
+** TH Syntax:
3059
+**
3060
+** ob clean|end|flush|get|level|start
3061
+**
3062
+** Runs the given subcommand.
3063
+**
3064
+*/
29653065
static int ob_cmd(
29663066
Th_Interp *interp,
29673067
void *ignored,
29683068
int argc,
29693069
const char **argv,
@@ -2973,18 +3073,20 @@
29733073
Th_SubCommand aSub[] = {
29743074
{ "clean", ob_clean_command },
29753075
{ "end", ob_end_command },
29763076
{ "flush", ob_flush_command },
29773077
{ "get", ob_get_command },
3078
+ { "level", ob_level_command },
29783079
{ "start", ob_start_command },
29793080
{ 0, 0 }
29803081
};
29813082
if(NULL == pMan->interp){
29823083
pMan->interp = interp;
29833084
/*
29843085
FIXME: add rudamentary at-finalization GC to Th_Interp and clean
2985
- this up there.
3086
+ this up there. We currently leak only if the client does not
3087
+ close all buffering levels properly.
29863088
*/
29873089
}
29883090
return Th_CallSubCommand(interp, pMan, argc, argv, argl, aSub);
29893091
29903092
}
@@ -2994,11 +3096,10 @@
29943096
{"ob", ob_cmd, 0},
29953097
{0,0,0}
29963098
};
29973099
return Th_register_commands( interp, aCommand );
29983100
}
2999
-#undef OB_MALLOC
3000
-#undef OB_REALLOC
3001
-#undef OB_FREE
3101
+
3102
+#undef Th_Ob_Man_empty_m
30023103
#endif
30033104
/* end TH_USE_OUTBUF */
30043105
30053106
--- src/th.c
+++ src/th.c
@@ -2751,71 +2751,92 @@
2751 #endif
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 ){
@@ -2836,15 +2857,23 @@
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;
@@ -2852,19 +2881,27 @@
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;
@@ -2877,10 +2914,18 @@
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) );
@@ -2888,15 +2933,27 @@
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;
@@ -2912,10 +2969,21 @@
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) );
@@ -2942,10 +3010,34 @@
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;
@@ -2956,14 +3048,22 @@
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,
@@ -2973,18 +3073,20 @@
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 }
@@ -2994,11 +3096,10 @@
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
3005
--- src/th.c
+++ src/th.c
@@ -2751,71 +2751,92 @@
2751 #endif
2752 /* end TH_USE_SQLITE */
2753
2754
2755 #ifdef TH_USE_OUTBUF
2756 /* Reminder: the ob code "really" belongs in th_lang.c,
2757 but we need access to Th_Interp internals in order to
2758 swap out Th_Vtab parts for purposes of stacking layers
2759 of buffers.
2760 */
2761 /*
2762 ** Manager of a stack of Blob objects for output buffering.
2763 */
2764 struct Th_Ob_Man {
2765 Blob ** aBuf; /* Stack of Blobs */
2766 int nBuf; /* Number of blobs */
2767 int cursor; /* Current level (-1=not active) */
2768 Th_Interp * interp; /* The associated interpreter */
2769 Th_Vtab ** aVtab; /* Stack of Vtabs (they get restored
2770 when a buffering level is popped).
2771 Has nBuf entries.
2772
2773 FIXME? Only swap out the "out" members?
2774 */
2775 };
2776
2777 typedef struct Th_Ob_Man Th_Ob_Man;
2778 #define Th_Ob_Man_empty_m { NULL, 0, -1, NULL, NULL }
2779 static const Th_Ob_Man Th_Ob_Man_empty = Th_Ob_Man_empty_m;
2780 static Th_Ob_Man Th_Ob_Man_instance = Th_Ob_Man_empty_m;
2781
2782 /*
2783 ** Returns the top-most Blob in pMan's stack, or NULL
2784 ** if buffering is not active.
2785 */
2786 static Blob * Th_ob_current( Th_Ob_Man * pMan ){
2787 return pMan->nBuf>0 ? pMan->aBuf[pMan->cursor] : 0;
2788 }
2789
2790
2791 /*
2792 ** Th_output_f() impl which expects pState to be (Th_Ob_Man*).
2793 ** (zData,len) are appended to pState's current output buffer.
2794 */
2795 static int Th_output_f_ob( char const * zData, int len, void * pState ){
2796 Th_Ob_Man * pMan = (Th_Ob_Man*)pState;
2797 Blob * b = Th_ob_current( pMan );
2798 assert( NULL != pMan );
2799 assert( b );
2800 blob_append( b, zData, len );
2801 return len;
2802 }
2803
2804 /*
2805 ** Vtab impl for the ob buffering layer.
2806 */
2807 static Th_Vtab Th_Vtab_Ob = { th_fossil_realloc,
2808 {
2809 Th_output_f_ob,
2810 NULL,
2811 1
2812 }
2813 };
2814
2815 /*
2816 ** Pushes a new blob onto pMan's stack. On success
2817 ** returns TH_OK and assigns *pOut (if pOut is not NULL)
2818 ** to the new blob (which is owned by pMan). On error
2819 ** pOut is not modified and non-0 is returned.
2820 */
 
 
 
2821 int Th_ob_push( Th_Ob_Man * pMan, Blob ** pOut ){
2822 Blob * pBlob;
2823 int x, i;
2824 assert( NULL != pMan->interp );
2825 pBlob = (Blob *)Th_Malloc(pMan->interp, sizeof(Blob));
2826 *pBlob = empty_blob;
2827
2828 if( pMan->cursor <= pMan->nBuf ){
2829 /* expand if needed */
2830 x = (pMan->cursor>0 ? pMan->cursor : 1) * 2;
2831 /*fprintf(stderr,"OB EXPAND x=%d\n",x);*/
2832 void * re = Th_Realloc( pMan->interp, pMan->aBuf, x * sizeof(Blob*) );
2833 if(NULL==re){
2834 goto error;
2835 }
2836 pMan->aBuf = (Blob **)re;
2837 re = Th_Realloc( pMan->interp, pMan->aVtab, x * sizeof(Th_Vtab*) );
2838 if(NULL==re){
2839 goto error;
2840 }
2841 pMan->aVtab = (Th_Vtab**)re;
2842 for( i = pMan->nBuf; i < x; ++i ){
@@ -2836,15 +2857,23 @@
2857 }
2858 /*fprintf(stderr,"OB PUSH: %p\n", pBlob);*/
2859 return TH_OK;
2860 error:
2861 if( pBlob ){
2862 Th_Free( pMan->interp, pBlob );
2863 }
2864 return TH_ERROR;
2865 }
2866
2867 /*
2868 ** Pops the top-most output buffer off the stack and returns
2869 ** it. Returns NULL if there is no current buffer. When the last
2870 ** buffer is popped, pMan's internals are cleaned up.
2871 **
2872 ** The caller owns the returned object and must eventually call
2873 ** blob_reset() on it.
2874 */
2875 Blob * Th_ob_pop( Th_Ob_Man * pMan ){
2876 if( pMan->cursor < 0 ){
2877 return NULL;
2878 }else{
2879 Blob * rc;
@@ -2852,19 +2881,27 @@
2881 rc = pMan->aBuf[pMan->cursor];
2882 pMan->aBuf[pMan->cursor] = NULL;
2883 pMan->interp->pVtab = pMan->aVtab[pMan->cursor];
2884 pMan->aVtab[pMan->cursor] = NULL;
2885 if(-1 == --pMan->cursor){
2886 Th_Free( pMan->interp, pMan->aBuf );
2887 Th_Free( pMan->interp, pMan->aVtab );
2888 *pMan = Th_Ob_Man_empty;
2889 }
2890 /*fprintf(stderr,"OB pop: %p level=%d\n", rc, pMan->cursor-1);*/
2891 return rc;
2892 }
2893 }
2894
2895 /*
2896 ** TH Syntax:
2897 **
2898 ** ob clean
2899 **
2900 ** Erases any currently buffered contents but does not modify
2901 ** the buffering level.
2902 */
2903 static int ob_clean_command( Th_Interp *interp, void *ctx,
2904 int argc, const char **argv, int *argl
2905 ){
2906 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
2907 Blob * b;
@@ -2877,10 +2914,18 @@
2914 blob_reset(b);
2915 }
2916 return TH_OK;
2917 }
2918
2919 /*
2920 ** TH Syntax:
2921 **
2922 ** ob end
2923 **
2924 ** Erases any currently buffered contents and pops the current buffer
2925 ** from the stack.
2926 */
2927 static int ob_end_command( Th_Interp *interp, void *ctx,
2928 int argc, const char **argv, int *argl ){
2929 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
2930 Blob * b;
2931 assert( pMan && (interp == pMan->interp) );
@@ -2888,15 +2933,27 @@
2933 if(!b){
2934 Th_ErrorMessage( interp, "Not currently buffering.", NULL, 0 );
2935 return TH_ERROR;
2936 }else{
2937 blob_reset(b);
2938 Th_Free( interp, b );
2939 }
2940 return TH_OK;
2941 }
2942
2943 /*
2944 ** TH Syntax:
2945 **
2946 ** ob flush
2947 **
2948 ** UNTESTED! Maybe not needed.
2949 **
2950 ** Briefly reverts the output layer to the next-lower
2951 ** level, flushes the current buffer to that output layer,
2952 ** and clears out the current buffer. Does not change the
2953 ** buffering level.
2954 */
2955 static int ob_flush_command( Th_Interp *interp, void *ctx,
2956 int argc, const char **argv, int *argl ){
2957 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
2958 Blob * b = NULL;
2959 Th_Vtab * oldVtab;
@@ -2912,10 +2969,21 @@
2969 interp->pVtab = oldVtab;
2970 blob_reset(b);
2971 return TH_OK;
2972 }
2973
2974 /*
2975 ** TH Syntax:
2976 **
2977 ** ob get ?clean|end?
2978 **
2979 ** Fetches the contents of the current buffer level. If either
2980 ** 'clean' or 'end' are specified then the effect is as if "ob clean"
2981 ** or "ob end", respectively, are called after fetching the
2982 ** value. Calling "ob get end" is functionality equivalent to "ob get"
2983 ** followed by "ob end".
2984 */
2985 static int ob_get_command( Th_Interp *interp, void *ctx,
2986 int argc, const char **argv, int *argl){
2987 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
2988 Blob * b = NULL;
2989 assert( pMan && (interp == pMan->interp) );
@@ -2942,10 +3010,34 @@
3010 }
3011 return rc;
3012 }
3013 }
3014
3015 /*
3016 ** TH Syntax:
3017 **
3018 ** ob level
3019 **
3020 ** Returns the buffering level, where 0 means no buffering is
3021 ** active, 1 means 1 level is active, etc.
3022 */
3023 static int ob_level_command( Th_Interp *interp, void *ctx,
3024 int argc, const char **argv, int *argl
3025 ){
3026 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
3027 Th_SetResultInt( interp, 1 + pMan->cursor );
3028 return TH_OK;
3029 }
3030
3031 /*
3032 ** TH Syntax:
3033 **
3034 ** ob start
3035 **
3036 ** Pushes a new level of buffering onto the buffer stack.
3037 ** Returns the new buffering level (1-based).
3038 */
3039 static int ob_start_command( Th_Interp *interp, void *ctx,
3040 int argc, const char **argv, int *argl
3041 ){
3042 Th_Ob_Man * pMan = (Th_Ob_Man *)ctx;
3043 Blob * b = NULL;
@@ -2956,14 +3048,22 @@
3048 assert( NULL == b );
3049 return rc;
3050 }
3051 assert( NULL != b );
3052 /*fprintf(stderr,"OB STARTED: %p level=%d\n", b, pMan->cursor);*/
3053 Th_SetResultInt( interp, 1 + pMan->cursor );
3054 return TH_OK;
3055 }
3056
3057 /*
3058 ** TH Syntax:
3059 **
3060 ** ob clean|end|flush|get|level|start
3061 **
3062 ** Runs the given subcommand.
3063 **
3064 */
3065 static int ob_cmd(
3066 Th_Interp *interp,
3067 void *ignored,
3068 int argc,
3069 const char **argv,
@@ -2973,18 +3073,20 @@
3073 Th_SubCommand aSub[] = {
3074 { "clean", ob_clean_command },
3075 { "end", ob_end_command },
3076 { "flush", ob_flush_command },
3077 { "get", ob_get_command },
3078 { "level", ob_level_command },
3079 { "start", ob_start_command },
3080 { 0, 0 }
3081 };
3082 if(NULL == pMan->interp){
3083 pMan->interp = interp;
3084 /*
3085 FIXME: add rudamentary at-finalization GC to Th_Interp and clean
3086 this up there. We currently leak only if the client does not
3087 close all buffering levels properly.
3088 */
3089 }
3090 return Th_CallSubCommand(interp, pMan, argc, argv, argl, aSub);
3091
3092 }
@@ -2994,11 +3096,10 @@
3096 {"ob", ob_cmd, 0},
3097 {0,0,0}
3098 };
3099 return Th_register_commands( interp, aCommand );
3100 }
3101
3102 #undef Th_Ob_Man_empty_m
 
3103 #endif
3104 /* end TH_USE_OUTBUF */
3105
3106
+2
--- src/th.h
+++ src/th.h
@@ -5,10 +5,12 @@
55
#include "sqlite3.h"
66
#endif
77
88
/*
99
** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
10
+** They are functionally similar to PHP's ob_start(), ob_end(), etc.
11
+** family of functions, providing output capturing/buffering.
1012
*/
1113
#define TH_USE_OUTBUF
1214
/*#undef TH_USE_OUTBUF*/
1315
1416
1517
--- src/th.h
+++ src/th.h
@@ -5,10 +5,12 @@
5 #include "sqlite3.h"
6 #endif
7
8 /*
9 ** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
 
 
10 */
11 #define TH_USE_OUTBUF
12 /*#undef TH_USE_OUTBUF*/
13
14
15
--- src/th.h
+++ src/th.h
@@ -5,10 +5,12 @@
5 #include "sqlite3.h"
6 #endif
7
8 /*
9 ** TH_USE_OUTBUF, if defined, enables the "ob" family of functions.
10 ** They are functionally similar to PHP's ob_start(), ob_end(), etc.
11 ** family of functions, providing output capturing/buffering.
12 */
13 #define TH_USE_OUTBUF
14 /*#undef TH_USE_OUTBUF*/
15
16
17

Keyboard Shortcuts

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