Applied patches from Stephen Deasey for better compile time error checking.
1 | /* |
2 | * The contents of this file are subject to the AOLserver Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://aolserver.com/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | /* |
31 | * tclvar.c -- |
32 | * |
33 | * Support for the old ns_var and new nsv_* commands. |
34 | */ |
35 | |
36 | #include "nsd.h" |
37 | |
38 | static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nsd/tclvar.c,v 1.17 2005/08/23 21:41:31 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__; |
39 | |
40 | /* |
41 | * The following structure defines a collection of arrays. |
42 | * Only the arrays within a given bucket share a lock, |
43 | * allowing for more concurency in nsv. |
44 | */ |
45 | |
46 | typedef struct Bucket { |
47 | Ns_Mutex lock; |
48 | Tcl_HashTable arrays; |
49 | } Bucket; |
50 | |
51 | /* |
52 | * The following structure maintains the context for each variable |
53 | * array. |
54 | */ |
55 | |
56 | typedef struct Array { |
57 | Bucket *bucketPtr; /* Array bucket. */ |
58 | Tcl_HashEntry *entryPtr; /* Entry in bucket array table. */ |
59 | Tcl_HashTable vars; /* Table of variables. */ |
60 | } Array; |
61 | |
62 | /* |
63 | * Forward declarations for coommands and routines defined in this file. |
64 | */ |
65 | |
66 | static void <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_SetVar">SetVar</a>(Array *, Tcl_Obj *key, Tcl_Obj *value); |
67 | static void <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_UpdateVar">UpdateVar</a>(Tcl_HashEntry *hPtr, Tcl_Obj *obj); |
68 | static void <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_FlushArray">FlushArray</a>(Array *arrayPtr); |
69 | static Array *<a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(void *arg, Tcl_Interp *interp, Tcl_Obj *array, |
70 | int create); |
71 | #define UnlockArray(arrayPtr) \ |
72 | Ns_MutexUnlock(&((arrayPtr)->bucketPtr->lock)); |
73 | |
74 | |
75 | /* |
76 | *---------------------------------------------------------------------- |
77 | * |
78 | * NsTclNsvCreateBuckets -- |
79 | * |
80 | * Create a new array of buckets for a server. |
81 | * |
82 | * Results: |
83 | * Pointer to bucket array. |
84 | * |
85 | * Side effects: |
86 | * None. |
87 | * |
88 | *---------------------------------------------------------------------- |
89 | */ |
90 | |
91 | struct Bucket * |
92 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclCreateBuckets">NsTclCreateBuckets</a>(char *server, int n) |
93 | { |
94 | char buf[NS_THREAD_NAMESIZE]; |
95 | Bucket *buckets; |
96 | |
97 | buckets = ns_malloc(sizeof(Bucket) * n); |
98 | while (--n >= 0) { |
99 | sprintf(buf, "nsv:%d", n); |
100 | Tcl_InitHashTable(&buckets[n].arrays, TCL_STRING_KEYS); |
101 | Ns_MutexInit(&buckets[n].lock); |
102 | Ns_MutexSetName2(&buckets[n].lock, buf, server); |
103 | } |
104 | return buckets; |
105 | } |
106 | |
107 | |
108 | /* |
109 | *---------------------------------------------------------------------- |
110 | * |
111 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvGetObjCmd">NsTclNsvGetObjCmd</a> -- |
112 | * |
113 | * Implements nsv_get. |
114 | * |
115 | * Results: |
116 | * Tcl result. |
117 | * |
118 | * Side effects: |
119 | * See docs. |
120 | * |
121 | *---------------------------------------------------------------------- |
122 | */ |
123 | |
124 | int |
125 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvGetObjCmd">NsTclNsvGetObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
126 | { |
127 | Tcl_HashEntry *hPtr; |
128 | Array *arrayPtr; |
129 | |
130 | if (objc != 3) { |
131 | Tcl_WrongNumArgs(interp, 1, objv, "array key"); |
132 | return TCL_ERROR; |
133 | } |
134 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, interp, objv[1], 0); |
135 | if (arrayPtr == NULL) { |
136 | return TCL_ERROR; |
137 | } |
138 | hPtr = Tcl_FindHashEntry(&arrayPtr->vars, Tcl_GetString(objv[2])); |
139 | if (hPtr != NULL) { |
140 | Tcl_SetStringObj(Tcl_GetObjResult(interp), Tcl_GetHashValue(hPtr), -1); |
141 | } |
142 | UnlockArray(arrayPtr); |
143 | if (hPtr == NULL) { |
144 | Tcl_AppendResult(interp, "no such key: ", Tcl_GetString(objv[2]), NULL); |
145 | return TCL_ERROR; |
146 | } |
147 | return TCL_OK; |
148 | } |
149 | |
150 | |
151 | /* |
152 | *---------------------------------------------------------------------- |
153 | * |
154 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvExistsObjCmd">NsTclNsvExistsObjCmd</a> -- |
155 | * |
156 | * Implements nsv_exists. |
157 | * |
158 | * Results: |
159 | * Tcl result. |
160 | * |
161 | * Side effects: |
162 | * See docs. |
163 | * |
164 | *---------------------------------------------------------------------- |
165 | */ |
166 | |
167 | int |
168 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvExistsObjCmd">NsTclNsvExistsObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
169 | { |
170 | Array *arrayPtr; |
171 | int exists; |
172 | |
173 | if (objc != 3) { |
174 | Tcl_WrongNumArgs(interp, 1, objv, "array key"); |
175 | return TCL_ERROR; |
176 | } |
177 | exists = 0; |
178 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, NULL, objv[1], 0); |
179 | if (arrayPtr != NULL) { |
180 | if (Tcl_FindHashEntry(&arrayPtr->vars, Tcl_GetString(objv[2])) != NULL) { |
181 | exists = 1; |
182 | } |
183 | UnlockArray(arrayPtr); |
184 | } |
185 | Tcl_SetBooleanObj(Tcl_GetObjResult(interp), exists); |
186 | return TCL_OK; |
187 | } |
188 | |
189 | |
190 | /* |
191 | *---------------------------------------------------------------------- |
192 | * |
193 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvSetObjCmd">NsTclNsvSetObjCmd</a> -- |
194 | * |
195 | * Implelments nsv_set. |
196 | * |
197 | * Results: |
198 | * Tcl result. |
199 | * |
200 | * Side effects: |
201 | * See docs. |
202 | * |
203 | *---------------------------------------------------------------------- |
204 | */ |
205 | |
206 | int |
207 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvSetObjCmd">NsTclNsvSetObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
208 | { |
209 | Array *arrayPtr; |
210 | |
211 | if (objc == 3) { |
212 | return <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvGetObjCmd">NsTclNsvGetObjCmd</a>(arg, interp, objc, objv); |
213 | } else if (objc != 4) { |
214 | Tcl_WrongNumArgs(interp, 1, objv, "array key ?value?"); |
215 | return TCL_ERROR; |
216 | } |
217 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, interp, objv[1], 1); |
218 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_SetVar">SetVar</a>(arrayPtr, objv[2], objv[3]); |
219 | UnlockArray(arrayPtr); |
220 | Tcl_SetObjResult(interp, objv[3]); |
221 | return TCL_OK; |
222 | } |
223 | |
224 | |
225 | /* |
226 | *---------------------------------------------------------------------- |
227 | * |
228 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvIncrObjCmd">NsTclNsvIncrObjCmd</a> -- |
229 | * |
230 | * Implements nsv_incr as an obj command. |
231 | * |
232 | * Results: |
233 | * Tcl result. |
234 | * |
235 | * Side effects: |
236 | * See docs. |
237 | * |
238 | *---------------------------------------------------------------------- |
239 | */ |
240 | |
241 | int |
242 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvIncrObjCmd">NsTclNsvIncrObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
243 | { |
244 | Array *arrayPtr; |
245 | int count, current, result, new; |
246 | char *value; |
247 | Tcl_HashEntry *hPtr; |
248 | |
249 | if (objc != 3 && objc != 4) { |
250 | Tcl_WrongNumArgs(interp, 1, objv, "array key ?count?"); |
251 | return TCL_ERROR; |
252 | } |
253 | if (objc == 3) { |
254 | count = 1; |
255 | } else if (Tcl_GetIntFromObj(interp, objv[3], &count) != TCL_OK) { |
256 | return TCL_ERROR; |
257 | } |
258 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, interp, objv[1], 1); |
259 | hPtr = Tcl_CreateHashEntry(&arrayPtr->vars, Tcl_GetString(objv[2]), &new); |
260 | if (new) { |
261 | current = 0; |
262 | result = TCL_OK; |
263 | } else { |
264 | value = Tcl_GetHashValue(hPtr); |
265 | result = Tcl_GetInt(interp, value, ¤t); |
266 | } |
267 | if (result == TCL_OK) { |
268 | Tcl_Obj *obj = Tcl_GetObjResult(interp); |
269 | current += count; |
270 | Tcl_SetIntObj(obj, current); |
271 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_UpdateVar">UpdateVar</a>(hPtr, obj); |
272 | } |
273 | UnlockArray(arrayPtr); |
274 | return result; |
275 | } |
276 | |
277 | |
278 | /* |
279 | *---------------------------------------------------------------------- |
280 | * |
281 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvLappendObjCmd">NsTclNsvLappendObjCmd</a> -- |
282 | * |
283 | * Implements nsv_lappend command. |
284 | * |
285 | * Results: |
286 | * Tcl result. |
287 | * |
288 | * Side effects: |
289 | * See docs. |
290 | * |
291 | *---------------------------------------------------------------------- |
292 | */ |
293 | |
294 | int |
295 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvLappendObjCmd">NsTclNsvLappendObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
296 | { |
297 | Array *arrayPtr; |
298 | int i, new; |
299 | Tcl_HashEntry *hPtr; |
300 | |
301 | if (objc < 4) { |
302 | Tcl_WrongNumArgs(interp, 1, objv, "array key string ?string ...?"); |
303 | return TCL_ERROR; |
304 | } |
305 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, interp, objv[1], 1); |
306 | hPtr = Tcl_CreateHashEntry(&arrayPtr->vars, Tcl_GetString(objv[2]), &new); |
307 | if (new) { |
308 | Tcl_SetListObj(Tcl_GetObjResult(interp), objc-3, objv+3); |
309 | } else { |
310 | Tcl_SetResult(interp, Tcl_GetHashValue(hPtr), TCL_VOLATILE); |
311 | for (i = 3; i < objc; ++i) { |
312 | Tcl_AppendElement(interp, Tcl_GetString(objv[i])); |
313 | } |
314 | } |
315 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_UpdateVar">UpdateVar</a>(hPtr, Tcl_GetObjResult(interp)); |
316 | UnlockArray(arrayPtr); |
317 | return TCL_OK; |
318 | } |
319 | |
320 | |
321 | /* |
322 | *---------------------------------------------------------------------- |
323 | * |
324 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvAppendObjCmd">NsTclNsvAppendObjCmd</a> -- |
325 | * |
326 | * Implements nsv_append command. |
327 | * |
328 | * Results: |
329 | * Tcl result. |
330 | * |
331 | * Side effects: |
332 | * See docs. |
333 | * |
334 | *---------------------------------------------------------------------- |
335 | */ |
336 | |
337 | int |
338 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvAppendObjCmd">NsTclNsvAppendObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
339 | { |
340 | Array *arrayPtr; |
341 | int i, new; |
342 | Tcl_HashEntry *hPtr; |
343 | |
344 | if (objc < 4) { |
345 | Tcl_WrongNumArgs(interp, 1, objv, "array key string ?string ...?"); |
346 | return TCL_ERROR; |
347 | } |
348 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, interp, objv[1], 1); |
349 | hPtr = Tcl_CreateHashEntry(&arrayPtr->vars, Tcl_GetString(objv[2]), &new); |
350 | if (!new) { |
351 | Tcl_SetResult(interp, Tcl_GetHashValue(hPtr), TCL_VOLATILE); |
352 | } |
353 | for (i = 3; i < objc; ++i) { |
354 | Tcl_AppendResult(interp, Tcl_GetString(objv[i]), NULL); |
355 | } |
356 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_UpdateVar">UpdateVar</a>(hPtr, Tcl_GetObjResult(interp)); |
357 | UnlockArray(arrayPtr); |
358 | return TCL_OK; |
359 | } |
360 | |
361 | |
362 | /* |
363 | *---------------------------------------------------------------------- |
364 | * |
365 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvArrayObjCmd">NsTclNsvArrayObjCmd</a> -- |
366 | * |
367 | * Implements nsv_array as an obj command. |
368 | * |
369 | * Results: |
370 | * Tcl result. |
371 | * |
372 | * Side effects: |
373 | * None. |
374 | * |
375 | *---------------------------------------------------------------------- |
376 | */ |
377 | |
378 | int |
379 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvArrayObjCmd">NsTclNsvArrayObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
380 | { |
381 | Array *arrayPtr; |
382 | Tcl_HashEntry *hPtr; |
383 | Tcl_HashSearch search; |
384 | char *pattern, *key; |
385 | int i, lobjc, size; |
386 | Tcl_Obj *result, **lobjv; |
387 | |
388 | static CONST char *opts[] = { |
389 | "set", "reset", "get", "names", "size", "exists", NULL |
390 | }; |
391 | enum { |
392 | CSetIdx, CResetIdx, CGetIdx, CNamesIdx, CSizeIdx, CExistsIdx |
393 | } _nsmayalias opt; |
394 | |
395 | if (objc < 2) { |
396 | Tcl_WrongNumArgs(interp, 1, objv, "option ..."); |
397 | return TCL_ERROR; |
398 | } |
399 | if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0, |
400 | (int *) &opt) != TCL_OK) { |
401 | return TCL_ERROR; |
402 | } |
403 | result = Tcl_GetObjResult(interp); |
404 | switch (opt) { |
405 | case CSetIdx: |
406 | case CResetIdx: |
407 | if (objc != 4) { |
408 | Tcl_WrongNumArgs(interp, 2, objv, "array valueList"); |
409 | return TCL_ERROR; |
410 | } |
411 | if (Tcl_ListObjGetElements(interp, objv[3], &lobjc, |
412 | &lobjv) != TCL_OK) { |
413 | return TCL_ERROR; |
414 | } |
415 | if (lobjc & 1) { |
416 | Tcl_AppendResult(interp, "invalid list: ", |
417 | Tcl_GetString(objv[3]), NULL); |
418 | return TCL_ERROR; |
419 | } |
420 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, interp, objv[2], 1); |
421 | if (opt == CResetIdx) { |
422 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_FlushArray">FlushArray</a>(arrayPtr); |
423 | } |
424 | for (i = 0; i < lobjc; i += 2) { |
425 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_SetVar">SetVar</a>(arrayPtr, lobjv[i], lobjv[i+1]); |
426 | } |
427 | UnlockArray(arrayPtr); |
428 | break; |
429 | |
430 | case CSizeIdx: |
431 | case CExistsIdx: |
432 | if (objc != 3) { |
433 | Tcl_WrongNumArgs(interp, 2, objv, "array"); |
434 | return TCL_ERROR; |
435 | } |
436 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, NULL, objv[2], 0); |
437 | if (arrayPtr == NULL) { |
438 | size = 0; |
439 | } else { |
440 | size = (opt == CSizeIdx) ? arrayPtr->vars.numEntries : 1; |
441 | UnlockArray(arrayPtr); |
442 | } |
443 | if (opt == CExistsIdx) { |
444 | Tcl_SetBooleanObj(result, size); |
445 | } else { |
446 | Tcl_SetIntObj(result, size); |
447 | } |
448 | break; |
449 | |
450 | case CGetIdx: |
451 | case CNamesIdx: |
452 | if (objc != 3 && objc != 4) { |
453 | Tcl_WrongNumArgs(interp, 2, objv, "array ?pattern?"); |
454 | return TCL_ERROR; |
455 | } |
456 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, NULL, objv[2], 0); |
457 | if (arrayPtr != NULL) { |
458 | pattern = (objc > 3) ? Tcl_GetString(objv[3]) : NULL; |
459 | hPtr = Tcl_FirstHashEntry(&arrayPtr->vars, &search); |
460 | while (hPtr != NULL) { |
461 | key = Tcl_GetHashKey(&arrayPtr->vars, hPtr); |
462 | if (pattern == NULL || Tcl_StringMatch(key, pattern)) { |
463 | Tcl_AppendElement(interp, key); |
464 | if (opt == CGetIdx) { |
465 | Tcl_AppendElement(interp, Tcl_GetHashValue(hPtr)); |
466 | } |
467 | } |
468 | hPtr = Tcl_NextHashEntry(&search); |
469 | } |
470 | UnlockArray(arrayPtr); |
471 | } |
472 | break; |
473 | } |
474 | return TCL_OK; |
475 | } |
476 | |
477 | |
478 | /* |
479 | *---------------------------------------------------------------------- |
480 | * |
481 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvUnsetObjCmd">NsTclNsvUnsetObjCmd</a> -- |
482 | * |
483 | * Implements nsv_unset as an obj command. |
484 | * |
485 | * Results: |
486 | * Tcl result. |
487 | * |
488 | * Side effects: |
489 | * See docs. |
490 | * |
491 | *---------------------------------------------------------------------- |
492 | */ |
493 | |
494 | int |
495 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvUnsetObjCmd">NsTclNsvUnsetObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
496 | { |
497 | Tcl_HashEntry *hPtr = NULL; |
498 | Array *arrayPtr = NULL; |
499 | |
500 | if (objc != 2 && objc != 3) { |
501 | Tcl_WrongNumArgs(interp, 1, objv, "array ?key?"); |
502 | return TCL_ERROR; |
503 | } |
504 | arrayPtr = <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(arg, interp, objv[1], 0); |
505 | if (arrayPtr == NULL) { |
506 | return TCL_ERROR; |
507 | } |
508 | if (objc == 2) { |
509 | Tcl_DeleteHashEntry(arrayPtr->entryPtr); |
510 | } else { |
511 | hPtr = Tcl_FindHashEntry(&arrayPtr->vars, Tcl_GetString(objv[2])); |
512 | if (hPtr != NULL) { |
513 | ns_free(Tcl_GetHashValue(hPtr)); |
514 | Tcl_DeleteHashEntry(hPtr); |
515 | } |
516 | } |
517 | UnlockArray(arrayPtr); |
518 | if (objc == 2) { |
519 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_FlushArray">FlushArray</a>(arrayPtr); |
520 | Tcl_DeleteHashTable(&arrayPtr->vars); |
521 | ns_free(arrayPtr); |
522 | } else if (hPtr == NULL) { |
523 | Tcl_AppendResult(interp, "no such key: ", Tcl_GetString(objv[2]), NULL); |
524 | return TCL_ERROR; |
525 | } |
526 | return TCL_OK; |
527 | } |
528 | |
529 | |
530 | /* |
531 | *---------------------------------------------------------------------- |
532 | * |
533 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvNamesObjCmd">NsTclNsvNamesObjCmd</a> -- |
534 | * |
535 | * Implements nsv_names as an obj command. |
536 | * |
537 | * Results: |
538 | * Tcl result. |
539 | * |
540 | * Side effects: |
541 | * See docs. |
542 | * |
543 | *---------------------------------------------------------------------- |
544 | */ |
545 | |
546 | int |
547 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclNsvNamesObjCmd">NsTclNsvNamesObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
548 | { |
549 | NsInterp *itPtr = arg; |
550 | NsServer *servPtr = itPtr->servPtr; |
551 | Tcl_HashEntry *hPtr; |
552 | Tcl_HashSearch search; |
553 | Tcl_Obj *result; |
554 | Bucket *bucketPtr; |
555 | char *pattern, *key; |
556 | int i; |
557 | |
558 | if (objc != 1 && objc !=2) { |
559 | Tcl_WrongNumArgs(interp, 1, objv, "?pattern?"); |
560 | return TCL_ERROR; |
561 | } |
562 | pattern = objc < 2 ? NULL : Tcl_GetString(objv[1]); |
563 | |
564 | /* |
565 | * Walk the bucket list for each array. |
566 | */ |
567 | |
568 | result = Tcl_GetObjResult(interp); |
569 | for (i = 0; i < servPtr->nsv.nbuckets; i++) { |
570 | bucketPtr = &servPtr->nsv.buckets[i]; |
571 | Ns_MutexLock(&bucketPtr->lock); |
572 | hPtr = Tcl_FirstHashEntry(&bucketPtr->arrays, &search); |
573 | while (hPtr != NULL) { |
574 | key = Tcl_GetHashKey(&bucketPtr->arrays, hPtr); |
575 | if (pattern == NULL || Tcl_StringMatch(key, pattern)) { |
576 | Tcl_ListObjAppendElement(NULL, result, |
577 | Tcl_NewStringObj(key, -1)); |
578 | } |
579 | hPtr = Tcl_NextHashEntry(&search); |
580 | } |
581 | Ns_MutexUnlock(&bucketPtr->lock); |
582 | } |
583 | return TCL_OK; |
584 | } |
585 | |
586 | |
587 | /* |
588 | *---------------------------------------------------------------- |
589 | * |
590 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a> -- |
591 | * |
592 | * Find (or create) the Array structure for an array and |
593 | * lock it. Array structure must be later unlocked with |
594 | * UnlockArray. |
595 | * |
596 | * Results: |
597 | * TCL_OK or TCL_ERROR if no such array. |
598 | * |
599 | * Side effects; |
600 | * Sets *arrayPtrPtr with Array pointer or leave error in |
601 | * given Tcl_Interp. |
602 | * |
603 | *---------------------------------------------------------------- |
604 | */ |
605 | |
606 | static Array * |
607 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_LockArray">LockArray</a>(void *arg, Tcl_Interp *interp, Tcl_Obj *arrayObj, int create) |
608 | { |
609 | NsInterp *itPtr = arg; |
610 | Bucket *bucketPtr; |
611 | Tcl_HashEntry *hPtr; |
612 | Array *arrayPtr; |
613 | char *array; |
614 | register char *p; |
615 | register unsigned int result; |
616 | register int i; |
617 | int new; |
618 | |
619 | array = Tcl_GetString(arrayObj); |
620 | p = array; |
621 | result = 0; |
622 | while (1) { |
623 | i = *p; |
624 | p++; |
625 | if (i == 0) { |
626 | break; |
627 | } |
628 | result += (result<<3) + i; |
629 | } |
630 | i = result % itPtr->servPtr->nsv.nbuckets; |
631 | bucketPtr = &itPtr->servPtr->nsv.buckets[i]; |
632 | |
633 | Ns_MutexLock(&bucketPtr->lock); |
634 | if (create) { |
635 | hPtr = Tcl_CreateHashEntry(&bucketPtr->arrays, array, &new); |
636 | if (!new) { |
637 | arrayPtr = Tcl_GetHashValue(hPtr); |
638 | } else { |
639 | arrayPtr = ns_malloc(sizeof(Array)); |
640 | arrayPtr->bucketPtr = bucketPtr; |
641 | arrayPtr->entryPtr = hPtr; |
642 | Tcl_InitHashTable(&arrayPtr->vars, TCL_STRING_KEYS); |
643 | Tcl_SetHashValue(hPtr, arrayPtr); |
644 | } |
645 | } else { |
646 | hPtr = Tcl_FindHashEntry(&bucketPtr->arrays, array); |
647 | if (hPtr == NULL) { |
648 | Ns_MutexUnlock(&bucketPtr->lock); |
649 | if (interp != NULL) { |
650 | Tcl_AppendResult(interp, "no such array: ", array, NULL); |
651 | } |
652 | return NULL; |
653 | } |
654 | arrayPtr = Tcl_GetHashValue(hPtr); |
655 | } |
656 | return arrayPtr; |
657 | } |
658 | |
659 | |
660 | /* |
661 | *---------------------------------------------------------------- |
662 | * |
663 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_UpdateVar">UpdateVar</a> -- |
664 | * |
665 | * Update a variable entry. |
666 | * |
667 | * Results: |
668 | * None. |
669 | * |
670 | * Side effects; |
671 | * New value is set. |
672 | * |
673 | *---------------------------------------------------------------- |
674 | */ |
675 | |
676 | static void |
677 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_UpdateVar">UpdateVar</a>(Tcl_HashEntry *hPtr, Tcl_Obj *obj) |
678 | { |
679 | char *str, *old, *new; |
680 | int len; |
681 | |
682 | str = Tcl_GetStringFromObj(obj, &len); |
683 | old = Tcl_GetHashValue(hPtr); |
684 | new = ns_realloc(old, (size_t)(len+1)); |
685 | memcpy(new, str, (size_t)(len+1)); |
686 | Tcl_SetHashValue(hPtr, new); |
687 | } |
688 | |
689 | |
690 | /* |
691 | *---------------------------------------------------------------- |
692 | * |
693 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_SetVar">SetVar</a> -- |
694 | * |
695 | * Set (or reset) an array entry. |
696 | * |
697 | * Results: |
698 | * None. |
699 | * |
700 | * Side effects; |
701 | * New entry is created and updated. |
702 | * |
703 | *---------------------------------------------------------------- |
704 | */ |
705 | |
706 | static void |
707 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_SetVar">SetVar</a>(Array *arrayPtr, Tcl_Obj *key, Tcl_Obj *value) |
708 | { |
709 | Tcl_HashEntry *hPtr; |
710 | int new; |
711 | |
712 | hPtr = Tcl_CreateHashEntry(&arrayPtr->vars, Tcl_GetString(key), &new); |
713 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_UpdateVar">UpdateVar</a>(hPtr, value); |
714 | } |
715 | |
716 | |
717 | /* |
718 | *---------------------------------------------------------------- |
719 | * |
720 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_FlushArray">FlushArray</a> -- |
721 | * |
722 | * Unset all keys in an array. |
723 | * |
724 | * Results: |
725 | * None. |
726 | * |
727 | * Side effects; |
728 | * New entry is created and updated. |
729 | * |
730 | *---------------------------------------------------------------- |
731 | */ |
732 | |
733 | static void |
734 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_FlushArray">FlushArray</a>(Array *arrayPtr) |
735 | { |
736 | Tcl_HashEntry *hPtr; |
737 | Tcl_HashSearch search; |
738 | |
739 | hPtr = Tcl_FirstHashEntry(&arrayPtr->vars, &search); |
740 | while (hPtr != NULL) { |
741 | ns_free(Tcl_GetHashValue(hPtr)); |
742 | Tcl_DeleteHashEntry(hPtr); |
743 | hPtr = Tcl_NextHashEntry(&search); |
744 | } |
745 | } |
746 | |
747 | |
748 | /* |
749 | *---------------------------------------------------------------------- |
750 | * |
751 | * <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclVarObjCmd">NsTclVarObjCmd</a> -- |
752 | * |
753 | * Implements ns_var (deprecated) |
754 | * |
755 | * Results: |
756 | * Tcl result. |
757 | * |
758 | * Side effects: |
759 | * None. |
760 | * |
761 | *---------------------------------------------------------------------- |
762 | */ |
763 | |
764 | int |
765 | <a href="/cvs/aolserver/aolserver/nsd/tclvar.c#A_NsTclVarObjCmd">NsTclVarObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, |
766 | Tcl_Obj **objv) |
767 | { |
768 | NsInterp *itPtr = arg; |
769 | NsServer *servPtr; |
770 | Tcl_HashTable *tablePtr; |
771 | Tcl_HashEntry *hPtr; |
772 | Tcl_HashSearch search; |
773 | int new, code; |
774 | char *var = NULL, *val = NULL; |
775 | static CONST char *opts[] = { |
776 | "exists", "get", "list", "set", "unset", NULL |
777 | }; |
778 | enum { |
779 | VExistsIdx, VGetIdx, VListIdx, VSetIdx, VUnsetIdx |
780 | } _nsmayalias opt; |
781 | |
782 | if (objc < 2) { |
783 | Tcl_WrongNumArgs(interp, 1, objv, "option ?args?"); |
784 | return TCL_ERROR; |
785 | } |
786 | if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0, |
787 | (int *) &opt) != TCL_OK) { |
788 | return TCL_ERROR; |
789 | } |
790 | servPtr = itPtr->servPtr; |
791 | tablePtr = &servPtr->var.table; |
792 | code = TCL_OK; |
793 | if (objc > 2) { |
794 | var = Tcl_GetString(objv[2]); |
795 | } |
796 | Ns_MutexLock(&servPtr->var.lock); |
797 | switch (opt) { |
798 | case VExistsIdx: |
799 | case VGetIdx: |
800 | case VUnsetIdx: |
801 | if (objc != 3) { |
802 | Tcl_WrongNumArgs(interp, 2, objv, "var"); |
803 | code = TCL_ERROR; |
804 | } else { |
805 | hPtr = Tcl_FindHashEntry(tablePtr, var); |
806 | if (opt == VExistsIdx) { |
807 | Tcl_SetBooleanObj(Tcl_GetObjResult(interp), hPtr ? 1 : 0); |
808 | } else if (hPtr == NULL) { |
809 | Tcl_AppendResult(interp, "no such variable \"", var, |
810 | "\"", NULL); |
811 | code = TCL_ERROR; |
812 | } else if (opt == VGetIdx) { |
813 | Tcl_SetResult(interp, Tcl_GetHashValue(hPtr), TCL_VOLATILE); |
814 | } else { |
815 | ns_free(Tcl_GetHashValue(hPtr)); |
816 | Tcl_DeleteHashEntry(hPtr); |
817 | } |
818 | } |
819 | break; |
820 | |
821 | case VSetIdx: |
822 | if (objc != 4) { |
823 | Tcl_WrongNumArgs(interp, 2, objv, "var value"); |
824 | code = TCL_ERROR; |
825 | } else { |
826 | hPtr = Tcl_CreateHashEntry(tablePtr, var, &new); |
827 | if (!new) { |
828 | ns_free(Tcl_GetHashValue(hPtr)); |
829 | } |
830 | val = Tcl_GetString(objv[3]); |
831 | Tcl_SetHashValue(hPtr, ns_strdup(val)); |
832 | Tcl_SetResult(interp, val, TCL_VOLATILE); |
833 | } |
834 | break; |
835 | |
836 | case VListIdx: |
837 | hPtr = Tcl_FirstHashEntry(tablePtr, &search); |
838 | while (hPtr != NULL) { |
839 | Tcl_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr)); |
840 | hPtr = Tcl_NextHashEntry(&search); |
841 | } |
842 | break; |
843 | } |
844 | Ns_MutexUnlock(&servPtr->var.lock); |
845 | return code; |
846 | } |
Copyright © 2010 Geeknet, Inc. All rights reserved. Terms of Use