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.17 - (show annotations) (download) (as text)
Tue Aug 23 21:41:31 2005 UTC (12 years, 4 months ago) by jgdavidson
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.16: +3 -3 lines
File MIME type: text/x-chdr
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, &current);
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 }