File: ms.c

package info (click to toggle)
tcllib 1.8-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 13,628 kB
  • ctags: 4,897
  • sloc: tcl: 88,012; sh: 7,856; ansic: 4,174; xml: 1,765; yacc: 753; perl: 84; f90: 84; makefile: 60; python: 33; ruby: 13; php: 11
file content (379 lines) | stat: -rw-r--r-- 10,501 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/* struct::tree - critcl - layer 2 definitions
 *
 * -> Support for the tree methods in layer 3.
 */

#include <ms.h>
#include <m.h>
#include <t.h>
#include <tn.h>
#include <util.h>

/* .................................................. */

/*
 *---------------------------------------------------------------------------
 *
 * ms_getchildren --
 *
 *	Retrieval of the children for a node, either only direct children or
 *	all, possibly filtering.
 *
 * Results:
 *	A standard Tcl result code.
 *
 * Side effects:
 *	Only internal, memory allocation changes ...
 *
 *---------------------------------------------------------------------------
 */

int
ms_getchildren (TN* n, int all,
		int cmdc, Tcl_Obj** cmdv,
		Tcl_Obj* tree, Tcl_Interp* interp)
{
    int	      res;
    int	      listc = 0;
    Tcl_Obj** listv = NULL;

    if (all) {
	listv = tn_getdescendants (n, &listc);
    } else {
	listv = tn_getchildren	  (n, &listc);
    }

    if (!listc) {
	/* => (listv == NULL) */
	Tcl_SetObjResult (interp, Tcl_NewListObj (0, NULL));
	return TCL_OK;
    }

    res = tn_filternodes (&listc, listv, cmdc, cmdv, tree, interp);

    if (res != TCL_OK) {
	ckfree ((char*) listv);
	return TCL_ERROR;
    }

    if (!listc) {
	Tcl_SetObjResult (interp, Tcl_NewListObj (0, NULL));
    } else {
	Tcl_SetObjResult (interp, Tcl_NewListObj (listc, listv));
    }

    ckfree ((char*) listv);
    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------
 *
 * ms_assign --
 *
 *	Copies the argument tree over into this one. Uses direct
 *	access to internal data structures for matching tree objects, and
 *	goes through a serialize/deserialize combination otherwise.
 *
 * Results:
 *	A standard Tcl result code.
 *
 * Side effects:
 *	Only internal, memory allocation changes ...
 *
 *---------------------------------------------------------------------------
 */

int
ms_assign (Tcl_Interp* interp, T* t, Tcl_Obj* srccmd)
{
    Tcl_CmdInfo srcCmd;

    if (!Tcl_GetCommandInfo(interp,
			    Tcl_GetString (srccmd),
			    &srcCmd)) {
	Tcl_AppendResult (interp, "invalid command name \"",
			  Tcl_GetString (srccmd), "\"", NULL);
	return TCL_ERROR;
    }

    if (srcCmd.objProc == ms_objcmd) {
	/* The source tree object is managed by this code also. We can
	 * retrieve and copy the data directly.
	 */

	T* src = (T*) srcCmd.objClientData;

	return t_assign (t, src);

    } else {
	/* The source tree is not managed by this package Use
	 * (de)serialization to transfer the information We do not invoke the
	 * command proc directly
	 */

	int	 res;
	Tcl_Obj* ser;
	Tcl_Obj* cmd [2];

	/* Phase 1: Obtain serialization object by invoking the object method
	 */

	cmd [0] = srccmd;
	cmd [1] = Tcl_NewStringObj ("serialize", -1);

	Tcl_IncrRefCount (cmd [0]);
	Tcl_IncrRefCount (cmd [1]);

	res = Tcl_EvalObjv (interp, 2, cmd, 0);

	Tcl_DecrRefCount (cmd [0]);
	Tcl_DecrRefCount (cmd [1]);

	if (res != TCL_OK) {
	    return TCL_ERROR;
	}

	ser = Tcl_GetObjResult (interp);
	Tcl_IncrRefCount (ser);
	Tcl_ResetResult (interp);

	/* Phase 2: Copy into ourselves using regular deserialization
	 */

	res = t_deserialize (t, interp, ser);
	Tcl_DecrRefCount (ser);
	return res;
    }
}

/*
 *---------------------------------------------------------------------------
 *
 * ms_set --
 *
 *	Copies this tree over into the argument tree. Uses direct access to
 *	internal data structures for matching tree objects, and goes through a
 *	serialize/deserialize combination otherwise.
 *
 * Results:
 *	A standard Tcl result code.
 *
 * Side effects:
 *	Only internal, memory allocation changes ...
 *
 *---------------------------------------------------------------------------
 */

int
ms_set (Tcl_Interp* interp, T* t, Tcl_Obj* dstcmd)
{
    Tcl_CmdInfo dstCmd;

    if (!Tcl_GetCommandInfo(interp,
			    Tcl_GetString (dstcmd),
			    &dstCmd)) {
	Tcl_AppendResult (interp, "invalid command name \"",
			  Tcl_GetString (dstcmd), "\"", NULL);
	return TCL_ERROR;
    }

    if (dstCmd.objProc == ms_objcmd) {
	/* The destination tree object is managed by this code also We can
	 * retrieve and copy the data directly.
	 */

	T* dest = (T*) dstCmd.objClientData;

	return t_assign (dest, t);

    } else {
	/* The destination tree is not managed by this package Use
	 * (de)serialization to transfer the information We do not invoke the
	 * command proc directly.
	 */

	int	 res;
	Tcl_Obj* ser;
	Tcl_Obj* cmd [3];

	/* Phase 1: Obtain our serialization */

	ser = ms_serialize (t->root);

	/* Phase 2: Copy into destination by invoking its deserialization
	 * method
	 */

	cmd [0] = dstcmd;
	cmd [1] = Tcl_NewStringObj ("deserialize", -1);
	cmd [2] = ser;

	Tcl_IncrRefCount (cmd [0]);
	Tcl_IncrRefCount (cmd [1]);
	Tcl_IncrRefCount (cmd [2]);

	res = Tcl_EvalObjv (interp, 3, cmd, 0);

	Tcl_DecrRefCount (cmd [0]);
	Tcl_DecrRefCount (cmd [1]);
	Tcl_DecrRefCount (cmd [2]); /* == ser, is gone now */

	if (res != TCL_OK) {
	    return TCL_ERROR;
	}

	Tcl_ResetResult (interp);
	return TCL_OK;
    }
}

/*
 *---------------------------------------------------------------------------
 *
 * ms_serialize --
 *
 *	Generates Tcl value from tree, serialized tree data.
 *
 * Results:
 *	A standard Tcl result code.
 *
 * Side effects:
 *	Only internal, memory allocation changes ...
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj*
ms_serialize (TN* n)
{
    Tcl_Obj*  ser;
    int	      end;
    int	      listc;
    Tcl_Obj** listv;
    Tcl_Obj*  empty;

    listc = 3 * (tn_ndescendants (n) + 1);
    listv = NALLOC (listc, Tcl_Obj*);
    empty = Tcl_NewObj ();
    Tcl_IncrRefCount (empty);

    end = tn_serialize (n, listc, listv, 0, -1, empty);

    ASSERT (listc == end, "Bad serialization");

    ser = Tcl_NewListObj (listc, listv);

    Tcl_DecrRefCount (empty);
    ckfree((char*) listv);

    return ser;
}

/*
 *---------------------------------------------------------------------------
 *
 * ms_objcmd --
 *
 *	Implementation of tree objects, the main dispatcher function.
 *
 * Results:
 *	A standard Tcl result code.
 *
 * Side effects:
 *	Per the called methods.
 *
 *---------------------------------------------------------------------------
 */

int
ms_objcmd (ClientData cd, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv)
{
    T*  t = (T*) cd;
    int m;

    static CONST char* methods [] = {
	"-->",         "=",           "ancestors", "append",   "attr",
	"children",    "cut",         "delete",    "depth",    "descendants",
	"deserialize", "destroy",     "exists",    "get",      "getall",
	"height",      "index",       "insert",    "isleaf",   "keyexists",
	"keys",        "lappend",     "leaves",    "move",     "next",
	"nodes",       "numchildren", "parent",    "previous", "rename",
	"rootname",    "serialize",   "set",       "size",     "splice",
	"swap",        "unset",       "walk",      "walkproc",
	NULL
    };
    enum methods {
	M_TSET,        M_TASSIGN,     M_ANCESTORS, M_APPEND,   M_ATTR,
	M_CHILDREN,    M_CUT,         M_DELETE,    M_DEPTH,    M_DESCENDANTS,
	M_DESERIALIZE, M_DESTROY,     M_EXISTS,    M_GET,      M_GETALL,
	M_HEIGHT,      M_INDEX,       M_INSERT,    M_ISLEAF,   M_KEYEXISTS,
	M_KEYS,        M_LAPPEND,     M_LEAVES,    M_MOVE,     M_NEXT,
	M_NODES,       M_NUMCHILDREN, M_PARENT,    M_PREVIOUS, M_RENAME,
	M_ROOTNAME,    M_SERIALIZE,   M_SET,       M_SIZE,     M_SPLICE,
	M_SWAP,        M_UNSET,       M_WALK,      M_WALKPROC
    };

    if (objc < 2) {
	Tcl_WrongNumArgs (interp, objc, objv, "option ?arg arg ...?");
	return TCL_ERROR;
    } else if (Tcl_GetIndexFromObj (interp, objv [1], methods, "option",
				    0, &m) != TCL_OK) {
	return TCL_ERROR;
    }

    /* Dispatch to methods. They check the #args in detail before performing
     * the requested functionality
     */

    switch (m) {
    case M_TASSIGN:	return m_TASSIGN     (t, interp, objc, objv);
    case M_TSET:	return m_TSET	     (t, interp, objc, objv);
    case M_ANCESTORS:	return m_ANCESTORS   (t, interp, objc, objv);
    case M_APPEND:	return m_APPEND	     (t, interp, objc, objv);
    case M_ATTR:	return m_ATTR	     (t, interp, objc, objv);
    case M_CHILDREN:	return m_CHILDREN    (t, interp, objc, objv);
    case M_CUT:		return m_CUT	     (t, interp, objc, objv);
    case M_DELETE:	return m_DELETE	     (t, interp, objc, objv);
    case M_DEPTH:	return m_DEPTH	     (t, interp, objc, objv);
    case M_DESCENDANTS: return m_DESCENDANTS (t, interp, objc, objv);
    case M_DESERIALIZE: return m_DESERIALIZE (t, interp, objc, objv);
    case M_DESTROY:	return m_DESTROY     (t, interp, objc, objv);
    case M_EXISTS:	return m_EXISTS	     (t, interp, objc, objv);
    case M_GET:		return m_GET	     (t, interp, objc, objv);
    case M_GETALL:	return m_GETALL	     (t, interp, objc, objv);
    case M_HEIGHT:	return m_HEIGHT	     (t, interp, objc, objv);
    case M_INDEX:	return m_INDEX	     (t, interp, objc, objv);
    case M_INSERT:	return m_INSERT	     (t, interp, objc, objv);
    case M_ISLEAF:	return m_ISLEAF	     (t, interp, objc, objv);
    case M_KEYEXISTS:	return m_KEYEXISTS   (t, interp, objc, objv);
    case M_KEYS:	return m_KEYS	     (t, interp, objc, objv);
    case M_LAPPEND:	return m_LAPPEND     (t, interp, objc, objv);
    case M_LEAVES:	return m_LEAVES	     (t, interp, objc, objv);
    case M_MOVE:	return m_MOVE	     (t, interp, objc, objv);
    case M_NEXT:	return m_NEXT	     (t, interp, objc, objv);
    case M_NODES:	return m_NODES	     (t, interp, objc, objv);
    case M_NUMCHILDREN: return m_NUMCHILDREN (t, interp, objc, objv);
    case M_PARENT:	return m_PARENT	     (t, interp, objc, objv);
    case M_PREVIOUS:	return m_PREVIOUS    (t, interp, objc, objv);
    case M_RENAME:	return m_RENAME	     (t, interp, objc, objv);
    case M_ROOTNAME:	return m_ROOTNAME    (t, interp, objc, objv);
    case M_SERIALIZE:	return m_SERIALIZE   (t, interp, objc, objv);
    case M_SET:		return m_SET	     (t, interp, objc, objv);
    case M_SIZE:	return m_SIZE	     (t, interp, objc, objv);
    case M_SPLICE:	return m_SPLICE	     (t, interp, objc, objv);
    case M_SWAP:	return m_SWAP	     (t, interp, objc, objv);
    case M_UNSET:	return m_UNSET	     (t, interp, objc, objv);
    case M_WALK:	return m_WALK	     (t, interp, objc, objv);
    case M_WALKPROC:	return m_WALKPROC    (t, interp, objc, objv);
    }
    /* Not coming to this place */
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */