Fixed bug in ckstrdup macro which produced wrong string copies.
1 | /* |
2 | * tclxkeylist.c -- |
3 | * |
4 | * Keyed list support, modified from the original |
5 | * Tcl8.x based TclX and Tcl source. |
6 | * |
7 | * Copyright (c) 1995-2003 America Online Inc. |
8 | * |
9 | */ |
10 | |
11 | static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nsd/tclxkeylist.c,v 1.9 2004/06/24 08:23:52 vasiljevic Exp $, compiled: " __DATE__ " " __TIME__; |
12 | |
13 | #include "nsd.h" |
14 | |
15 | /* |
16 | * tclXkeylist.c -- |
17 | * |
18 | * Extended Tcl keyed list commands and interfaces. |
19 | *----------------------------------------------------------------------------- |
20 | * Copyright 1991-1999 Karl Lehenbauer and Mark Diekhans. |
21 | * |
22 | * Permission to use, copy, modify, and distribute this software and its |
23 | * documentation for any purpose and without fee is hereby granted, provided |
24 | * that the above copyright notice appear in all copies. Karl Lehenbauer and |
25 | * Mark Diekhans make no representations about the suitability of this |
26 | * software for any purpose. It is provided "as is" without express or |
27 | * implied warranty. |
28 | *----------------------------------------------------------------------------- |
29 | * $Id: tclxkeylist.c,v 1.9 2004/06/24 08:23:52 vasiljevic Exp $ |
30 | *----------------------------------------------------------------------------- |
31 | */ |
32 | |
33 | |
34 | /*---------------------------------------------------------------------------*/ |
35 | /*---------------------------------------------------------------------------*/ |
36 | /* Stuff copied from the rest of TclX to avoid dependencies */ |
37 | /*---------------------------------------------------------------------------*/ |
38 | /*---------------------------------------------------------------------------*/ |
39 | |
40 | |
41 | /* #include "tclExtdInt.h" */ |
42 | /* |
43 | * Assert macro for use in TclX. Some GCCs libraries are missing a function |
44 | * used by their macro, so we define out own. |
45 | */ |
46 | #ifdef TCLX_DEBUG |
47 | # define TclX_Assert(expr) ((expr) ? (void)0 : \ |
48 | panic("TclX assertion failure: %s:%d \"%s\"\n",\ |
49 | __FILE__, __LINE__, "expr")) |
50 | #else |
51 | # define TclX_Assert(expr) |
52 | #endif |
53 | |
54 | #define TRUE 1 |
55 | #define FALSE 0 |
56 | |
57 | /* |
58 | * Macro that behaves like strdup, only uses ckalloc. Also macro that does the |
59 | * same with a string that might contain zero bytes, |
60 | */ |
61 | |
62 | #define ckstrdup(a) \ |
63 | (strcpy(ckalloc((size_t)(strlen((a))+1)),(a))) |
64 | |
65 | #define ckbinstrdup(a,b) \ |
66 | ((char*)memcpy(ckalloc((size_t)((b)+1)),(a),(size_t)((b)+1))) |
67 | |
68 | /* |
69 | * Used to return argument messages by most commands. |
70 | */ |
71 | char *tclXWrongArgs = "wrong # args: "; |
72 | |
73 | /* |
74 | * Those are used in <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_IsNullObj">TclX_IsNullObj</a>() in read-only mode |
75 | * therefore no need to mutex protect them (see below). |
76 | */ |
77 | static Tcl_ObjType *listType; |
78 | static Tcl_ObjType *stringType; |
79 | |
80 | /* |
81 | * This is called once from <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_InitInterp">InitInterp</a>() call in tclinit.c |
82 | * for first-time initialization of special Tcl objects. |
83 | */ |
84 | void NsTclInitKeylistType (void) |
85 | { |
86 | listType = Tcl_GetObjType("list"); |
87 | stringType = Tcl_GetObjType("string"); |
88 | } |
89 | |
90 | /*----------------------------------------------------------------------------- |
91 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_WrongArgs">TclX_WrongArgs</a> -- |
92 | * |
93 | * Easily create "wrong # args" error messages. |
94 | * |
95 | * Parameters: |
96 | * o commandNameObj - Object containing name of command (objv[0]) |
97 | * o string - Text message to append. |
98 | * Returns: |
99 | * TCL_ERROR |
100 | *----------------------------------------------------------------------------- |
101 | */ |
102 | int |
103 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_WrongArgs">TclX_WrongArgs</a> (interp, commandNameObj, string) |
104 | Tcl_Interp *interp; |
105 | Tcl_Obj *commandNameObj; |
106 | char *string; |
107 | { |
108 | char *commandName; |
109 | Tcl_Obj *resultPtr = Tcl_GetObjResult (interp); |
110 | int commandLength; |
111 | |
112 | commandName = Tcl_GetStringFromObj (commandNameObj, &commandLength); |
113 | |
114 | Tcl_AppendStringsToObj (resultPtr, |
115 | tclXWrongArgs, |
116 | commandName, |
117 | (char *)NULL); |
118 | |
119 | if (*string != '\0') { |
120 | Tcl_AppendStringsToObj (resultPtr, " ", string, (char *)NULL); |
121 | } |
122 | return TCL_ERROR; |
123 | } |
124 | |
125 | /*----------------------------------------------------------------------------- |
126 | * TclX_AppendObjResult -- |
127 | * |
128 | * Append a variable number of strings onto the object result already |
129 | * present for an interpreter. If the object is shared, the current contents |
130 | * are discarded. |
131 | * |
132 | * Parameters: |
133 | * o interp - Interpreter to set the result in. |
134 | * o args - Strings to append, terminated by a NULL. |
135 | *----------------------------------------------------------------------------- |
136 | */ |
137 | void |
138 | TclX_AppendObjResult TCL_VARARGS_DEF (Tcl_Interp *, arg1) |
139 | { |
140 | Tcl_Interp *interp; |
141 | Tcl_Obj *resultPtr; |
142 | va_list argList; |
143 | char *string; |
144 | |
145 | interp = TCL_VARARGS_START (Tcl_Interp *, arg1, argList); |
146 | resultPtr = Tcl_GetObjResult (interp); |
147 | |
148 | if (Tcl_IsShared(resultPtr)) { |
149 | resultPtr = Tcl_NewStringObj((char *)NULL, 0); |
150 | Tcl_SetObjResult(interp, resultPtr); |
151 | } |
152 | |
153 | TCL_VARARGS_START(Tcl_Interp *,arg1,argList); |
154 | while (1) { |
155 | string = va_arg(argList, char *); |
156 | if (string == NULL) { |
157 | break; |
158 | } |
159 | Tcl_AppendToObj (resultPtr, string, -1); |
160 | } |
161 | va_end(argList); |
162 | } |
163 | |
164 | /*----------------------------------------------------------------------------- |
165 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_IsNullObj">TclX_IsNullObj</a> -- |
166 | * |
167 | * Check if an object is {}, either in list or zero-lemngth string form, with |
168 | * out forcing a conversion. |
169 | * |
170 | * Parameters: |
171 | * o objPtr - Object to check. |
172 | * Returns: |
173 | * True if NULL, FALSE if not. |
174 | *----------------------------------------------------------------------------- |
175 | */ |
176 | int |
177 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_IsNullObj">TclX_IsNullObj</a> (objPtr) |
178 | Tcl_Obj *objPtr; |
179 | { |
180 | int length; |
181 | |
182 | if (objPtr->typePtr == NULL) { |
183 | return (objPtr->length == 0); |
184 | } else { |
185 | if (objPtr->typePtr == listType) { |
186 | Tcl_ListObjLength (NULL, objPtr, &length); |
187 | return (length == 0); |
188 | } else if (objPtr->typePtr == stringType) { |
189 | Tcl_GetStringFromObj (objPtr, &length); |
190 | return (length == 0); |
191 | } |
192 | } |
193 | Tcl_GetStringFromObj (objPtr, &length); |
194 | return (length == 0); |
195 | } |
196 | |
197 | |
198 | /*---------------------------------------------------------------------------*/ |
199 | /*---------------------------------------------------------------------------*/ |
200 | /* Here is the C-API compatibility layer */ |
201 | /* for those who still use it (AOL) */ |
202 | /*---------------------------------------------------------------------------*/ |
203 | /*---------------------------------------------------------------------------*/ |
204 | |
205 | /* |
206 | * ---------------------------------------------------------------------------- |
207 | * - |
208 | * |
209 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_GetKeyedListKeys">Tcl_GetKeyedListKeys</a> -- Retrieve a list of keyes from a keyed list. The list |
210 | * is walked rather than converted to a argv for increased performance. |
211 | * |
212 | * Parameters: o interp (I/O) - Error message will be return in result if there |
213 | * is an error. o subFieldName (I) - If "" or NULL, then the keys are |
214 | * retreved for the top level of the list. If specified, it is name of the |
215 | * field who's subfield keys are to be retrieve. o keyedList (I) - The list |
216 | * to search for the field. o keyesArgcPtr (O) - The number of keys in the |
217 | * keyed list is returned here. o keyesArgvPtr (O) - An argv containing the |
218 | * key names. It is dynamically allocated, containing both the array and the |
219 | * strings. A single call to ckfree will release it. Returns: TCL_OK - If the |
220 | * field was found. TCL_BREAK - If the field was not found. TCL_ERROR - If an |
221 | * error occured. |
222 | * --------------------------------------------------------------------------- |
223 | */ |
224 | |
225 | int |
226 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_GetKeyedListKeys">Tcl_GetKeyedListKeys</a>(interp, subFieldName, keyedList, keyesArgcPtr,keyesArgvPtr) |
227 | Tcl_Interp *interp; |
228 | CONST char *subFieldName; |
229 | CONST char *keyedList; |
230 | int *keyesArgcPtr; |
231 | char ***keyesArgvPtr; |
232 | { |
233 | Tcl_Obj *keylistPtr = Tcl_NewStringObj(keyedList, -1); |
234 | char *keylistKey = (char*)subFieldName; |
235 | |
236 | Tcl_Obj *objValPtr; |
237 | int status; |
238 | |
239 | Tcl_IncrRefCount(keylistPtr); |
240 | |
241 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGetKeys">TclX_KeyedListGetKeys</a>(interp, keylistPtr, keylistKey, &objValPtr); |
242 | |
243 | if (status == TCL_BREAK) { |
244 | if (keyesArgcPtr) { |
245 | *keyesArgcPtr = 0; |
246 | } |
247 | if (keyesArgvPtr) { |
248 | *keyesArgvPtr = NULL; |
249 | } |
250 | } else if (status == TCL_OK) { |
251 | if (keyesArgcPtr && keyesArgvPtr) { |
252 | size_t keySize = 0, totalKeySize = 0; |
253 | int ii, keyCount; |
254 | char **keyArgv, *keyPtr, *nextByte; |
255 | Tcl_Obj **objValues; |
256 | if (Tcl_ListObjGetElements(interp, objValPtr, &keyCount, |
257 | &objValues) != TCL_OK) { |
258 | Tcl_DecrRefCount(keylistPtr); |
259 | return TCL_ERROR; |
260 | } |
261 | for (ii = 0; ii < keyCount; ii++) { |
262 | keyPtr = Tcl_GetStringFromObj(objValues[ii], &keySize); |
263 | totalKeySize += keySize + 1; |
264 | } |
265 | keyArgv = (char**)ckalloc(((keyCount+1)*sizeof(char*))+totalKeySize); |
266 | keyArgv[keyCount] = NULL; |
267 | nextByte = ((char*)keyArgv) + ((keyCount+1) * sizeof(char*)); |
268 | for (ii = 0; ii < keyCount; ii++) { |
269 | keyArgv[ii] = nextByte; |
270 | keyPtr = Tcl_GetStringFromObj(objValues[ii], &keySize); |
271 | strncpy(nextByte, keyPtr, keySize); |
272 | nextByte[keySize] = 0; |
273 | nextByte += keySize + 1; |
274 | } |
275 | *keyesArgcPtr = keyCount; |
276 | *keyesArgvPtr = keyArgv; |
277 | } |
278 | Tcl_DecrRefCount(objValPtr); |
279 | } |
280 | |
281 | Tcl_DecrRefCount(keylistPtr); |
282 | |
283 | return status; |
284 | } |
285 | |
286 | /* |
287 | * ---------------------------------------------------------------------------- |
288 | * - |
289 | * |
290 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_GetKeyedListField">Tcl_GetKeyedListField</a> -- Retrieve a field value from a keyed list. The list |
291 | * is walked rather than converted to a argv for increased performance. This |
292 | * if the name contains sub-fields, this function recursive. |
293 | * |
294 | * Parameters: o interp (I/O) - Error message will be return in result if there |
295 | * is an error. o fieldName (I) - The name of the field to extract. Will |
296 | * recusively process sub-field names seperated by `.'. o keyedList (I) - The |
297 | * list to search for the field. o fieldValuePtr (O) - If the field is found, |
298 | * a pointer to a dynamicly allocated string containing the value is returned |
299 | * here. If NULL is specified, then only the presence of the field is |
300 | * validated, the value is not returned. Returns: TCL_OK - If the field was |
301 | * found. TCL_BREAK - If the field was not found. TCL_ERROR - If an error |
302 | * occured. |
303 | * --------------------------------------------------------------------------- |
304 | * -- */ |
305 | |
306 | int |
307 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_GetKeyedListField">Tcl_GetKeyedListField</a>(interp, fieldName, keyedList, fieldValuePtr) |
308 | Tcl_Interp *interp; |
309 | CONST char *fieldName; |
310 | CONST char *keyedList; |
311 | char **fieldValuePtr; |
312 | { |
313 | Tcl_Obj *keylistPtr = Tcl_NewStringObj(keyedList, -1); |
314 | char *keylistKey = (char*)fieldName; |
315 | |
316 | Tcl_Obj *objValPtr; |
317 | int status; |
318 | |
319 | Tcl_IncrRefCount(keylistPtr); |
320 | |
321 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGet">TclX_KeyedListGet</a>(interp, keylistPtr, keylistKey, &objValPtr); |
322 | |
323 | if (status == TCL_BREAK) { |
324 | if (fieldValuePtr) { |
325 | *fieldValuePtr = NULL; |
326 | } |
327 | } else if (status == TCL_OK) { |
328 | if (fieldValuePtr) { |
329 | size_t valueLen; |
330 | char *keyValue = Tcl_GetStringFromObj(objValPtr, &valueLen); |
331 | char *newValue = strncpy(ckalloc(valueLen + 1), keyValue, valueLen); |
332 | newValue[valueLen] = 0; |
333 | *fieldValuePtr = newValue; |
334 | } |
335 | } |
336 | |
337 | Tcl_DecrRefCount(keylistPtr); |
338 | |
339 | return status; |
340 | } |
341 | |
342 | /* |
343 | * ---------------------------------------------------------------------------- |
344 | * - |
345 | * |
346 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_SetKeyedListField">Tcl_SetKeyedListField</a> -- Set a field value in keyed list. |
347 | * |
348 | * Parameters: o interp (I/O) - Error message will be return in result if there |
349 | * is an error. o fieldName (I) - The name of the field to extract. Will |
350 | * recusively process sub-field names seperated by `.'. o fieldValue (I) - |
351 | * The value to set for the field. o keyedList (I) - The keyed list to set a |
352 | * field value in, may be an NULL or an empty list to create a new keyed |
353 | * list. Returns: A pointer to a dynamically allocated string, or NULL if an |
354 | * error occured. |
355 | * --------------------------------------------------------------------------- |
356 | * -- */ |
357 | |
358 | char * |
359 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_SetKeyedListField">Tcl_SetKeyedListField</a>(interp, fieldName, fieldValue, keyedList) |
360 | Tcl_Interp *interp; |
361 | CONST char *fieldName; |
362 | CONST char *fieldValue; |
363 | CONST char *keyedList; |
364 | { |
365 | Tcl_Obj *keylistPtr = Tcl_NewStringObj(keyedList, -1); |
366 | Tcl_Obj *valuePtr = Tcl_NewStringObj(fieldValue, -1); |
367 | char *keylistKey = (char*)fieldName; |
368 | |
369 | char *listStr, *newList; |
370 | int status; |
371 | size_t listLen; |
372 | |
373 | Tcl_IncrRefCount(keylistPtr); |
374 | Tcl_IncrRefCount(valuePtr); |
375 | |
376 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListSet">TclX_KeyedListSet</a>(interp, keylistPtr, keylistKey, valuePtr); |
377 | |
378 | if (status != TCL_OK) { |
379 | Tcl_DecrRefCount(valuePtr); |
380 | Tcl_DecrRefCount(keylistPtr); |
381 | return NULL; |
382 | } |
383 | |
384 | listStr = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &listLen); |
385 | newList = strncpy(ckalloc(listLen + 1), listStr, listLen); |
386 | listStr[listLen] = 0; |
387 | |
388 | Tcl_DecrRefCount(valuePtr); |
389 | Tcl_DecrRefCount(keylistPtr); |
390 | |
391 | return newList; |
392 | } |
393 | |
394 | /* |
395 | * ---------------------------------------------------------------------------- |
396 | * - |
397 | * |
398 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_DeleteKeyedListField">Tcl_DeleteKeyedListField</a> -- Delete a field value in keyed list. |
399 | * |
400 | * Parameters: o interp (I/O) - Error message will be return in result if there |
401 | * is an error. o fieldName (I) - The name of the field to extract. Will |
402 | * recusively process sub-field names seperated by `.'. o fieldValue (I) - |
403 | * The value to set for the field. o keyedList (I) - The keyed list to delete |
404 | * the field from. Returns: A pointer to a dynamically allocated string |
405 | * containing the new list, or NULL if an error occured. |
406 | * --------------------------------------------------------------------------- |
407 | * -- */ |
408 | |
409 | char * |
410 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_Tcl_DeleteKeyedListField">Tcl_DeleteKeyedListField</a>(interp, fieldName, keyedList) |
411 | Tcl_Interp *interp; |
412 | CONST char *fieldName; |
413 | CONST char *keyedList; |
414 | { |
415 | Tcl_Obj *keylistPtr = Tcl_NewStringObj(keyedList, -1); |
416 | char *keylistKey = (char*)fieldName; |
417 | |
418 | char *listStr, *newList; |
419 | int status; |
420 | size_t listLen; |
421 | |
422 | Tcl_IncrRefCount(keylistPtr); |
423 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListDelete">TclX_KeyedListDelete</a>(interp, keylistPtr, keylistKey); |
424 | |
425 | if (status != TCL_OK) { |
426 | Tcl_DecrRefCount(keylistPtr); |
427 | return NULL; |
428 | } |
429 | |
430 | listStr = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &listLen); |
431 | newList = strncpy(ckalloc(listLen + 1), listStr, listLen); |
432 | listStr[listLen] = 0; |
433 | |
434 | Tcl_DecrRefCount(keylistPtr); |
435 | |
436 | return newList; |
437 | } |
438 | |
439 | /*---------------------------------------------------------------------------*/ |
440 | /*---------------------------------------------------------------------------*/ |
441 | /* Here is where the original file begins */ |
442 | /*---------------------------------------------------------------------------*/ |
443 | /*---------------------------------------------------------------------------*/ |
444 | |
445 | /* |
446 | * Keyed lists are stored as arrays recursively defined objects. The data |
447 | * portion of a keyed list entry is a Tcl_Obj which may be a keyed list object |
448 | * or any other Tcl object. Since determine the structure of a keyed list is |
449 | * lazy (you don't know if an element is data or another keyed list) until it |
450 | * is accessed, the object can be transformed into a keyed list from a Tcl |
451 | * string or list. |
452 | */ |
453 | |
454 | /* |
455 | * An entry in a keyed list array. (FIX: Should key be object?) |
456 | */ |
457 | typedef struct { |
458 | char *key; |
459 | Tcl_Obj *valuePtr; |
460 | } keylEntry_t; |
461 | |
462 | /* |
463 | * Internal representation of a keyed list object. |
464 | */ |
465 | typedef struct { |
466 | int arraySize; /* Current slots available in the array. */ |
467 | int numEntries; /* Number of actual entries in the array. */ |
468 | keylEntry_t *entries; /* Array of keyed list entries. */ |
469 | } keylIntObj_t; |
470 | |
471 | /* |
472 | * Amount to increment array size by when it needs to grow. |
473 | */ |
474 | #define KEYEDLIST_ARRAY_INCR_SIZE 16 |
475 | |
476 | /* |
477 | * Macro to duplicate a child entry of a keyed list if it is share by more |
478 | * than the parent. |
479 | */ |
480 | #define DupSharedKeyListChild(keylIntPtr, idx) \ |
481 | if (Tcl_IsShared (keylIntPtr->entries [idx].valuePtr)) { \ |
482 | keylIntPtr->entries [idx].valuePtr = \ |
483 | Tcl_DuplicateObj (keylIntPtr->entries [idx].valuePtr); \ |
484 | Tcl_IncrRefCount (keylIntPtr->entries [idx].valuePtr); \ |
485 | } |
486 | |
487 | /* |
488 | * Macros to validate an keyed list object or internal representation |
489 | */ |
490 | #ifdef TCLX_DEBUG |
491 | # define KEYL_OBJ_ASSERT(keylAPtr) {\ |
492 | TclX_Assert (keylAPtr->typePtr == &keyedListType); \ |
493 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKeyedList">ValidateKeyedList</a> (keylAIntPtr); \ |
494 | } |
495 | # define KEYL_REP_ASSERT(keylAIntPtr) \ |
496 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKeyedList">ValidateKeyedList</a> (keylAIntPtr) |
497 | #else |
498 | # define KEYL_REP_ASSERT(keylAIntPtr) |
499 | #endif |
500 | |
501 | |
502 | /* |
503 | * Prototypes of internal functions. |
504 | */ |
505 | #ifdef TCLX_DEBUG |
506 | static void |
507 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKeyedList">ValidateKeyedList</a> _ANSI_ARGS_((keylIntObj_t *keylIntPtr)); |
508 | #endif |
509 | |
510 | static int |
511 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> _ANSI_ARGS_((Tcl_Interp *interp, |
512 | char *key, |
513 | int keyLen, |
514 | int isPath)); |
515 | |
516 | static keylIntObj_t * |
517 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_AllocKeyedListIntRep">AllocKeyedListIntRep</a> _ANSI_ARGS_((void)); |
518 | |
519 | static void |
520 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListData">FreeKeyedListData</a> _ANSI_ARGS_((keylIntObj_t *keylIntPtr)); |
521 | |
522 | static void |
523 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_EnsureKeyedListSpace">EnsureKeyedListSpace</a> _ANSI_ARGS_((keylIntObj_t *keylIntPtr, |
524 | int newNumEntries)); |
525 | |
526 | static void |
527 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DeleteKeyedListEntry">DeleteKeyedListEntry</a> _ANSI_ARGS_((keylIntObj_t *keylIntPtr, |
528 | int entryIdx)); |
529 | |
530 | static int |
531 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FindKeyedListEntry">FindKeyedListEntry</a> _ANSI_ARGS_((keylIntObj_t *keylIntPtr, |
532 | char *key, |
533 | int *keyLenPtr, |
534 | char **nextSubKeyPtr)); |
535 | |
536 | static int |
537 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ObjToKeyedListEntry">ObjToKeyedListEntry</a> _ANSI_ARGS_((Tcl_Interp *interp, |
538 | Tcl_Obj *objPtr, |
539 | keylEntry_t *entryPtr)); |
540 | |
541 | static void |
542 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DupKeyedListInternalRep">DupKeyedListInternalRep</a> _ANSI_ARGS_((Tcl_Obj *srcPtr, |
543 | Tcl_Obj *copyPtr)); |
544 | |
545 | static void |
546 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListInternalRep">FreeKeyedListInternalRep</a> _ANSI_ARGS_((Tcl_Obj *keylPtr)); |
547 | |
548 | static int |
549 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_SetKeyedListFromAny">SetKeyedListFromAny</a> _ANSI_ARGS_((Tcl_Interp *interp, |
550 | Tcl_Obj *objPtr)); |
551 | |
552 | static void |
553 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_UpdateStringOfKeyedList">UpdateStringOfKeyedList</a> _ANSI_ARGS_((Tcl_Obj *keylPtr)); |
554 | |
555 | |
556 | int |
557 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylgetObjCmd">TclX_KeylgetObjCmd</a> _ANSI_ARGS_((ClientData clientData, |
558 | Tcl_Interp *interp, |
559 | int objc, |
560 | Tcl_Obj *CONST objv[])); |
561 | |
562 | int |
563 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylsetObjCmd">TclX_KeylsetObjCmd</a> _ANSI_ARGS_((ClientData clientData, |
564 | Tcl_Interp *interp, |
565 | int objc, |
566 | Tcl_Obj *CONST objv[])); |
567 | |
568 | int |
569 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyldelObjCmd">TclX_KeyldelObjCmd</a> _ANSI_ARGS_((ClientData clientData, |
570 | Tcl_Interp *interp, |
571 | int objc, |
572 | Tcl_Obj *CONST objv[])); |
573 | |
574 | int |
575 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylkeysObjCmd">TclX_KeylkeysObjCmd</a> _ANSI_ARGS_((ClientData clientData, |
576 | Tcl_Interp *interp, |
577 | int objc, |
578 | Tcl_Obj *CONST objv[])); |
579 | |
580 | /* |
581 | * Type definition. |
582 | */ |
583 | static Tcl_ObjType keyedListType = { |
584 | "keyedList", /* name */ |
585 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListInternalRep">FreeKeyedListInternalRep</a>, /* freeIntRepProc */ |
586 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DupKeyedListInternalRep">DupKeyedListInternalRep</a>, /* dupIntRepProc */ |
587 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_UpdateStringOfKeyedList">UpdateStringOfKeyedList</a>, /* updateStringProc */ |
588 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_SetKeyedListFromAny">SetKeyedListFromAny</a> /* setFromAnyProc */ |
589 | }; |
590 | |
591 | |
592 | /*----------------------------------------------------------------------------- |
593 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKeyedList">ValidateKeyedList</a> -- |
594 | * Validate a keyed list (only when TCLX_DEBUG is enabled). |
595 | * Parameters: |
596 | * o keylIntPtr - Keyed list internal representation. |
597 | *----------------------------------------------------------------------------- |
598 | */ |
599 | #ifdef TCLX_DEBUG |
600 | static void |
601 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKeyedList">ValidateKeyedList</a> (keylIntPtr) |
602 | keylIntObj_t *keylIntPtr; |
603 | { |
604 | int idx; |
605 | |
606 | TclX_Assert (keylIntPtr->arraySize >= keylIntPtr->numEntries); |
607 | TclX_Assert (keylIntPtr->arraySize >= 0); |
608 | TclX_Assert (keylIntPtr->numEntries >= 0); |
609 | TclX_Assert ((keylIntPtr->arraySize > 0) ? |
610 | (keylIntPtr->entries != NULL) : TRUE); |
611 | TclX_Assert ((keylIntPtr->numEntries > 0) ? |
612 | (keylIntPtr->entries != NULL) : TRUE); |
613 | |
614 | for (idx = 0; idx < keylIntPtr->numEntries; idx++) { |
615 | keylEntry_t *entryPtr = &(keylIntPtr->entries [idx]); |
616 | TclX_Assert (entryPtr->key != NULL); |
617 | TclX_Assert (entryPtr->valuePtr->refCount >= 1); |
618 | if (entryPtr->valuePtr->typePtr == &keyedListType) { |
619 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKeyedList">ValidateKeyedList</a> (entryPtr->valuePtr->internalRep.otherValuePtr); |
620 | } |
621 | } |
622 | } |
623 | #endif |
624 | |
625 | /*----------------------------------------------------------------------------- |
626 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> -- |
627 | * Check that a key or keypath string is a valid value. |
628 | * |
629 | * Parameters: |
630 | * o interp - Used to return error messages. |
631 | * o key - Key string to check. |
632 | * o keyLen - Length of the string, used to check for binary data. |
633 | * o isPath - TRUE if this is a key path, FALSE if its a simple key and |
634 | * thus "." is illegal. |
635 | * Returns: |
636 | * TCL_OK or TCL_ERROR. |
637 | *----------------------------------------------------------------------------- |
638 | */ |
639 | static int |
640 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> (interp, key, keyLen, isPath) |
641 | Tcl_Interp *interp; |
642 | char *key; |
643 | int keyLen; |
644 | int isPath; |
645 | { |
646 | char *keyp; |
647 | |
648 | if (strlen (key) != (size_t) keyLen) { |
649 | Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), |
650 | "keyed list key may not be a ", |
651 | "binary string", (char *) NULL); |
652 | return TCL_ERROR; |
653 | } |
654 | if (key [0] == '\0') { |
655 | Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), |
656 | "keyed list key may not be an ", |
657 | "empty string", (char *) NULL); |
658 | return TCL_ERROR; |
659 | } |
660 | for (keyp = key; *keyp != '\0'; keyp++) { |
661 | if ((!isPath) && (*keyp == '.')) { |
662 | Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), |
663 | "keyed list key may not contain a \".\"; ", |
664 | "it is used as a separator in key paths", |
665 | (char *) NULL); |
666 | return TCL_ERROR; |
667 | } |
668 | } |
669 | return TCL_OK; |
670 | } |
671 | |
672 | |
673 | /*----------------------------------------------------------------------------- |
674 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_AllocKeyedListIntRep">AllocKeyedListIntRep</a> -- |
675 | * Allocate an and initialize the keyed list internal representation. |
676 | * |
677 | * Returns: |
678 | * A pointer to the keyed list internal structure. |
679 | *----------------------------------------------------------------------------- |
680 | */ |
681 | static keylIntObj_t * |
682 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_AllocKeyedListIntRep">AllocKeyedListIntRep</a> () |
683 | { |
684 | keylIntObj_t *keylIntPtr; |
685 | |
686 | keylIntPtr = (keylIntObj_t *) ckalloc (sizeof (keylIntObj_t)); |
687 | |
688 | keylIntPtr->arraySize = 0; |
689 | keylIntPtr->numEntries = 0; |
690 | keylIntPtr->entries = NULL; |
691 | |
692 | return keylIntPtr; |
693 | } |
694 | |
695 | /*----------------------------------------------------------------------------- |
696 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListData">FreeKeyedListData</a> -- |
697 | * Free the internal representation of a keyed list. |
698 | * |
699 | * Parameters: |
700 | * o keylIntPtr - Keyed list internal structure to free. |
701 | *----------------------------------------------------------------------------- |
702 | */ |
703 | static void |
704 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListData">FreeKeyedListData</a> (keylIntPtr) |
705 | keylIntObj_t *keylIntPtr; |
706 | { |
707 | int idx; |
708 | |
709 | for (idx = 0; idx < keylIntPtr->numEntries ; idx++) { |
710 | ckfree (keylIntPtr->entries [idx].key); |
711 | Tcl_DecrRefCount (keylIntPtr->entries [idx].valuePtr); |
712 | } |
713 | if (keylIntPtr->entries != NULL) |
714 | ckfree ((VOID*) keylIntPtr->entries); |
715 | ckfree ((VOID*) keylIntPtr); |
716 | } |
717 | |
718 | /*----------------------------------------------------------------------------- |
719 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_EnsureKeyedListSpace">EnsureKeyedListSpace</a> -- |
720 | * Ensure there is enough room in a keyed list array for a certain number |
721 | * of entries, expanding if necessary. |
722 | * |
723 | * Parameters: |
724 | * o keylIntPtr - Keyed list internal representation. |
725 | * o newNumEntries - The number of entries that are going to be added to |
726 | * the keyed list. |
727 | *----------------------------------------------------------------------------- |
728 | */ |
729 | static void |
730 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_EnsureKeyedListSpace">EnsureKeyedListSpace</a> (keylIntPtr, newNumEntries) |
731 | keylIntObj_t *keylIntPtr; |
732 | int newNumEntries; |
733 | { |
734 | KEYL_REP_ASSERT (keylIntPtr); |
735 | |
736 | if ((keylIntPtr->arraySize - keylIntPtr->numEntries) < newNumEntries) { |
737 | int newSize = keylIntPtr->arraySize + newNumEntries + |
738 | KEYEDLIST_ARRAY_INCR_SIZE; |
739 | if (keylIntPtr->entries == NULL) { |
740 | keylIntPtr->entries = (keylEntry_t *) |
741 | ckalloc (newSize * sizeof (keylEntry_t)); |
742 | } else { |
743 | keylIntPtr->entries = (keylEntry_t *) |
744 | ckrealloc ((VOID *) keylIntPtr->entries, |
745 | newSize * sizeof (keylEntry_t)); |
746 | } |
747 | keylIntPtr->arraySize = newSize; |
748 | } |
749 | |
750 | KEYL_REP_ASSERT (keylIntPtr); |
751 | } |
752 | |
753 | /*----------------------------------------------------------------------------- |
754 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DeleteKeyedListEntry">DeleteKeyedListEntry</a> -- |
755 | * Delete an entry from a keyed list. |
756 | * |
757 | * Parameters: |
758 | * o keylIntPtr - Keyed list internal representation. |
759 | * o entryIdx - Index of entry to delete. |
760 | *----------------------------------------------------------------------------- |
761 | */ |
762 | static void |
763 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DeleteKeyedListEntry">DeleteKeyedListEntry</a> (keylIntPtr, entryIdx) |
764 | keylIntObj_t *keylIntPtr; |
765 | int entryIdx; |
766 | { |
767 | int idx; |
768 | |
769 | ckfree (keylIntPtr->entries [entryIdx].key); |
770 | Tcl_DecrRefCount (keylIntPtr->entries [entryIdx].valuePtr); |
771 | |
772 | for (idx = entryIdx; idx < keylIntPtr->numEntries - 1; idx++) |
773 | keylIntPtr->entries [idx] = keylIntPtr->entries [idx + 1]; |
774 | keylIntPtr->numEntries--; |
775 | |
776 | KEYL_REP_ASSERT (keylIntPtr); |
777 | } |
778 | |
779 | /*----------------------------------------------------------------------------- |
780 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FindKeyedListEntry">FindKeyedListEntry</a> -- |
781 | * Find an entry in keyed list. |
782 | * |
783 | * Parameters: |
784 | * o keylIntPtr - Keyed list internal representation. |
785 | * o key - Name of key to search for. |
786 | * o keyLenPtr - In not NULL, the length of the key for this |
787 | * level is returned here. This excludes subkeys and the `.' delimiters. |
788 | * o nextSubKeyPtr - If not NULL, the start of the name of the next |
789 | * sub-key within key is returned. |
790 | * Returns: |
791 | * Index of the entry or -1 if not found. |
792 | *----------------------------------------------------------------------------- |
793 | */ |
794 | static int |
795 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FindKeyedListEntry">FindKeyedListEntry</a> (keylIntPtr, key, keyLenPtr, nextSubKeyPtr) |
796 | keylIntObj_t *keylIntPtr; |
797 | char *key; |
798 | int *keyLenPtr; |
799 | char **nextSubKeyPtr; |
800 | { |
801 | char *keySeparPtr; |
802 | int keyLen, findIdx; |
803 | |
804 | keySeparPtr = strchr (key, '.'); |
805 | if (keySeparPtr != NULL) { |
806 | keyLen = keySeparPtr - key; |
807 | } else { |
808 | keyLen = strlen (key); |
809 | } |
810 | |
811 | for (findIdx = 0; findIdx < keylIntPtr->numEntries; findIdx++) { |
812 | if ((strncmp (keylIntPtr->entries [findIdx].key, key, |
813 | (size_t)keyLen) == 0) && |
814 | (keylIntPtr->entries [findIdx].key [keyLen] == '\0')) |
815 | break; |
816 | } |
817 | |
818 | if (nextSubKeyPtr != NULL) { |
819 | if (keySeparPtr == NULL) { |
820 | *nextSubKeyPtr = NULL; |
821 | } else { |
822 | *nextSubKeyPtr = keySeparPtr + 1; |
823 | } |
824 | } |
825 | if (keyLenPtr != NULL) { |
826 | *keyLenPtr = keyLen; |
827 | } |
828 | |
829 | if (findIdx >= keylIntPtr->numEntries) { |
830 | return -1; |
831 | } |
832 | |
833 | return findIdx; |
834 | } |
835 | |
836 | /*----------------------------------------------------------------------------- |
837 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ObjToKeyedListEntry">ObjToKeyedListEntry</a> -- |
838 | * Convert an object to a keyed list entry. (Keyword/value pair). |
839 | * |
840 | * Parameters: |
841 | * o interp - Used to return error messages, if not NULL. |
842 | * o objPtr - Object to convert. Each entry must be a two element list, |
843 | * with the first element being the key and the second being the |
844 | * value. |
845 | * o entryPtr - The keyed list entry to initialize from the object. |
846 | * Returns: |
847 | * TCL_OK or TCL_ERROR. |
848 | *----------------------------------------------------------------------------- |
849 | */ |
850 | static int |
851 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ObjToKeyedListEntry">ObjToKeyedListEntry</a> (interp, objPtr, entryPtr) |
852 | Tcl_Interp *interp; |
853 | Tcl_Obj *objPtr; |
854 | keylEntry_t *entryPtr; |
855 | { |
856 | int objc; |
857 | Tcl_Obj **objv; |
858 | char *key; |
859 | int keyLen; |
860 | |
861 | if (Tcl_ListObjGetElements (interp, objPtr, &objc, &objv) != TCL_OK) { |
862 | Tcl_ResetResult (interp); |
863 | Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), |
864 | "keyed list entry not a valid list, ", |
865 | "found \"", |
866 | Tcl_GetStringFromObj (objPtr, NULL), |
867 | "\"", (char *) NULL); |
868 | return TCL_ERROR; |
869 | } |
870 | |
871 | if (objc != 2) { |
872 | Tcl_AppendStringsToObj (Tcl_GetObjResult (interp), |
873 | "keyed list entry must be a two ", |
874 | "element list, found \"", |
875 | Tcl_GetStringFromObj (objPtr, NULL), |
876 | "\"", (char *) NULL); |
877 | return TCL_ERROR; |
878 | } |
879 | |
880 | key = Tcl_GetStringFromObj (objv [0], &keyLen); |
881 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> (interp, key, keyLen, FALSE) == TCL_ERROR) { |
882 | return TCL_ERROR; |
883 | } |
884 | |
885 | entryPtr->key = ckstrdup (key); |
886 | entryPtr->valuePtr = Tcl_DuplicateObj (objv [1]); |
887 | Tcl_IncrRefCount (entryPtr->valuePtr); |
888 | |
889 | return TCL_OK; |
890 | } |
891 | |
892 | /*----------------------------------------------------------------------------- |
893 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListInternalRep">FreeKeyedListInternalRep</a> -- |
894 | * Free the internal representation of a keyed list. |
895 | * |
896 | * Parameters: |
897 | * o keylPtr - Keyed list object being deleted. |
898 | *----------------------------------------------------------------------------- |
899 | */ |
900 | static void |
901 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListInternalRep">FreeKeyedListInternalRep</a> (keylPtr) |
902 | Tcl_Obj *keylPtr; |
903 | { |
904 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListData">FreeKeyedListData</a> ((keylIntObj_t *) keylPtr->internalRep.otherValuePtr); |
905 | } |
906 | |
907 | /*----------------------------------------------------------------------------- |
908 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DupKeyedListInternalRep">DupKeyedListInternalRep</a> -- |
909 | * Duplicate the internal representation of a keyed list. |
910 | * |
911 | * Parameters: |
912 | * o srcPtr - Keyed list object to copy. |
913 | * o copyPtr - Target object to copy internal representation to. |
914 | *----------------------------------------------------------------------------- |
915 | */ |
916 | static void |
917 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DupKeyedListInternalRep">DupKeyedListInternalRep</a> (srcPtr, copyPtr) |
918 | Tcl_Obj *srcPtr; |
919 | Tcl_Obj *copyPtr; |
920 | { |
921 | keylIntObj_t *srcIntPtr = |
922 | (keylIntObj_t *) srcPtr->internalRep.otherValuePtr; |
923 | keylIntObj_t *copyIntPtr; |
924 | int idx; |
925 | |
926 | KEYL_REP_ASSERT (srcIntPtr); |
927 | |
928 | copyIntPtr = (keylIntObj_t *) ckalloc (sizeof (keylIntObj_t)); |
929 | copyIntPtr->arraySize = srcIntPtr->arraySize; |
930 | copyIntPtr->numEntries = srcIntPtr->numEntries; |
931 | copyIntPtr->entries = (keylEntry_t *) |
932 | ckalloc (copyIntPtr->arraySize * sizeof (keylEntry_t)); |
933 | |
934 | for (idx = 0; idx < srcIntPtr->numEntries ; idx++) { |
935 | copyIntPtr->entries [idx].key = |
936 | ckstrdup (srcIntPtr->entries [idx].key); |
937 | copyIntPtr->entries [idx].valuePtr = srcIntPtr->entries [idx].valuePtr; |
938 | Tcl_IncrRefCount (copyIntPtr->entries [idx].valuePtr); |
939 | } |
940 | |
941 | copyPtr->internalRep.otherValuePtr = (VOID *) copyIntPtr; |
942 | copyPtr->typePtr = &keyedListType; |
943 | |
944 | KEYL_REP_ASSERT (copyIntPtr); |
945 | } |
946 | |
947 | /*----------------------------------------------------------------------------- |
948 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_SetKeyedListFromAny">SetKeyedListFromAny</a> -- |
949 | * Convert an object to a keyed list from its string representation. Only |
950 | * the first level is converted, as there is no way of knowing how far down |
951 | * the keyed list recurses until lower levels are accessed. |
952 | * |
953 | * Parameters: |
954 | * o objPtr - Object to convert to a keyed list. |
955 | *----------------------------------------------------------------------------- |
956 | */ |
957 | static int |
958 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_SetKeyedListFromAny">SetKeyedListFromAny</a> (interp, objPtr) |
959 | Tcl_Interp *interp; |
960 | Tcl_Obj *objPtr; |
961 | { |
962 | keylIntObj_t *keylIntPtr; |
963 | int idx, objc; |
964 | Tcl_Obj **objv; |
965 | |
966 | if (Tcl_ListObjGetElements (interp, objPtr, &objc, &objv) != TCL_OK) |
967 | return TCL_ERROR; |
968 | |
969 | keylIntPtr = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_AllocKeyedListIntRep">AllocKeyedListIntRep</a> (); |
970 | |
971 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_EnsureKeyedListSpace">EnsureKeyedListSpace</a> (keylIntPtr, objc); |
972 | |
973 | for (idx = 0; idx < objc; idx++) { |
974 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ObjToKeyedListEntry">ObjToKeyedListEntry</a> (interp, objv [idx], |
975 | &(keylIntPtr->entries [keylIntPtr->numEntries])) != TCL_OK) |
976 | goto errorExit; |
977 | keylIntPtr->numEntries++; |
978 | } |
979 | |
980 | if ((objPtr->typePtr != NULL) && |
981 | (objPtr->typePtr->freeIntRepProc != NULL)) { |
982 | (*objPtr->typePtr->freeIntRepProc) (objPtr); |
983 | } |
984 | objPtr->internalRep.otherValuePtr = (VOID *) keylIntPtr; |
985 | objPtr->typePtr = &keyedListType; |
986 | |
987 | KEYL_REP_ASSERT (keylIntPtr); |
988 | return TCL_OK; |
989 | |
990 | errorExit: |
991 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FreeKeyedListData">FreeKeyedListData</a> (keylIntPtr); |
992 | return TCL_ERROR; |
993 | } |
994 | |
995 | /*----------------------------------------------------------------------------- |
996 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_UpdateStringOfKeyedList">UpdateStringOfKeyedList</a> -- |
997 | * Update the string representation of a keyed list. |
998 | * |
999 | * Parameters: |
1000 | * o objPtr - Object to convert to a keyed list. |
1001 | *----------------------------------------------------------------------------- |
1002 | */ |
1003 | static void |
1004 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_UpdateStringOfKeyedList">UpdateStringOfKeyedList</a> (keylPtr) |
1005 | Tcl_Obj *keylPtr; |
1006 | { |
1007 | #define UPDATE_STATIC_SIZE 32 |
1008 | int idx, strLen; |
1009 | Tcl_Obj **listObjv, *entryObjv [2], *tmpListObj; |
1010 | Tcl_Obj *staticListObjv [UPDATE_STATIC_SIZE]; |
1011 | char *listStr; |
1012 | keylIntObj_t *keylIntPtr = |
1013 | (keylIntObj_t *) keylPtr->internalRep.otherValuePtr; |
1014 | |
1015 | /* |
1016 | * Conversion to strings is done via list objects to support binary data. |
1017 | */ |
1018 | if (keylIntPtr->numEntries > UPDATE_STATIC_SIZE) { |
1019 | listObjv = |
1020 | (Tcl_Obj **) ckalloc (keylIntPtr->numEntries * sizeof (Tcl_Obj *)); |
1021 | } else { |
1022 | listObjv = staticListObjv; |
1023 | } |
1024 | |
1025 | /* |
1026 | * Convert each keyed list entry to a two element list object. No |
1027 | * need to incr/decr ref counts, the list objects will take care of that. |
1028 | * FIX: Keeping key as string object will speed this up. |
1029 | */ |
1030 | for (idx = 0; idx < keylIntPtr->numEntries; idx++) { |
1031 | entryObjv [0] = |
1032 | Tcl_NewStringObj (keylIntPtr->entries [idx].key, |
1033 | (int)strlen (keylIntPtr->entries [idx].key)); |
1034 | entryObjv [1] = keylIntPtr->entries [idx].valuePtr; |
1035 | listObjv [idx] = Tcl_NewListObj (2, entryObjv); |
1036 | } |
1037 | |
1038 | tmpListObj = Tcl_NewListObj (keylIntPtr->numEntries, listObjv); |
1039 | listStr = Tcl_GetStringFromObj (tmpListObj, &strLen); |
1040 | keylPtr->bytes = ckbinstrdup (listStr, strLen); |
1041 | keylPtr->length = strLen; |
1042 | |
1043 | Tcl_DecrRefCount (tmpListObj); |
1044 | if (listObjv != staticListObjv) |
1045 | ckfree ((VOID*) listObjv); |
1046 | } |
1047 | |
1048 | /*----------------------------------------------------------------------------- |
1049 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_NewKeyedListObj">TclX_NewKeyedListObj</a> -- |
1050 | * Create and initialize a new keyed list object. |
1051 | * |
1052 | * Returns: |
1053 | * A pointer to the object. |
1054 | *----------------------------------------------------------------------------- |
1055 | */ |
1056 | Tcl_Obj * |
1057 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_NewKeyedListObj">TclX_NewKeyedListObj</a> () |
1058 | { |
1059 | Tcl_Obj *keylPtr = Tcl_NewObj (); |
1060 | keylIntObj_t *keylIntPtr = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_AllocKeyedListIntRep">AllocKeyedListIntRep</a> (); |
1061 | |
1062 | keylPtr->internalRep.otherValuePtr = (VOID *) keylIntPtr; |
1063 | keylPtr->typePtr = &keyedListType; |
1064 | return keylPtr; |
1065 | } |
1066 | |
1067 | /*----------------------------------------------------------------------------- |
1068 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGet">TclX_KeyedListGet</a> -- |
1069 | * Retrieve a key value from a keyed list. |
1070 | * |
1071 | * Parameters: |
1072 | * o interp - Error message will be return in result if there is an error. |
1073 | * o keylPtr - Keyed list object to get key from. |
1074 | * o key - The name of the key to extract. Will recusively process sub-keys |
1075 | * seperated by `.'. |
1076 | * o valueObjPtrPtr - If the key is found, a pointer to the key object |
1077 | * is returned here. NULL is returned if the key is not present. |
1078 | * Returns: |
1079 | * o TCL_OK - If the key value was returned. |
1080 | * o TCL_BREAK - If the key was not found. |
1081 | * o TCL_ERROR - If an error occured. |
1082 | *----------------------------------------------------------------------------- |
1083 | */ |
1084 | int |
1085 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGet">TclX_KeyedListGet</a> (interp, keylPtr, key, valuePtrPtr) |
1086 | Tcl_Interp *interp; |
1087 | Tcl_Obj *keylPtr; |
1088 | char *key; |
1089 | Tcl_Obj **valuePtrPtr; |
1090 | { |
1091 | keylIntObj_t *keylIntPtr; |
1092 | char *nextSubKey; |
1093 | int findIdx; |
1094 | |
1095 | if (Tcl_ConvertToType (interp, keylPtr, &keyedListType) != TCL_OK) |
1096 | return TCL_ERROR; |
1097 | keylIntPtr = (keylIntObj_t *) keylPtr->internalRep.otherValuePtr; |
1098 | KEYL_REP_ASSERT (keylIntPtr); |
1099 | |
1100 | findIdx = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FindKeyedListEntry">FindKeyedListEntry</a> (keylIntPtr, key, NULL, &nextSubKey); |
1101 | |
1102 | /* |
1103 | * If not found, return status. |
1104 | */ |
1105 | if (findIdx < 0) { |
1106 | *valuePtrPtr = NULL; |
1107 | return TCL_BREAK; |
1108 | } |
1109 | |
1110 | /* |
1111 | * If we are at the last subkey, return the entry, otherwise recurse |
1112 | * down looking for the entry. |
1113 | */ |
1114 | if (nextSubKey == NULL) { |
1115 | *valuePtrPtr = keylIntPtr->entries [findIdx].valuePtr; |
1116 | return TCL_OK; |
1117 | } else { |
1118 | return <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGet">TclX_KeyedListGet</a> (interp, |
1119 | keylIntPtr->entries [findIdx].valuePtr, |
1120 | nextSubKey, |
1121 | valuePtrPtr); |
1122 | } |
1123 | } |
1124 | |
1125 | /*----------------------------------------------------------------------------- |
1126 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListSet">TclX_KeyedListSet</a> -- |
1127 | * Set a key value in keyed list object. |
1128 | * |
1129 | * Parameters: |
1130 | * o interp - Error message will be return in result object. |
1131 | * o keylPtr - Keyed list object to update. |
1132 | * o key - The name of the key to extract. Will recusively process |
1133 | * sub-key seperated by `.'. |
1134 | * o valueObjPtr - The value to set for the key. |
1135 | * Returns: |
1136 | * TCL_OK or TCL_ERROR. |
1137 | *----------------------------------------------------------------------------- |
1138 | */ |
1139 | int |
1140 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListSet">TclX_KeyedListSet</a> (interp, keylPtr, key, valuePtr) |
1141 | Tcl_Interp *interp; |
1142 | Tcl_Obj *keylPtr; |
1143 | char *key; |
1144 | Tcl_Obj *valuePtr; |
1145 | { |
1146 | keylIntObj_t *keylIntPtr; |
1147 | char *nextSubKey; |
1148 | int findIdx, keyLen, status; |
1149 | Tcl_Obj *newKeylPtr; |
1150 | |
1151 | if (Tcl_ConvertToType (interp, keylPtr, &keyedListType) != TCL_OK) |
1152 | return TCL_ERROR; |
1153 | keylIntPtr = (keylIntObj_t *) keylPtr->internalRep.otherValuePtr; |
1154 | KEYL_REP_ASSERT (keylIntPtr); |
1155 | |
1156 | findIdx = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FindKeyedListEntry">FindKeyedListEntry</a> (keylIntPtr, key, |
1157 | &keyLen, &nextSubKey); |
1158 | |
1159 | /* |
1160 | * If we are at the last subkey, either update or add an entry. |
1161 | */ |
1162 | if (nextSubKey == NULL) { |
1163 | if (findIdx < 0) { |
1164 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_EnsureKeyedListSpace">EnsureKeyedListSpace</a> (keylIntPtr, 1); |
1165 | findIdx = keylIntPtr->numEntries; |
1166 | keylIntPtr->numEntries++; |
1167 | } else { |
1168 | ckfree (keylIntPtr->entries [findIdx].key); |
1169 | Tcl_DecrRefCount (keylIntPtr->entries [findIdx].valuePtr); |
1170 | } |
1171 | keylIntPtr->entries [findIdx].key = |
1172 | (char *) ckalloc ((size_t)(keyLen + 1)); |
1173 | strncpy (keylIntPtr->entries [findIdx].key, key, (size_t)keyLen); |
1174 | keylIntPtr->entries [findIdx].key [keyLen] = '\0'; |
1175 | keylIntPtr->entries [findIdx].valuePtr = valuePtr; |
1176 | Tcl_IncrRefCount (valuePtr); |
1177 | Tcl_InvalidateStringRep (keylPtr); |
1178 | |
1179 | KEYL_REP_ASSERT (keylIntPtr); |
1180 | return TCL_OK; |
1181 | } |
1182 | |
1183 | /* |
1184 | * If we are not at the last subkey, recurse down, creating new |
1185 | * entries if neccessary. If this level key was not found, it |
1186 | * means we must build new subtree. Don't insert the new tree until we |
1187 | * come back without error. |
1188 | */ |
1189 | if (findIdx >= 0) { |
1190 | DupSharedKeyListChild (keylIntPtr, findIdx); |
1191 | status = |
1192 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListSet">TclX_KeyedListSet</a> (interp, |
1193 | keylIntPtr->entries [findIdx].valuePtr, |
1194 | nextSubKey, valuePtr); |
1195 | if (status == TCL_OK) { |
1196 | Tcl_InvalidateStringRep (keylPtr); |
1197 | } |
1198 | |
1199 | KEYL_REP_ASSERT (keylIntPtr); |
1200 | return status; |
1201 | } else { |
1202 | newKeylPtr = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_NewKeyedListObj">TclX_NewKeyedListObj</a> (); |
1203 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListSet">TclX_KeyedListSet</a> (interp, newKeylPtr, |
1204 | nextSubKey, valuePtr) != TCL_OK) { |
1205 | Tcl_DecrRefCount (newKeylPtr); |
1206 | return TCL_ERROR; |
1207 | } |
1208 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_EnsureKeyedListSpace">EnsureKeyedListSpace</a> (keylIntPtr, 1); |
1209 | findIdx = keylIntPtr->numEntries++; |
1210 | keylIntPtr->entries [findIdx].key = |
1211 | (char *) ckalloc ((size_t)(keyLen + 1)); |
1212 | strncpy (keylIntPtr->entries [findIdx].key, key, (size_t)keyLen); |
1213 | keylIntPtr->entries [findIdx].key [keyLen] = '\0'; |
1214 | keylIntPtr->entries [findIdx].valuePtr = newKeylPtr; |
1215 | Tcl_IncrRefCount (newKeylPtr); |
1216 | Tcl_InvalidateStringRep (keylPtr); |
1217 | |
1218 | KEYL_REP_ASSERT (keylIntPtr); |
1219 | return TCL_OK; |
1220 | } |
1221 | } |
1222 | |
1223 | /*----------------------------------------------------------------------------- |
1224 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListDelete">TclX_KeyedListDelete</a> -- |
1225 | * Delete a key value from keyed list. |
1226 | * |
1227 | * Parameters: |
1228 | * o interp - Error message will be return in result if there is an error. |
1229 | * o keylPtr - Keyed list object to update. |
1230 | * o key - The name of the key to extract. Will recusively process |
1231 | * sub-key seperated by `.'. |
1232 | * Returns: |
1233 | * o TCL_OK - If the key was deleted. |
1234 | * o TCL_BREAK - If the key was not found. |
1235 | * o TCL_ERROR - If an error occured. |
1236 | *----------------------------------------------------------------------------- |
1237 | */ |
1238 | int |
1239 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListDelete">TclX_KeyedListDelete</a> (interp, keylPtr, key) |
1240 | Tcl_Interp *interp; |
1241 | Tcl_Obj *keylPtr; |
1242 | char *key; |
1243 | { |
1244 | keylIntObj_t *keylIntPtr, *subKeylIntPtr; |
1245 | char *nextSubKey; |
1246 | int findIdx, status; |
1247 | |
1248 | if (Tcl_ConvertToType (interp, keylPtr, &keyedListType) != TCL_OK) |
1249 | return TCL_ERROR; |
1250 | keylIntPtr = (keylIntObj_t *) keylPtr->internalRep.otherValuePtr; |
1251 | |
1252 | findIdx = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FindKeyedListEntry">FindKeyedListEntry</a> (keylIntPtr, key, NULL, &nextSubKey); |
1253 | |
1254 | /* |
1255 | * If not found, return status. |
1256 | */ |
1257 | if (findIdx < 0) { |
1258 | KEYL_REP_ASSERT (keylIntPtr); |
1259 | return TCL_BREAK; |
1260 | } |
1261 | |
1262 | /* |
1263 | * If we are at the last subkey, delete the entry. |
1264 | */ |
1265 | if (nextSubKey == NULL) { |
1266 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DeleteKeyedListEntry">DeleteKeyedListEntry</a> (keylIntPtr, findIdx); |
1267 | Tcl_InvalidateStringRep (keylPtr); |
1268 | |
1269 | KEYL_REP_ASSERT (keylIntPtr); |
1270 | return TCL_OK; |
1271 | } |
1272 | |
1273 | /* |
1274 | * If we are not at the last subkey, recurse down. If the entry is |
1275 | * deleted and the sub-keyed list is empty, delete it as well. Must |
1276 | * invalidate string, as it caches all representations below it. |
1277 | */ |
1278 | DupSharedKeyListChild (keylIntPtr, findIdx); |
1279 | |
1280 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListDelete">TclX_KeyedListDelete</a> (interp, |
1281 | keylIntPtr->entries [findIdx].valuePtr, |
1282 | nextSubKey); |
1283 | if (status == TCL_OK) { |
1284 | subKeylIntPtr = (keylIntObj_t *) |
1285 | keylIntPtr->entries [findIdx].valuePtr->internalRep.otherValuePtr; |
1286 | if (subKeylIntPtr->numEntries == 0) { |
1287 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_DeleteKeyedListEntry">DeleteKeyedListEntry</a> (keylIntPtr, findIdx); |
1288 | } |
1289 | Tcl_InvalidateStringRep (keylPtr); |
1290 | } |
1291 | |
1292 | KEYL_REP_ASSERT (keylIntPtr); |
1293 | return status; |
1294 | } |
1295 | |
1296 | /*----------------------------------------------------------------------------- |
1297 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGetKeys">TclX_KeyedListGetKeys</a> -- |
1298 | * Retrieve a list of keyed list keys. |
1299 | * |
1300 | * Parameters: |
1301 | * o interp - Error message will be return in result if there is an error. |
1302 | * o keylPtr - Keyed list object to get key from. |
1303 | * o key - The name of the key to get the sub keys for. NULL or empty |
1304 | * to retrieve all top level keys. |
1305 | * o listObjPtrPtr - List object is returned here with key as values. |
1306 | * Returns: |
1307 | * o TCL_OK - If the zero or more key where returned. |
1308 | * o TCL_BREAK - If the key was not found. |
1309 | * o TCL_ERROR - If an error occured. |
1310 | *----------------------------------------------------------------------------- |
1311 | */ |
1312 | int |
1313 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGetKeys">TclX_KeyedListGetKeys</a> (interp, keylPtr, key, listObjPtrPtr) |
1314 | Tcl_Interp *interp; |
1315 | Tcl_Obj *keylPtr; |
1316 | char *key; |
1317 | Tcl_Obj **listObjPtrPtr; |
1318 | { |
1319 | keylIntObj_t *keylIntPtr; |
1320 | Tcl_Obj *nameObjPtr, *listObjPtr; |
1321 | char *nextSubKey; |
1322 | int idx, findIdx; |
1323 | |
1324 | if (Tcl_ConvertToType (interp, keylPtr, &keyedListType) != TCL_OK) |
1325 | return TCL_ERROR; |
1326 | keylIntPtr = (keylIntObj_t *) keylPtr->internalRep.otherValuePtr; |
1327 | |
1328 | /* |
1329 | * If key is not NULL or empty, then recurse down until we go past |
1330 | * the end of all of the elements of the key. |
1331 | */ |
1332 | if ((key != NULL) && (key [0] != '\0')) { |
1333 | findIdx = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_FindKeyedListEntry">FindKeyedListEntry</a> (keylIntPtr, key, NULL, &nextSubKey); |
1334 | if (findIdx < 0) { |
1335 | TclX_Assert (keylIntPtr->arraySize >= keylIntPtr->numEntries); |
1336 | return TCL_BREAK; |
1337 | } |
1338 | TclX_Assert (keylIntPtr->arraySize >= keylIntPtr->numEntries); |
1339 | return <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGetKeys">TclX_KeyedListGetKeys</a> (interp, |
1340 | keylIntPtr->entries [findIdx].valuePtr, |
1341 | nextSubKey, |
1342 | listObjPtrPtr); |
1343 | } |
1344 | |
1345 | /* |
1346 | * Reached the end of the full key, return all keys at this level. |
1347 | */ |
1348 | listObjPtr = Tcl_NewListObj (0, NULL); |
1349 | for (idx = 0; idx < keylIntPtr->numEntries; idx++) { |
1350 | nameObjPtr = Tcl_NewStringObj (keylIntPtr->entries [idx].key, |
1351 | -1); |
1352 | if (Tcl_ListObjAppendElement (interp, listObjPtr, |
1353 | nameObjPtr) != TCL_OK) { |
1354 | Tcl_DecrRefCount (nameObjPtr); |
1355 | Tcl_DecrRefCount (listObjPtr); |
1356 | return TCL_ERROR; |
1357 | } |
1358 | } |
1359 | *listObjPtrPtr = listObjPtr; |
1360 | TclX_Assert (keylIntPtr->arraySize >= keylIntPtr->numEntries); |
1361 | return TCL_OK; |
1362 | } |
1363 | |
1364 | /*----------------------------------------------------------------------------- |
1365 | * Tcl_KeylgetObjCmd -- |
1366 | * Implements the TCL keylget command: |
1367 | * keylget listvar ?key? ?retvar | {}? |
1368 | *----------------------------------------------------------------------------- |
1369 | */ |
1370 | int |
1371 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylgetObjCmd">TclX_KeylgetObjCmd</a> (clientData, interp, objc, objv) |
1372 | ClientData clientData; |
1373 | Tcl_Interp *interp; |
1374 | int objc; |
1375 | Tcl_Obj *CONST objv[]; |
1376 | { |
1377 | Tcl_Obj *keylPtr, *valuePtr; |
1378 | char *varName, *key; |
1379 | int keyLen, status; |
1380 | |
1381 | if ((objc < 2) || (objc > 4)) { |
1382 | return <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_WrongArgs">TclX_WrongArgs</a> (interp, objv [0], |
1383 | "listvar ?key? ?retvar | {}?"); |
1384 | } |
1385 | varName = Tcl_GetStringFromObj (objv [1], NULL); |
1386 | |
1387 | /* |
1388 | * Handle request for list of keys, use keylkeys command. |
1389 | */ |
1390 | if (objc == 2) |
1391 | return <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylkeysObjCmd">TclX_KeylkeysObjCmd</a> (clientData, interp, objc, objv); |
1392 | |
1393 | keylPtr = Tcl_GetVar2Ex(interp, varName, NULL, |
1394 | TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG); |
1395 | if (keylPtr == NULL) { |
1396 | return TCL_ERROR; |
1397 | } |
1398 | |
1399 | /* |
1400 | * Handle retrieving a value for a specified key. |
1401 | */ |
1402 | key = Tcl_GetStringFromObj (objv [2], &keyLen); |
1403 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> (interp, key, keyLen, TRUE) == TCL_ERROR) { |
1404 | return TCL_ERROR; |
1405 | } |
1406 | |
1407 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGet">TclX_KeyedListGet</a> (interp, keylPtr, key, &valuePtr); |
1408 | if (status == TCL_ERROR) |
1409 | return TCL_ERROR; |
1410 | |
1411 | /* |
1412 | * Handle key not found. |
1413 | */ |
1414 | if (status == TCL_BREAK) { |
1415 | if (objc == 3) { |
1416 | TclX_AppendObjResult (interp, "key \"", key, |
1417 | "\" not found in keyed list", |
1418 | (char *) NULL); |
1419 | return TCL_ERROR; |
1420 | } else { |
1421 | Tcl_SetBooleanObj (Tcl_GetObjResult (interp), FALSE); |
1422 | return TCL_OK; |
1423 | } |
1424 | } |
1425 | |
1426 | /* |
1427 | * No variable specified, so return value in the result. |
1428 | */ |
1429 | if (objc == 3) { |
1430 | Tcl_SetObjResult (interp, valuePtr); |
1431 | return TCL_OK; |
1432 | } |
1433 | |
1434 | /* |
1435 | * Variable (or empty variable name) specified. |
1436 | */ |
1437 | if (!<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_IsNullObj">TclX_IsNullObj</a> (objv [3])) { |
1438 | if (Tcl_SetVar2Ex(interp, Tcl_GetStringFromObj(objv [3], NULL), NULL, |
1439 | valuePtr, TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG) == NULL) |
1440 | return TCL_ERROR; |
1441 | } |
1442 | Tcl_SetBooleanObj (Tcl_GetObjResult (interp), TRUE); |
1443 | return TCL_OK; |
1444 | } |
1445 | |
1446 | /*----------------------------------------------------------------------------- |
1447 | * Tcl_KeylsetObjCmd -- |
1448 | * Implements the TCL keylset command: |
1449 | * keylset listvar key value ?key value...? |
1450 | *----------------------------------------------------------------------------- |
1451 | */ |
1452 | int |
1453 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylsetObjCmd">TclX_KeylsetObjCmd</a> (clientData, interp, objc, objv) |
1454 | ClientData clientData; |
1455 | Tcl_Interp *interp; |
1456 | int objc; |
1457 | Tcl_Obj *CONST objv[]; |
1458 | { |
1459 | Tcl_Obj *keylVarPtr, *newVarObj; |
1460 | char *varName, *key; |
1461 | int idx, keyLen; |
1462 | |
1463 | if ((objc < 4) || ((objc % 2) != 0)) { |
1464 | return <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_WrongArgs">TclX_WrongArgs</a> (interp, objv [0], |
1465 | "listvar key value ?key value...?"); |
1466 | } |
1467 | varName = Tcl_GetStringFromObj (objv [1], NULL); |
1468 | |
1469 | /* |
1470 | * Get the variable that we are going to update. If the var doesn't exist, |
1471 | * create it. If it is shared by more than being a variable, duplicated |
1472 | * it. |
1473 | */ |
1474 | keylVarPtr = Tcl_GetVar2Ex(interp, varName, NULL, TCL_PARSE_PART1); |
1475 | if ((keylVarPtr == NULL) || (Tcl_IsShared (keylVarPtr))) { |
1476 | if (keylVarPtr == NULL) { |
1477 | keylVarPtr = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_NewKeyedListObj">TclX_NewKeyedListObj</a> (); |
1478 | } else { |
1479 | keylVarPtr = Tcl_DuplicateObj (keylVarPtr); |
1480 | } |
1481 | newVarObj = keylVarPtr; |
1482 | } else { |
1483 | newVarObj = NULL; |
1484 | } |
1485 | |
1486 | for (idx = 2; idx < objc; idx += 2) { |
1487 | key = Tcl_GetStringFromObj (objv [idx], &keyLen); |
1488 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> (interp, key, keyLen, TRUE) == TCL_ERROR) { |
1489 | goto errorExit; |
1490 | } |
1491 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListSet">TclX_KeyedListSet</a> (interp, keylVarPtr, key, objv [idx+1]) != TCL_OK) { |
1492 | goto errorExit; |
1493 | } |
1494 | } |
1495 | |
1496 | if (Tcl_SetVar2Ex(interp, varName, NULL, keylVarPtr, |
1497 | TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG) == NULL) { |
1498 | goto errorExit; |
1499 | } |
1500 | |
1501 | return TCL_OK; |
1502 | |
1503 | errorExit: |
1504 | if (newVarObj != NULL) { |
1505 | Tcl_DecrRefCount (newVarObj); |
1506 | } |
1507 | return TCL_ERROR; |
1508 | } |
1509 | |
1510 | /*----------------------------------------------------------------------------- |
1511 | * Tcl_KeyldelObjCmd -- |
1512 | * Implements the TCL keyldel command: |
1513 | * keyldel listvar key ?key ...? |
1514 | *---------------------------------------------------------------------------- |
1515 | */ |
1516 | int |
1517 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyldelObjCmd">TclX_KeyldelObjCmd</a> (clientData, interp, objc, objv) |
1518 | ClientData clientData; |
1519 | Tcl_Interp *interp; |
1520 | int objc; |
1521 | Tcl_Obj *CONST objv[]; |
1522 | { |
1523 | Tcl_Obj *keylVarPtr, *keylPtr; |
1524 | char *varName, *key; |
1525 | int idx, keyLen, status; |
1526 | |
1527 | if (objc < 3) { |
1528 | return <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_WrongArgs">TclX_WrongArgs</a> (interp, objv [0], "listvar key ?key ...?"); |
1529 | } |
1530 | varName = Tcl_GetStringFromObj (objv [1], NULL); |
1531 | |
1532 | /* |
1533 | * Get the variable that we are going to update. If it is shared by more |
1534 | * than being a variable, duplicated it. |
1535 | */ |
1536 | keylVarPtr = Tcl_GetVar2Ex(interp, varName, NULL, |
1537 | TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG); |
1538 | if (keylVarPtr == NULL) { |
1539 | return TCL_ERROR; |
1540 | } |
1541 | if (Tcl_IsShared (keylVarPtr)) { |
1542 | keylPtr = Tcl_DuplicateObj (keylVarPtr); |
1543 | keylVarPtr = Tcl_SetVar2Ex(interp, varName, NULL, keylPtr, |
1544 | TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG); |
1545 | if (keylVarPtr == NULL) { |
1546 | Tcl_DecrRefCount (keylPtr); |
1547 | return TCL_ERROR; |
1548 | } |
1549 | if (keylVarPtr != keylPtr) |
1550 | Tcl_DecrRefCount (keylPtr); |
1551 | } |
1552 | keylPtr = keylVarPtr; |
1553 | |
1554 | for (idx = 2; idx < objc; idx++) { |
1555 | key = Tcl_GetStringFromObj (objv [idx], &keyLen); |
1556 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> (interp, key, keyLen, TRUE) == TCL_ERROR) { |
1557 | return TCL_ERROR; |
1558 | } |
1559 | |
1560 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListDelete">TclX_KeyedListDelete</a> (interp, keylPtr, key); |
1561 | switch (status) { |
1562 | case TCL_BREAK: |
1563 | TclX_AppendObjResult (interp, "key not found: \"", |
1564 | key, "\"", (char *) NULL); |
1565 | return TCL_ERROR; |
1566 | case TCL_ERROR: |
1567 | return TCL_ERROR; |
1568 | } |
1569 | } |
1570 | |
1571 | return TCL_OK; |
1572 | } |
1573 | |
1574 | /*----------------------------------------------------------------------------- |
1575 | * Tcl_KeylkeysObjCmd -- |
1576 | * Implements the TCL keylkeys command: |
1577 | * keylkeys listvar ?key? |
1578 | *----------------------------------------------------------------------------- |
1579 | */ |
1580 | int |
1581 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylkeysObjCmd">TclX_KeylkeysObjCmd</a> (clientData, interp, objc, objv) |
1582 | ClientData clientData; |
1583 | Tcl_Interp *interp; |
1584 | int objc; |
1585 | Tcl_Obj *CONST objv[]; |
1586 | { |
1587 | Tcl_Obj *keylPtr, *listObjPtr; |
1588 | char *varName, *key; |
1589 | int keyLen, status; |
1590 | |
1591 | if ((objc < 2) || (objc > 3)) { |
1592 | return <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_WrongArgs">TclX_WrongArgs</a> (interp, objv [0], "listvar ?key?"); |
1593 | } |
1594 | varName = Tcl_GetStringFromObj (objv [1], NULL); |
1595 | |
1596 | keylPtr = Tcl_GetVar2Ex(interp, varName, NULL, |
1597 | TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG); |
1598 | if (keylPtr == NULL) { |
1599 | return TCL_ERROR; |
1600 | } |
1601 | |
1602 | /* |
1603 | * If key argument is not specified, then objv [2] is NULL or empty, |
1604 | * meaning get top level keys. |
1605 | */ |
1606 | if (objc < 3) { |
1607 | key = NULL; |
1608 | } else { |
1609 | key = Tcl_GetStringFromObj (objv [2], &keyLen); |
1610 | if (<a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_ValidateKey">ValidateKey</a> (interp, key, keyLen, TRUE) == TCL_ERROR) { |
1611 | return TCL_ERROR; |
1612 | } |
1613 | } |
1614 | |
1615 | status = <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListGetKeys">TclX_KeyedListGetKeys</a> (interp, keylPtr, key, &listObjPtr); |
1616 | switch (status) { |
1617 | case TCL_BREAK: |
1618 | TclX_AppendObjResult (interp, "key not found: \"", key, "\"", |
1619 | (char *) NULL); |
1620 | return TCL_ERROR; |
1621 | case TCL_ERROR: |
1622 | return TCL_ERROR; |
1623 | } |
1624 | |
1625 | Tcl_SetObjResult (interp, listObjPtr); |
1626 | |
1627 | return TCL_OK; |
1628 | } |
1629 | |
1630 | /*----------------------------------------------------------------------------- |
1631 | * <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListInit">TclX_KeyedListInit</a> -- |
1632 | * Initialize the keyed list commands for this interpreter. |
1633 | * |
1634 | * Parameters: |
1635 | * o interp - Interpreter to add commands to. |
1636 | *----------------------------------------------------------------------------- |
1637 | */ |
1638 | void |
1639 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyedListInit">TclX_KeyedListInit</a> (interp) |
1640 | Tcl_Interp *interp; |
1641 | { |
1642 | Tcl_RegisterObjType (&keyedListType); |
1643 | |
1644 | Tcl_CreateObjCommand (interp, |
1645 | "keylget", |
1646 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylgetObjCmd">TclX_KeylgetObjCmd</a>, |
1647 | (ClientData) NULL, |
1648 | (Tcl_CmdDeleteProc*) NULL); |
1649 | |
1650 | Tcl_CreateObjCommand (interp, |
1651 | "keylset", |
1652 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylsetObjCmd">TclX_KeylsetObjCmd</a>, |
1653 | (ClientData) NULL, |
1654 | (Tcl_CmdDeleteProc*) NULL); |
1655 | |
1656 | Tcl_CreateObjCommand (interp, |
1657 | "keyldel", |
1658 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeyldelObjCmd">TclX_KeyldelObjCmd</a>, |
1659 | (ClientData) NULL, |
1660 | (Tcl_CmdDeleteProc*) NULL); |
1661 | |
1662 | Tcl_CreateObjCommand (interp, |
1663 | "keylkeys", |
1664 | <a href="/cvs/aolserver/aolserver/nsd/tclxkeylist.c#A_TclX_KeylkeysObjCmd">TclX_KeylkeysObjCmd</a>, |
1665 | (ClientData) NULL, |
1666 | (Tcl_CmdDeleteProc*) NULL); |
1667 | } |
1668 |
Copyright © 2010 Geeknet, Inc. All rights reserved. Terms of Use