There are no available options for this view.

Parent Directory Parent Directory | Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a> Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a>

Revision 1.9 - (show annotations) (download) (as text)
Thu Jun 24 08:23:52 2004 UTC (13 years, 6 months ago) by vasiljevic
Branch: MAIN
CVS Tags: aolserver_v45_r0, aolserver_v45_r2_rc0, HEAD
Branch point for: aolserver_v45_r1, aolserver_v45_r2, aolserver_v45_bp
Changes since 1.8: +14 -15 lines
File MIME type: text/x-chdr
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