1
2#include <tcl.h>
3#include <string.h>
4#include <expat.h>
5#include <tclexpat.h>
6
7/*
8 * Beginning with 8.4, Tcl API is CONST'ified
9 */
10#if (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION <= 3)
11# define CONST84
12#endif
13
14
15typedef struct simpleCounter
16{
17    int elementCounter;
18} simpleCounter;
19
20static char example_usage[] =
21               "Usage example <expat parser obj> <subCommand>, where subCommand can be: \n"
22               "        enable    \n"
23               "        getresult \n"
24               "        remove    \n"
25               ;
26
27
28
29/*
30 *----------------------------------------------------------------------------
31 *
32 * ExampleElementStartCommand --
33 *
34 *	This procedure is called for every element start event
35 *      while parsing XML Data with an "example" enabled tclexpat
36 *      parser.
37 *
38 * Results:
39 *	None.
40 *
41 * Side effects:
42 *	Uses the "userData" field as int and increments it by every call.
43 *
44 *----------------------------------------------------------------------------
45 */
46
47void
48ExampleElementStartCommand (userData, name, atts)
49    void *userData;
50    const char *name;
51    const char **atts;
52{
53    simpleCounter *counter = (simpleCounter*) userData;
54
55    counter->elementCounter++;
56}
57
58
59/*
60 *----------------------------------------------------------------------------
61 *
62 * ExampleResetProc
63 *
64 *	Called for C handler set specific reset actions in case of
65 *      parser reset.
66 *
67 * Results:
68 *	None.
69 *
70 * Side effects:
71 *	Resets the "userData" of the C handler set parser extension.
72 *
73 *----------------------------------------------------------------------------
74 */
75
76void
77ExampleResetProc (interp, userData)
78    Tcl_Interp *interp;
79    void *userData;
80{
81    simpleCounter *counter = (simpleCounter*) userData;
82
83    counter->elementCounter = 0;
84}
85
86
87
88/*
89 *----------------------------------------------------------------------------
90 *
91 * ExampleFreeProc
92 *
93 *	Called for C handler set specific cleanup in case of parser
94 *      delete.
95 *
96 * Results:
97 *	None.
98 *
99 * Side effects:
100 *	C handler set specific userData gets free'd.
101 *
102 *----------------------------------------------------------------------------
103 */
104
105void
106ExampleFreeProc (interp, userData)
107    Tcl_Interp *interp;
108    void *userData;
109{
110    free (userData);
111}
112
113
114/*
115 *----------------------------------------------------------------------------
116 *
117 * TclExampleObjCmd --
118 *
119 *	This procedure is invoked to process the "example" command.
120 *
121 * Results:
122 *	A standard Tcl result.
123 *
124 * Side effects:
125 *	The expat parser object provided as argument is enhanced by
126 *      by the "example" handler set.
127 *
128 *----------------------------------------------------------------------------
129 */
130
131int
132TclExampleObjCmd(dummy, interp, objc, objv)
133     ClientData dummy;
134     Tcl_Interp *interp;
135     int objc;
136     Tcl_Obj *CONST objv[];
137{
138    char          *method;
139    CHandlerSet   *handlerSet;
140    int            methodIndex, result;
141    simpleCounter *counter;
142
143
144    static CONST84 char *exampleMethods[] = {
145        "enable", "getresult", "remove",
146        NULL
147    };
148    enum exampleMethod {
149        m_enable, m_getresult, m_remove
150    };
151
152    if (objc != 3) {
153        Tcl_WrongNumArgs (interp, 1, objv, example_usage);
154        return TCL_ERROR;
155    }
156
157    if (!CheckExpatParserObj (interp, objv[1])) {
158        Tcl_SetResult (interp, "First argument has to be a expat parser object", NULL);
159        return TCL_ERROR;
160    }
161
162    method = Tcl_GetStringFromObj (objv[2], NULL);
163    if (Tcl_GetIndexFromObj (interp, objv[2], exampleMethods, "method", 0,
164                             &methodIndex) != TCL_OK)
165    {
166        Tcl_SetResult (interp, example_usage, NULL);
167        return TCL_ERROR;
168    }
169
170    switch ((enum exampleMethod) methodIndex) {
171    case m_enable:
172        counter = (simpleCounter *) malloc (sizeof (simpleCounter));
173        counter->elementCounter = 0;
174
175        handlerSet = CHandlerSetCreate ("example");
176        handlerSet->userData = counter;
177        handlerSet->resetProc = ExampleResetProc;
178        handlerSet->freeProc = ExampleFreeProc;
179        handlerSet->elementstartcommand = ExampleElementStartCommand;
180
181        result = CHandlerSetInstall (interp, objv[1], handlerSet);
182        if (result == 1) {
183            /* This should not happen if CheckExpatParserObj() is used. */
184            Tcl_SetResult (interp, "argument has to be a expat parser object", NULL);
185            return TCL_ERROR;
186        }
187        if (result == 2) {
188            Tcl_SetResult (interp, "there is already a C handler set with this name installed", NULL);
189            /* In error case malloc'ed memory should be free'ed */
190            free (handlerSet->name);
191            Tcl_Free ( (char *) handlerSet);
192            return TCL_ERROR;
193        }
194        return TCL_OK;
195    case m_getresult:
196        counter = CHandlerSetGetUserData (interp, objv[1], "example");
197        Tcl_SetIntObj (Tcl_GetObjResult (interp), counter->elementCounter);
198        return TCL_OK;
199    case m_remove:
200        result = CHandlerSetRemove (interp, objv[1], "example");
201        if (result == 1) {
202            /* This should not happen if CheckExpatParserObj() is used. */
203            Tcl_SetResult (interp, "argument has to be a expat parser object", NULL);
204            return TCL_ERROR;
205        }
206        if (result == 2) {
207            Tcl_SetResult (interp, "expat parser obj hasn't a C handler set named \"example\"", NULL);
208            return TCL_ERROR;
209        }
210        return TCL_OK;
211    default:
212        Tcl_SetResult (interp, "unknown method", NULL);
213        return TCL_ERROR;
214    }
215
216}
217
218/*
219 *----------------------------------------------------------------------------
220 *
221 * Example_Init --
222 *
223 *	Initialization routine for loadable module
224 *
225 * Results:
226 *	None.
227 *
228 * Side effects:
229 *	Defines "example" enhancement command for expat parser obj
230 *
231 *----------------------------------------------------------------------------
232 */
233
234int
235Example_Init (interp)
236    Tcl_Interp *interp;
237{
238    Tcl_PkgRequire (interp, "expat", "2.0", 0);
239    Tcl_CreateObjCommand (interp, "example", TclExampleObjCmd, NULL, NULL );
240    Tcl_PkgProvide (interp, "example", "1.0");
241}
242
243