source: trunk/kitgen/8.x/blt/generic/bltVector.c@ 175

Last change on this file since 175 was 175, checked in by demin, 12 years ago

initial commit

File size: 62.6 KB
RevLine 
[175]1/*
2 * bltVector.c --
3 *
4 * This module implements vector data objects.
5 *
6 * Copyright 1995-1998 Lucent Technologies, Inc.
7 *
8 * Permission to use, copy, modify, and distribute this software and
9 * its documentation for any purpose and without fee is hereby
10 * granted, provided that the above copyright notice appear in all
11 * copies and that both that the copyright notice and warranty
12 * disclaimer appear in supporting documentation, and that the names
13 * of Lucent Technologies any of their entities not be used in
14 * advertising or publicity pertaining to distribution of the software
15 * without specific, written prior permission.
16 *
17 * Lucent Technologies disclaims all warranties with regard to this
18 * software, including all implied warranties of merchantability and
19 * fitness. In no event shall Lucent Technologies be liable for any
20 * special, indirect or consequential damages or any damages
21 * whatsoever resulting from loss of use, data or profits, whether in
22 * an action of contract, negligence or other tortuous action, arising
23 * out of or in connection with the use or performance of this
24 * software.
25 */
26
27/*
28 * TODO:
29 * o Add H. Kirsch's vector binary read operation
30 * x binread file0
31 * x binread -file file0
32 *
33 * o Add ASCII/binary file reader
34 * x read fileName
35 *
36 * o Allow Tcl-based client notifications.
37 * vector x
38 * x notify call Display
39 * x notify delete Display
40 * x notify reorder #1 #2
41 */
42
43#include "bltVecInt.h"
44#include "bltMath.h"
45
46#ifdef TIME_WITH_SYS_TIME
47#include <sys/time.h>
48#include <time.h>
49#else
50#ifdef HAVE_SYS_TIME_H
51#include <sys/time.h>
52#else
53#include <time.h>
54#endif /* HAVE_SYS_TIME_H */
55#endif /* TIME_WITH_SYS_TIME */
56
57#ifndef TCL_NAMESPACE_ONLY
58#define TCL_NAMESPACE_ONLY TCL_GLOBAL_ONLY
59#endif
60
61#define DEF_ARRAY_SIZE 64
62#define VECFLAGS(v) \
63 (((v)->varNsPtr != NULL) ? (TCL_NAMESPACE_ONLY | TCL_GLOBAL_ONLY) : 0;
64#define TRACE_ALL (TCL_TRACE_WRITES | TCL_TRACE_READS | TCL_TRACE_UNSETS)
65
66
67#define VECTOR_CHAR(c) ((isalnum(UCHAR(c))) || \
68 (c == '_') || (c == ':') || (c == '@') || (c == '.'))
69
70
71/*
72 * VectorClient --
73 *
74 * A vector can be shared by several clients. Each client
75 * allocates this structure that acts as its key for using the
76 * vector. Clients can also designate a callback routine that is
77 * executed whenever the vector is updated or destroyed.
78 *
79 */
80typedef struct {
81 unsigned int magic; /* Magic value designating whether this
82 * really is a vector token or not */
83
84 VectorObject *serverPtr; /* Pointer to the master record of the
85 * vector. If NULL, indicates that the
86 * vector has been destroyed but as of
87 * yet, this client hasn't recognized
88 * it. */
89
90 Blt_VectorChangedProc *proc;/* Routine to call when the contents
91 * of the vector change or the vector
92 * is deleted. */
93
94 ClientData clientData; /* Data passed whenever the vector
95 * change procedure is called. */
96
97 Blt_ChainLink *linkPtr; /* Used to quickly remove this entry from
98 * its server's client chain. */
99} VectorClient;
100
101static Tcl_CmdDeleteProc VectorInstDeleteProc;
102static Tcl_CmdProc VectorCmd;
103static Tcl_InterpDeleteProc VectorInterpDeleteProc;
104
105extern void srand48 _ANSI_ARGS_((long int seed));
106
107static VectorObject *
108FindVectorInNamespace(dataPtr, nsPtr, vecName)
109 VectorInterpData *dataPtr; /* Interpreter-specific data. */
110 Tcl_Namespace *nsPtr;
111 CONST char *vecName;
112{
113 Tcl_DString dString;
114 CONST char *name;
115 Blt_HashEntry *hPtr;
116
117 name = Blt_GetQualifiedName(nsPtr, vecName, &dString);
118 hPtr = Blt_FindHashEntry(&(dataPtr->vectorTable), name);
119 Tcl_DStringFree(&dString);
120 if (hPtr != NULL) {
121 return (VectorObject *)Blt_GetHashValue(hPtr);
122 }
123 return NULL;
124}
125
126/*
127 * ----------------------------------------------------------------------
128 *
129 * GetVectorObject --
130 *
131 * Searches for the vector associated with the name given.
132 * Allow for a range specification.
133 *
134 * Results:
135 * Returns a pointer to the vector if found, otherwise NULL.
136 *
137 * ----------------------------------------------------------------------
138 */
139static VectorObject *
140GetVectorObject(dataPtr, name, flags)
141 VectorInterpData *dataPtr; /* Interpreter-specific data. */
142 CONST char *name;
143 int flags;
144{
145 CONST char *vecName;
146 Tcl_Namespace *nsPtr;
147 VectorObject *vPtr;
148
149 nsPtr = NULL;
150 vecName = name;
151 if (Blt_ParseQualifiedName(dataPtr->interp, name, &nsPtr, &vecName)
152 != TCL_OK) {
153 return NULL; /* Can't find namespace. */
154 }
155 vPtr = NULL;
156 if (nsPtr != NULL) {
157 vPtr = FindVectorInNamespace(dataPtr, nsPtr, vecName);
158 } else {
159 if (flags & NS_SEARCH_CURRENT) {
160 nsPtr = Tcl_GetCurrentNamespace(dataPtr->interp);
161 vPtr = FindVectorInNamespace(dataPtr, nsPtr, vecName);
162 }
163 if ((vPtr == NULL) && (flags & NS_SEARCH_GLOBAL)) {
164 nsPtr = Tcl_GetGlobalNamespace(dataPtr->interp);
165 vPtr = FindVectorInNamespace(dataPtr, nsPtr, vecName);
166 }
167 }
168 return vPtr;
169}
170
171void
172Blt_VectorUpdateRange(vPtr)
173 VectorObject *vPtr;
174{
175 double min, max;
176 register int i;
177
178 min = DBL_MAX, max = -DBL_MAX;
179 for (i = 0; i < vPtr->length; i++) {
180 if (FINITE(vPtr->valueArr[i])) {
181 min = max = vPtr->valueArr[i];
182 break;
183 }
184 }
185 for (/* empty */; i < vPtr->length; i++) {
186 if (FINITE(vPtr->valueArr[i])) {
187 if (min > vPtr->valueArr[i]) {
188 min = vPtr->valueArr[i];
189 } else if (max < vPtr->valueArr[i]) {
190 max = vPtr->valueArr[i];
191 }
192 }
193 }
194 vPtr->min = min;
195 vPtr->max = max;
196 vPtr->notifyFlags &= ~UPDATE_RANGE;
197}
198
199/*
200 * ----------------------------------------------------------------------
201 *
202 * Blt_VectorGetIndex --
203 *
204 * Converts the string representing an index in the vector, to
205 * its numeric value. A valid index may be an numeric string of
206 * the string "end" (indicating the last element in the string).
207 *
208 * Results:
209 * A standard Tcl result. If the string is a valid index, TCL_OK
210 * is returned. Otherwise TCL_ERROR is returned and interp->result
211 * will contain an error message.
212 *
213 * ----------------------------------------------------------------------
214 */
215int
216Blt_VectorGetIndex(interp, vPtr, string, indexPtr, flags, procPtrPtr)
217 Tcl_Interp *interp;
218 VectorObject *vPtr;
219 CONST char *string;
220 int *indexPtr;
221 int flags;
222 Blt_VectorIndexProc **procPtrPtr;
223{
224 char c;
225 int value;
226
227 c = string[0];
228
229 /* Treat the index "end" like a numeric index. */
230
231 if ((c == 'e') && (strcmp(string, "end") == 0)) {
232 if (vPtr->length < 1) {
233 if (interp != NULL) {
234 Tcl_AppendResult(interp, "bad index \"end\": vector is empty",
235 (char *)NULL);
236 }
237 return TCL_ERROR;
238 }
239 *indexPtr = vPtr->length - 1;
240 return TCL_OK;
241 } else if ((c == '+') && (strcmp(string, "++end") == 0)) {
242 *indexPtr = vPtr->length;
243 return TCL_OK;
244 }
245 if (procPtrPtr != NULL) {
246 Blt_HashEntry *hPtr;
247
248 hPtr = Blt_FindHashEntry(&(vPtr->dataPtr->indexProcTable), string);
249 if (hPtr != NULL) {
250 *indexPtr = SPECIAL_INDEX;
251 *procPtrPtr = (Blt_VectorIndexProc *) Blt_GetHashValue(hPtr);
252 return TCL_OK;
253 }
254 }
255 if (Tcl_GetInt(interp, (char *)string, &value) != TCL_OK) {
256 long int lvalue;
257 /*
258 * Unlike Tcl_GetInt, Tcl_ExprLong needs a valid interpreter,
259 * but the interp passed in may be NULL. So we have to use
260 * vPtr->interp and then reset the result.
261 */
262 if (Tcl_ExprLong(vPtr->interp, (char *)string, &lvalue) != TCL_OK) {
263 Tcl_ResetResult(vPtr->interp);
264 if (interp != NULL) {
265 Tcl_AppendResult(interp, "bad index \"", string, "\"",
266 (char *)NULL);
267 }
268 return TCL_ERROR;
269 }
270 value = lvalue;
271 }
272 /*
273 * Correct the index by the current value of the offset. This makes
274 * all the numeric indices non-negative, which is how we distinguish
275 * the special non-numeric indices.
276 */
277 value -= vPtr->offset;
278
279 if ((value < 0) || ((flags & INDEX_CHECK) && (value >= vPtr->length))) {
280 if (interp != NULL) {
281 Tcl_AppendResult(interp, "index \"", string, "\" is out of range",
282 (char *)NULL);
283 }
284 return TCL_ERROR;
285 }
286 *indexPtr = (int)value;
287 return TCL_OK;
288}
289
290/*
291 * ----------------------------------------------------------------------
292 *
293 * Blt_VectorGetIndexRange --
294 *
295 * Converts the string representing an index in the vector, to
296 * its numeric value. A valid index may be an numeric string of
297 * the string "end" (indicating the last element in the string).
298 *
299 * Results:
300 * A standard Tcl result. If the string is a valid index, TCL_OK
301 * is returned. Otherwise TCL_ERROR is returned and interp->result
302 * will contain an error message.
303 *
304 * ----------------------------------------------------------------------
305 */
306int
307Blt_VectorGetIndexRange(interp, vPtr, string, flags, procPtrPtr)
308 Tcl_Interp *interp;
309 VectorObject *vPtr;
310 CONST char *string;
311 int flags;
312 Blt_VectorIndexProc **procPtrPtr;
313{
314 int ielem;
315 char *colon;
316
317 colon = NULL;
318 if (flags & INDEX_COLON) {
319 colon = strchr(string, ':');
320 }
321 if (colon != NULL) {
322 if (string == colon) {
323 vPtr->first = 0; /* Default to the first index */
324 } else {
325 int result;
326
327 *colon = '\0';
328 result = Blt_VectorGetIndex(interp, vPtr, string, &ielem, flags,
329 (Blt_VectorIndexProc **) NULL);
330 *colon = ':';
331 if (result != TCL_OK) {
332 return TCL_ERROR;
333 }
334 vPtr->first = ielem;
335 }
336 if (*(colon + 1) == '\0') {
337 /* Default to the last index */
338 vPtr->last = (vPtr->length > 0) ? vPtr->length - 1 : 0;
339 } else {
340 if (Blt_VectorGetIndex(interp, vPtr, colon + 1, &ielem, flags,
341 (Blt_VectorIndexProc **) NULL) != TCL_OK) {
342 return TCL_ERROR;
343 }
344 vPtr->last = ielem;
345 }
346 if (vPtr->first > vPtr->last) {
347 if (interp != NULL) {
348 Tcl_AppendResult(interp, "bad range \"", string,
349 "\" (first > last)", (char *)NULL);
350 }
351 return TCL_ERROR;
352 }
353 } else {
354 if (Blt_VectorGetIndex(interp, vPtr, string, &ielem, flags,
355 procPtrPtr) != TCL_OK) {
356 return TCL_ERROR;
357 }
358 vPtr->last = vPtr->first = ielem;
359 }
360 return TCL_OK;
361}
362
363VectorObject *
364Blt_VectorParseElement(interp, dataPtr, start, endPtr, flags)
365 Tcl_Interp *interp;
366 VectorInterpData *dataPtr; /* Interpreter-specific data. */
367 CONST char *start;
368 char **endPtr;
369 int flags;
370{
371 register char *p;
372 char saved;
373 VectorObject *vPtr;
374
375 p = (char *)start;
376 /* Find the end of the vector name */
377 while (VECTOR_CHAR(*p)) {
378 p++;
379 }
380 saved = *p;
381 *p = '\0';
382
383 vPtr = GetVectorObject(dataPtr, start, flags);
384 if (vPtr == NULL) {
385 if (interp != NULL) {
386 Tcl_AppendResult(interp, "can't find vector \"", start, "\"",
387 (char *)NULL);
388 }
389 *p = saved;
390 return NULL;
391 }
392 *p = saved;
393 vPtr->first = 0;
394 vPtr->last = vPtr->length - 1;
395 if (*p == '(') {
396 int count, result;
397
398 start = p + 1;
399 p++;
400
401 /* Find the matching right parenthesis */
402 count = 1;
403 while (*p != '\0') {
404 if (*p == ')') {
405 count--;
406 if (count == 0) {
407 break;
408 }
409 } else if (*p == '(') {
410 count++;
411 }
412 p++;
413 }
414 if (count > 0) {
415 if (interp != NULL) {
416 Tcl_AppendResult(interp, "unbalanced parentheses \"", start,
417 "\"", (char *)NULL);
418 }
419 return NULL;
420 }
421 *p = '\0';
422 result = Blt_VectorGetIndexRange(interp, vPtr, start,
423 (INDEX_COLON | INDEX_CHECK), (Blt_VectorIndexProc **) NULL);
424 *p = ')';
425 if (result != TCL_OK) {
426 return NULL;
427 }
428 p++;
429 }
430 if (endPtr != NULL) {
431 *endPtr = p;
432 }
433 return vPtr;
434}
435
436
437/*
438 * ----------------------------------------------------------------------
439 *
440 * Blt_VectorNotifyClients --
441 *
442 * Notifies each client of the vector that the vector has changed
443 * (updated or destroyed) by calling the provided function back.
444 * The function pointer may be NULL, in that case the client is
445 * not notified.
446 *
447 * Results:
448 * None.
449 *
450 * Side effects:
451 * The results depend upon what actions the client callbacks
452 * take.
453 *
454 * ----------------------------------------------------------------------
455 */
456void
457Blt_VectorNotifyClients(clientData)
458 ClientData clientData;
459{
460 VectorObject *vPtr = clientData;
461 Blt_ChainLink *linkPtr;
462 VectorClient *clientPtr;
463 Blt_VectorNotify notify;
464
465 notify = (vPtr->notifyFlags & NOTIFY_DESTROYED)
466 ? BLT_VECTOR_NOTIFY_DESTROY : BLT_VECTOR_NOTIFY_UPDATE;
467 vPtr->notifyFlags &= ~(NOTIFY_UPDATED | NOTIFY_DESTROYED | NOTIFY_PENDING);
468
469 for (linkPtr = Blt_ChainFirstLink(vPtr->chainPtr); linkPtr != NULL;
470 linkPtr = Blt_ChainNextLink(linkPtr)) {
471 clientPtr = Blt_ChainGetValue(linkPtr);
472 if (clientPtr->proc != NULL) {
473 (*clientPtr->proc) (vPtr->interp, clientPtr->clientData, notify);
474 }
475 }
476 /*
477 * Some clients may not handle the "destroy" callback properly
478 * (they should call Blt_FreeVectorId to release the client
479 * identifier), so mark any remaining clients to indicate that
480 * vector's server has gone away.
481 */
482 if (notify == BLT_VECTOR_NOTIFY_DESTROY) {
483 for (linkPtr = Blt_ChainFirstLink(vPtr->chainPtr); linkPtr != NULL;
484 linkPtr = Blt_ChainNextLink(linkPtr)) {
485 clientPtr = Blt_ChainGetValue(linkPtr);
486 clientPtr->serverPtr = NULL;
487 }
488 }
489}
490
491/*
492 * ----------------------------------------------------------------------
493 *
494 * Blt_VectorUpdateClients --
495 *
496 * Notifies each client of the vector that the vector has changed
497 * (updated or destroyed) by calling the provided function back.
498 *
499 * Results:
500 * None.
501 *
502 * Side effects:
503 * The individual client callbacks are eventually invoked.
504 *
505 * ----------------------------------------------------------------------
506 */
507void
508Blt_VectorUpdateClients(vPtr)
509 VectorObject *vPtr;
510{
511 vPtr->dirty++;
512 vPtr->max = vPtr->min = bltNaN;
513 if (vPtr->notifyFlags & NOTIFY_NEVER) {
514 return;
515 }
516 vPtr->notifyFlags |= NOTIFY_UPDATED;
517 if (vPtr->notifyFlags & NOTIFY_ALWAYS) {
518 Blt_VectorNotifyClients(vPtr);
519 return;
520 }
521 if (!(vPtr->notifyFlags & NOTIFY_PENDING)) {
522 vPtr->notifyFlags |= NOTIFY_PENDING;
523 Tcl_DoWhenIdle(Blt_VectorNotifyClients, vPtr);
524 }
525}
526
527/*
528 * ----------------------------------------------------------------------
529 *
530 * Blt_VectorFlushCache --
531 *
532 * Unsets all the elements of the Tcl array variable associated
533 * with the vector, freeing memory associated with the variable.
534 * This includes both the hash table and the hash keys. The down
535 * side is that this effectively flushes the caching of vector
536 * elements in the array. This means that the subsequent reads
537 * of the array will require a decimal to string conversion.
538 *
539 * This is needed when the vector changes its values, making
540 * the array variable out-of-sync.
541 *
542 * Results:
543 * None.
544 *
545 * Side effects:
546 * All elements of array variable (except one) are unset, freeing
547 * the memory associated with the variable.
548 *
549 * ----------------------------------------------------------------------
550 */
551void
552Blt_VectorFlushCache(vPtr)
553 VectorObject *vPtr;
554{
555 Tcl_CallFrame *framePtr;
556 Tcl_Interp *interp = vPtr->interp;
557
558 if (vPtr->arrayName == NULL) {
559 return; /* Doesn't use the variable API */
560 }
561 framePtr = NULL;
562 if (vPtr->varNsPtr != NULL) {
563 framePtr = Blt_EnterNamespace(interp, vPtr->varNsPtr);
564 }
565 /* Turn off the trace temporarily so that we can unset all the
566 * elements in the array. */
567
568 Tcl_UntraceVar2(interp, vPtr->arrayName, (char *)NULL,
569 TRACE_ALL | vPtr->varFlags, Blt_VectorVarTrace, vPtr);
570
571 /* Clear all the element entries from the entire array */
572 Tcl_UnsetVar2(interp, vPtr->arrayName, (char *)NULL, vPtr->varFlags);
573
574 /* Restore the "end" index by default and the trace on the entire array */
575 Tcl_SetVar2(interp, vPtr->arrayName, "end", "", vPtr->varFlags);
576 Tcl_TraceVar2(interp, vPtr->arrayName, (char *)NULL,
577 TRACE_ALL | vPtr->varFlags, Blt_VectorVarTrace, vPtr);
578
579 if ((vPtr->varNsPtr != NULL) && (framePtr != NULL)) {
580 Blt_LeaveNamespace(interp, framePtr); /* Go back to current */
581 }
582}
583
584/*
585 * ----------------------------------------------------------------------
586 *
587 * Blt_VectorLookupName --
588 *
589 * Searches for the vector associated with the name given. Allow
590 * for a range specification.
591 *
592 * Results:
593 * Returns a pointer to the vector if found, otherwise NULL.
594 * If the name is not associated with a vector and the
595 * TCL_LEAVE_ERR_MSG flag is set, and interp->result will contain
596 * an error message.
597 *
598 * ----------------------------------------------------------------------
599 */
600int
601Blt_VectorLookupName(dataPtr, vecName, vPtrPtr)
602 VectorInterpData *dataPtr; /* Interpreter-specific data. */
603 char *vecName;
604 VectorObject **vPtrPtr;
605{
606 VectorObject *vPtr;
607 char *endPtr;
608
609 vPtr = Blt_VectorParseElement(dataPtr->interp, dataPtr, vecName, &endPtr,
610 NS_SEARCH_BOTH);
611 if (vPtr == NULL) {
612 return TCL_ERROR;
613 }
614 if (*endPtr != '\0') {
615 Tcl_AppendResult(dataPtr->interp,
616 "extra characters after vector name", (char *)NULL);
617 return TCL_ERROR;
618 }
619 *vPtrPtr = vPtr;
620 return TCL_OK;
621}
622
623/*
624 * ----------------------------------------------------------------------
625 *
626 * DeleteCommand --
627 *
628 * Deletes the Tcl command associated with the vector, without
629 * triggering a callback to "VectorInstDeleteProc".
630 *
631 * Results:
632 * None.
633 *
634 * ----------------------------------------------------------------------
635 */
636static void
637DeleteCommand(vPtr)
638 VectorObject *vPtr; /* Vector associated with the Tcl command. */
639{
640 Tcl_Interp *interp = vPtr->interp;
641 char *qualName; /* Name of Tcl command. */
642 Tcl_CmdInfo cmdInfo;
643 Tcl_DString dString;
644
645 Tcl_DStringInit(&dString);
646 qualName = Blt_GetQualifiedName(
647 Blt_GetCommandNamespace(interp, vPtr->cmdToken),
648 Tcl_GetCommandName(interp, vPtr->cmdToken), &dString);
649 if (Tcl_GetCommandInfo(interp, qualName, &cmdInfo)) {
650 cmdInfo.deleteProc = NULL; /* Disable the callback before
651 * deleting the Tcl command.*/
652 Tcl_SetCommandInfo(interp, qualName, &cmdInfo);
653 Tcl_DeleteCommandFromToken(interp, vPtr->cmdToken);
654 }
655 Tcl_DStringFree(&dString);
656 vPtr->cmdToken = 0;
657}
658
659/*
660 * ----------------------------------------------------------------------
661 *
662 * UnmapVariable --
663 *
664 * Destroys the trace on the current Tcl variable designated
665 * to access the vector.
666 *
667 * Results:
668 * None.
669 *
670 * ----------------------------------------------------------------------
671 */
672static void
673UnmapVariable(vPtr)
674 VectorObject *vPtr;
675{
676 Tcl_Interp *interp = vPtr->interp;
677 Tcl_CallFrame *framePtr;
678
679 framePtr = NULL;
680 if (vPtr->varNsPtr != NULL) { /* Activate namespace */
681 framePtr = Blt_EnterNamespace(interp, vPtr->varNsPtr);
682 }
683 /* Unset the entire array */
684 Tcl_UntraceVar2(interp, vPtr->arrayName, (char *)NULL,
685 (TRACE_ALL | vPtr->varFlags), Blt_VectorVarTrace, vPtr);
686 Tcl_UnsetVar2(interp, vPtr->arrayName, (char *)NULL, vPtr->varFlags);
687
688 if ((vPtr->varNsPtr != NULL) && (framePtr != NULL)) {
689 /* Go back to current namespace */
690 Blt_LeaveNamespace(interp, framePtr);
691 }
692 if (vPtr->arrayName != NULL) {
693 Blt_Free(vPtr->arrayName);
694 vPtr->arrayName = NULL;
695 }
696 vPtr->varNsPtr = NULL;
697}
698
699/*
700 * ----------------------------------------------------------------------
701 *
702 * Blt_VectorMapVariable --
703 *
704 * Sets up traces on a Tcl variable to access the vector.
705 *
706 * If another variable is already mapped, it's first untraced and
707 * removed. Don't do anything else for variables named "" (even
708 * though Tcl allows this pathology). Saves the name of the new
709 * array variable.
710 *
711 * Results:
712 * A standard Tcl result. If an error occurs setting the variable
713 * TCL_ERROR is returned and an error message is left in the
714 * interpreter.
715 *
716 * Side effects:
717 * Traces are set for the new variable. The new variable name is
718 * saved in a malloc'ed string in vPtr->arrayName. If this
719 * variable is non-NULL, it indicates that a Tcl variable has
720 * been mapped to this vector.
721 *
722 * ----------------------------------------------------------------------
723 */
724int
725Blt_VectorMapVariable(interp, vPtr, name)
726 Tcl_Interp *interp;
727 VectorObject *vPtr;
728 CONST char *name;
729{
730 Tcl_Namespace *nsPtr;
731 Tcl_CallFrame *framePtr;
732 CONST char *varName;
733 CONST char *result;
734
735 if (vPtr->arrayName != NULL) {
736 UnmapVariable(vPtr);
737 }
738 if ((name == NULL) || (name[0] == '\0')) {
739 return TCL_OK; /* If the variable name is the empty
740 * string, simply return after
741 * removing any existing variable. */
742 }
743 framePtr = NULL;
744
745 /* Get the variable name (without the namespace qualifier). */
746 if (Blt_ParseQualifiedName(interp, name, &nsPtr, &varName) != TCL_OK) {
747 Tcl_AppendResult(interp, "can't find namespace in \"", name, "\"",
748 (char *)NULL);
749 return TCL_ERROR;
750 }
751 if (nsPtr != NULL) {
752 /* [incr Tcl] 2.x doesn't like qualifiers with variable names,
753 * so we need to enter the namespace if one was designated. */
754 framePtr = Blt_EnterNamespace(interp, nsPtr);
755 }
756 /*
757 * To play it safe, delete the variable first. This has
758 * side-effect of unmapping the variable from any vector that may
759 * be currently using it.
760 */
761 Tcl_UnsetVar2(interp, (char *)varName, (char *)NULL, 0);
762
763 /* Set the index "end" in the array. This will create the
764 * variable immediately so that we can check its namespace
765 * context. */
766 result = Tcl_SetVar2(interp, (char *)varName, "end", "", TCL_LEAVE_ERR_MSG);
767
768 /* Determine if the variable is global or not. If there wasn't a
769 * namespace qualifier, it still may be global. We need to look
770 * inside the Var structure to see what it's namespace field says.
771 * NULL indicates that it's local. */
772
773 vPtr->varNsPtr = Blt_GetVariableNamespace(interp, varName);
774 vPtr->varFlags = (vPtr->varNsPtr != NULL) ?
775 (TCL_NAMESPACE_ONLY | TCL_GLOBAL_ONLY) : 0;
776
777 if (result != NULL) {
778 /* Trace the array on reads, writes, and unsets */
779 Tcl_TraceVar2(interp, (char *)varName, (char *)NULL,
780 (TRACE_ALL | vPtr->varFlags), Blt_VectorVarTrace, vPtr);
781 }
782 if ((nsPtr != NULL) && (framePtr != NULL)) {
783 Blt_LeaveNamespace(interp, framePtr); /* Go back to current */
784 }
785 vPtr->arrayName = Blt_Strdup(varName);
786 return (result == NULL) ? TCL_ERROR : TCL_OK;
787}
788
789/*
790 * ----------------------------------------------------------------------
791 *
792 * Blt_VectorChangeLength --
793 *
794 * Resizes the vector to the new size.
795 *
796 * The new size of the vector is computed by doubling the
797 * size of the vector until it fits the number of slots needed
798 * (designated by *length*).
799 *
800 * If the new size is the same as the old, simply adjust the
801 * length of the vector. Otherwise we're copying the data from
802 * one memory location to another. The trailing elements of the
803 * vector need to be reset to zero.
804 *
805 * If the storage changed memory locations, free up the old
806 * location if it was dynamically allocated.
807 *
808 * Results:
809 * A standard Tcl result. If the reallocation is successful,
810 * TCL_OK is returned, otherwise TCL_ERROR.
811 *
812 * Side effects:
813 * Memory for the array is reallocated.
814 *
815 * ----------------------------------------------------------------------
816 */
817
818int
819Blt_VectorChangeLength(vPtr, length)
820 VectorObject *vPtr;
821 int length;
822{
823 int newSize; /* Size of array in elements */
824 double *newArr;
825 Tcl_FreeProc *freeProc;
826
827 newArr = NULL;
828 newSize = 0;
829 freeProc = TCL_STATIC;
830
831 if (length > 0) {
832 int wanted, used;
833
834 wanted = length;
835 used = vPtr->length;
836
837 /* Compute the new size by doubling old size until it's big enough */
838 newSize = DEF_ARRAY_SIZE;
839 if (wanted > DEF_ARRAY_SIZE) {
840 while (newSize < wanted) {
841 newSize += newSize;
842 }
843 }
844 freeProc = vPtr->freeProc;
845 if (newSize == vPtr->size) {
846 newArr = vPtr->valueArr; /* Same size, use current array. */
847 } else {
848 /* Dynamically allocate memory for the new array. */
849 newArr = Blt_Malloc(newSize * sizeof(double));
850 if (newArr == NULL) {
851 Tcl_AppendResult(vPtr->interp, "can't allocate ",
852 Blt_Itoa(newSize), " elements for vector \"", vPtr->name,
853 "\"", (char *)NULL); return TCL_ERROR;
854 }
855 if (used > wanted) {
856 used = wanted;
857 }
858 /* Copy any previous data */
859 if (used > 0) {
860 memcpy(newArr, vPtr->valueArr, used * sizeof(double));
861 }
862 freeProc = TCL_DYNAMIC;
863 }
864 /* Clear any new slots that we're now using in the array */
865 if (wanted > used) {
866 memset(newArr + used, 0, (wanted - used) * sizeof(double));
867 }
868 }
869 if ((newArr != vPtr->valueArr) && (vPtr->valueArr != NULL)) {
870 /*
871 * We're not using the old storage anymore, so free it if it's
872 * not static. It's static because the user previously reset
873 * the vector with a statically allocated array (setting freeProc
874 * to TCL_STATIC).
875 */
876 if (vPtr->freeProc != TCL_STATIC) {
877 if (vPtr->freeProc == TCL_DYNAMIC) {
878 Blt_Free(vPtr->valueArr);
879 } else {
880 (*vPtr->freeProc) ((char *)vPtr->valueArr);
881 }
882 }
883 }
884 vPtr->valueArr = newArr;
885 vPtr->size = newSize;
886 vPtr->length = length;
887 vPtr->first = 0;
888 vPtr->last = length - 1;
889 vPtr->freeProc = freeProc; /* Set the type of the new storage */
890 return TCL_OK;
891}
892
893/*
894 * -----------------------------------------------------------------------
895 *
896 * Blt_ResetVector --
897 *
898 * Resets the vector data. This is called by a client to
899 * indicate that the vector data has changed. The vector does
900 * not need to point to different memory. Any clients of the
901 * vector will be notified of the change.
902 *
903 * Results:
904 * A standard Tcl result. If the new array size is invalid,
905 * TCL_ERROR is returned. Otherwise TCL_OK is returned and the
906 * new vector data is recorded.
907 *
908 * Side Effects:
909 * Any client designated callbacks will be posted. Memory may
910 * be changed for the vector array.
911 *
912 * -----------------------------------------------------------------------
913 */
914int
915Blt_VectorReset(vPtr, valueArr, length, size, freeProc)
916 VectorObject *vPtr;
917 double *valueArr; /* Array containing the elements of the
918 * vector. If NULL, indicates to reset the
919 * vector.*/
920 int length; /* The number of elements that the vector
921 * currently holds. */
922 int size; /* The maximum number of elements that the
923 * array can hold. */
924 Tcl_FreeProc *freeProc; /* Address of memory deallocation routine
925 * for the array of values. Can also be
926 * TCL_STATIC, TCL_DYNAMIC, or TCL_VOLATILE. */
927{
928 if (vPtr->valueArr != valueArr) { /* New array of values resides
929 * in different memory than
930 * the current vector. */
931 if ((valueArr == NULL) || (size == 0)) {
932 /* Empty array. Set up default values */
933 freeProc = TCL_STATIC;
934 valueArr = NULL;
935 size = length = 0;
936 } else if (freeProc == TCL_VOLATILE) {
937 double *newArr;
938 /* Data is volatile. Make a copy of the value array. */
939 newArr = Blt_Malloc(size * sizeof(double));
940 if (newArr == NULL) {
941 Tcl_AppendResult(vPtr->interp, "can't allocate ",
942 Blt_Itoa(size), " elements for vector \"",
943 vPtr->name, "\"", (char *)NULL);
944 return TCL_ERROR;
945 }
946 memcpy((char *)newArr, (char *)valueArr,
947 sizeof(double) * length);
948 valueArr = newArr;
949 freeProc = TCL_DYNAMIC;
950 }
951
952 if (vPtr->freeProc != TCL_STATIC) {
953 /* Old data was dynamically allocated. Free it before
954 * attaching new data. */
955 if (vPtr->freeProc == TCL_DYNAMIC) {
956 Blt_Free(vPtr->valueArr);
957 } else {
958 (*freeProc) ((char *)vPtr->valueArr);
959 }
960 }
961 vPtr->freeProc = freeProc;
962 vPtr->valueArr = valueArr;
963 vPtr->size = size;
964 }
965
966 vPtr->length = length;
967 if (vPtr->flush) {
968 Blt_VectorFlushCache(vPtr);
969 }
970 Blt_VectorUpdateClients(vPtr);
971 return TCL_OK;
972}
973
974VectorObject *
975Blt_VectorNew(dataPtr)
976 VectorInterpData *dataPtr; /* Interpreter-specific data. */
977{
978 VectorObject *vPtr;
979
980 vPtr = Blt_Calloc(1, sizeof(VectorObject));
981 assert(vPtr);
982 vPtr->notifyFlags = NOTIFY_WHENIDLE;
983 vPtr->freeProc = TCL_STATIC;
984 vPtr->dataPtr = dataPtr;
985 vPtr->valueArr = NULL;
986 vPtr->length = vPtr->size = 0;
987 vPtr->interp = dataPtr->interp;
988 vPtr->hashPtr = NULL;
989 vPtr->chainPtr = Blt_ChainCreate();
990 vPtr->flush = FALSE;
991 vPtr->min = vPtr->max = bltNaN;
992 return vPtr;
993}
994
995/*
996 * ----------------------------------------------------------------------
997 *
998 * Blt_VectorFree --
999 *
1000 * Removes the memory and frees resources associated with the
1001 * vector.
1002 *
1003 * o Removes the trace and the Tcl array variable and unsets
1004 * the variable.
1005 * o Notifies clients of the vector that the vector is being
1006 * destroyed.
1007 * o Removes any clients that are left after notification.
1008 * o Frees the memory (if necessary) allocated for the array.
1009 * o Removes the entry from the hash table of vectors.
1010 * o Frees the memory allocated for the name.
1011 *
1012 * Results:
1013 * None.
1014 *
1015 * Side effects:
1016 *
1017 * ----------------------------------------------------------------------
1018 */
1019void
1020Blt_VectorFree(vPtr)
1021 VectorObject *vPtr;
1022{
1023 Blt_ChainLink *linkPtr;
1024 VectorClient *clientPtr;
1025
1026 if (vPtr->cmdToken != 0) {
1027 DeleteCommand(vPtr);
1028 }
1029 if (vPtr->arrayName != NULL) {
1030 UnmapVariable(vPtr);
1031 }
1032 vPtr->length = 0;
1033
1034 /* Immediately notify clients that vector is going away */
1035 if (vPtr->notifyFlags & NOTIFY_PENDING) {
1036 vPtr->notifyFlags &= ~NOTIFY_PENDING;
1037 Tcl_CancelIdleCall(Blt_VectorNotifyClients, vPtr);
1038 }
1039 vPtr->notifyFlags |= NOTIFY_DESTROYED;
1040 Blt_VectorNotifyClients(vPtr);
1041
1042 for (linkPtr = Blt_ChainFirstLink(vPtr->chainPtr); linkPtr != NULL;
1043 linkPtr = Blt_ChainNextLink(linkPtr)) {
1044 clientPtr = Blt_ChainGetValue(linkPtr);
1045 Blt_Free(clientPtr);
1046 }
1047 Blt_ChainDestroy(vPtr->chainPtr);
1048 if ((vPtr->valueArr != NULL) && (vPtr->freeProc != TCL_STATIC)) {
1049 if (vPtr->freeProc == TCL_DYNAMIC) {
1050 Blt_Free(vPtr->valueArr);
1051 } else {
1052 (*vPtr->freeProc) ((char *)vPtr->valueArr);
1053 }
1054 }
1055 if (vPtr->hashPtr != NULL) {
1056 Blt_DeleteHashEntry(&(vPtr->dataPtr->vectorTable), vPtr->hashPtr);
1057 }
1058#ifdef NAMESPACE_DELETE_NOTIFY
1059 if (vPtr->nsPtr != NULL) {
1060 Blt_DestroyNsDeleteNotify(vPtr->interp, vPtr->nsPtr, vPtr);
1061 }
1062#endif /* NAMESPACE_DELETE_NOTIFY */
1063 Blt_Free(vPtr);
1064}
1065
1066/*
1067 * ----------------------------------------------------------------------
1068 *
1069 * VectorInstDeleteProc --
1070 *
1071 * Deletes the command associated with the vector. This is
1072 * called only when the command associated with the vector is
1073 * destroyed.
1074 *
1075 * Results:
1076 * None.
1077 *
1078 * ----------------------------------------------------------------------
1079 */
1080static void
1081VectorInstDeleteProc(clientData)
1082 ClientData clientData;
1083{
1084 VectorObject *vPtr = clientData;
1085
1086 vPtr->cmdToken = 0;
1087 Blt_VectorFree(vPtr);
1088}
1089
1090/*
1091 * ----------------------------------------------------------------------
1092 *
1093 * Blt_VectorCreate --
1094 *
1095 * Creates a vector structure and the following items:
1096 *
1097 * o Tcl command
1098 * o Tcl array variable and establishes traces on the variable
1099 * o Adds a new entry in the vector hash table
1100 *
1101 * Results:
1102 * A pointer to the new vector structure. If an error occurred
1103 * NULL is returned and an error message is left in
1104 * interp->result.
1105 *
1106 * Side effects:
1107 * A new Tcl command and array variable is added to the
1108 * interpreter.
1109 *
1110 * ---------------------------------------------------------------------- */
1111VectorObject *
1112Blt_VectorCreate(dataPtr, vecName, cmdName, varName, newPtr)
1113 VectorInterpData *dataPtr; /* Interpreter-specific data. */
1114 CONST char *vecName; /* Namespace-qualified name of the vector */
1115 CONST char *cmdName; /* Name of the Tcl command mapped to
1116 * the vector */
1117 CONST char *varName; /* Name of the Tcl array mapped to the
1118 * vector */
1119 int *newPtr;
1120{
1121 Tcl_DString dString;
1122 VectorObject *vPtr;
1123 int isNew;
1124 CONST char *name;
1125 char *qualName;
1126 Tcl_Namespace *nsPtr;
1127 Blt_HashEntry *hPtr;
1128 Tcl_Interp *interp = dataPtr->interp;
1129
1130 isNew = 0;
1131 nsPtr = NULL;
1132 vPtr = NULL;
1133
1134 if (Blt_ParseQualifiedName(interp, vecName, &nsPtr, &name) != TCL_OK) {
1135 Tcl_AppendResult(interp, "can't find namespace in \"", vecName, "\"",
1136 (char *)NULL);
1137 return NULL;
1138 }
1139 if (nsPtr == NULL) {
1140 nsPtr = Tcl_GetCurrentNamespace(interp);
1141 }
1142 Tcl_DStringInit(&dString);
1143 if ((name[0] == '#') && (strcmp(name, "#auto") == 0)) {
1144 char string[200];
1145
1146 do { /* Generate a unique vector name. */
1147 sprintf(string, "vector%d", dataPtr->nextId++);
1148 qualName = Blt_GetQualifiedName(nsPtr, string, &dString);
1149 hPtr = Blt_FindHashEntry(&(dataPtr->vectorTable), qualName);
1150 } while (hPtr != NULL);
1151 } else {
1152 register CONST char *p;
1153
1154 for (p = name; *p != '\0'; p++) {
1155 if (!VECTOR_CHAR(*p)) {
1156 Tcl_AppendResult(interp, "bad vector name \"", name,
1157 "\": must contain digits, letters, underscore, or period",
1158 (char *)NULL);
1159 goto error;
1160 }
1161 }
1162 qualName = Blt_GetQualifiedName(nsPtr, name, &dString);
1163 vPtr = Blt_VectorParseElement((Tcl_Interp *)NULL, dataPtr, qualName,
1164 (char **)NULL, NS_SEARCH_CURRENT);
1165 }
1166 if (vPtr == NULL) {
1167 hPtr = Blt_CreateHashEntry(&(dataPtr->vectorTable), qualName, &isNew);
1168 vPtr = Blt_VectorNew(dataPtr);
1169 vPtr->hashPtr = hPtr;
1170 vPtr->nsPtr = nsPtr;
1171
1172 vPtr->name = Blt_GetHashKey(&(dataPtr->vectorTable), hPtr);
1173#ifdef NAMESPACE_DELETE_NOTIFY
1174 Blt_CreateNsDeleteNotify(interp, nsPtr, vPtr, VectorInstDeleteProc);
1175#endif /* NAMESPACE_DELETE_NOTIFY */
1176 Blt_SetHashValue(hPtr, vPtr);
1177 }
1178 if (cmdName != NULL) {
1179 Tcl_CmdInfo cmdInfo;
1180
1181 if ((cmdName == vecName) ||
1182 ((name[0] == '#') && (strcmp(name, "#auto") == 0))) {
1183 cmdName = qualName;
1184 }
1185 if (Tcl_GetCommandInfo(interp, (char *)cmdName, &cmdInfo)) {
1186#if TCL_MAJOR_VERSION > 7
1187 if (vPtr != cmdInfo.objClientData) {
1188#else
1189 if (vPtr != cmdInfo.clientData) {
1190#endif
1191 Tcl_AppendResult(interp, "command \"", cmdName,
1192 "\" already exists", (char *)NULL);
1193 goto error;
1194 }
1195 /* We get here only if the old name is the same as the new. */
1196 goto checkVariable;
1197 }
1198 }
1199 if (vPtr->cmdToken != 0) {
1200 DeleteCommand(vPtr); /* Command already exists, delete old first */
1201 }
1202 if (cmdName != NULL) {
1203#if (TCL_MAJOR_VERSION == 7)
1204 vPtr->cmdToken = Blt_CreateCommand(interp, cmdName, Blt_VectorInstCmd,
1205 vPtr, VectorInstDeleteProc);
1206#else
1207 Tcl_DString dString2;
1208
1209 Tcl_DStringInit(&dString2);
1210 if (cmdName != qualName) {
1211 if (Blt_ParseQualifiedName(interp, cmdName, &nsPtr, &name)
1212 != TCL_OK) {
1213 Tcl_AppendResult(interp, "can't find namespace in \"", cmdName,
1214 "\"", (char *)NULL);
1215 goto error;
1216 }
1217 if (nsPtr == NULL) {
1218 nsPtr = Tcl_GetCurrentNamespace(interp);
1219 }
1220 cmdName = Blt_GetQualifiedName(nsPtr, name, &dString2);
1221 }
1222 vPtr->cmdToken = Tcl_CreateObjCommand(interp, (char *)cmdName,
1223 Blt_VectorInstCmd, vPtr, VectorInstDeleteProc);
1224 Tcl_DStringFree(&dString2);
1225#endif
1226 }
1227 checkVariable:
1228 if (varName != NULL) {
1229 if ((varName[0] == '#') && (strcmp(varName, "#auto") == 0)) {
1230 varName = qualName;
1231 }
1232 if (Blt_VectorMapVariable(interp, vPtr, varName) != TCL_OK) {
1233 goto error;
1234 }
1235 }
1236
1237 Tcl_DStringFree(&dString);
1238 *newPtr = isNew;
1239 return vPtr;
1240
1241 error:
1242 Tcl_DStringFree(&dString);
1243 if (vPtr != NULL) {
1244 Blt_VectorFree(vPtr);
1245 }
1246 return NULL;
1247}
1248
1249
1250int
1251Blt_VectorDuplicate(destPtr, srcPtr)
1252 VectorObject *destPtr, *srcPtr;
1253{
1254 int nBytes;
1255 int length;
1256
1257 if (destPtr == srcPtr) {
1258 /* Copying the same vector. */
1259 }
1260 length = srcPtr->last - srcPtr->first + 1;
1261 if (Blt_VectorChangeLength(destPtr, length) != TCL_OK) {
1262 return TCL_ERROR;
1263 }
1264 nBytes = length * sizeof(double);
1265 memcpy(destPtr->valueArr, srcPtr->valueArr + srcPtr->first, nBytes);
1266 destPtr->offset = srcPtr->offset;
1267 return TCL_OK;
1268}
1269
1270
1271
1272/*
1273 *----------------------------------------------------------------------
1274 *
1275 * VectorNamesOp --
1276 *
1277 * Reports the names of all the current vectors in the interpreter.
1278 *
1279 * Results:
1280 * A standard Tcl result. interp->result will contain a list of
1281 * all the names of the vector instances.
1282 *
1283 *----------------------------------------------------------------------
1284 */
1285/*ARGSUSED*/
1286static int
1287VectorNamesOp(clientData, interp, argc, argv)
1288 ClientData clientData; /* Interpreter-specific data. */
1289 Tcl_Interp *interp;
1290 int argc;
1291 char **argv;
1292{
1293 VectorInterpData *dataPtr = clientData;
1294 Blt_HashEntry *hPtr;
1295 char *name;
1296 Blt_HashSearch cursor;
1297
1298 for (hPtr = Blt_FirstHashEntry(&(dataPtr->vectorTable), &cursor);
1299 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1300 name = Blt_GetHashKey(&(dataPtr->vectorTable), hPtr);
1301 if ((argc == 2) || (Tcl_StringMatch(name, argv[2]))) {
1302 Tcl_AppendElement(interp, name);
1303 }
1304 }
1305 return TCL_OK;
1306}
1307
1308/*
1309 *----------------------------------------------------------------------
1310 *
1311 * VectorCreateOp --
1312 *
1313 * Creates a Tcl command, and array variable representing an
1314 * instance of a vector.
1315 *
1316 * vector a
1317 * vector b(20)
1318 * vector c(-5:14)
1319 *
1320 * Results:
1321 * A standard Tcl result.
1322 *
1323 * Side effects:
1324 * See the user documentation.
1325 *
1326 *----------------------------------------------------------------------
1327 */
1328/*ARGSUSED*/
1329static int
1330VectorCreate2(clientData, interp, argStart, argc, argv)
1331 ClientData clientData; /* Interpreter-specific data. */
1332 Tcl_Interp *interp;
1333 int argStart;
1334 int argc;
1335 char **argv;
1336{
1337 VectorInterpData *dataPtr = clientData;
1338 VectorObject *vPtr;
1339 char *leftParen, *rightParen;
1340 int isNew, size, first, last;
1341 char *cmdName, *varName;
1342 int length;
1343 int inspectFlags, freeOnUnset, flush;
1344 char **nameArr;
1345 int count;
1346 register int i;
1347
1348 /*
1349 * Handle switches to the vector command and collect the vector
1350 * name arguments into an array.
1351 */
1352 varName = cmdName = NULL;
1353 freeOnUnset = 0;
1354 nameArr = Blt_Malloc(sizeof(char *) * argc);
1355 assert(nameArr);
1356
1357 inspectFlags = TRUE;
1358 flush = FALSE;
1359 count = 0;
1360 vPtr = NULL;
1361 for (i = argStart; i < argc; i++) {
1362 if ((inspectFlags) && (argv[i][0] == '-')) {
1363 length = strlen(argv[i]);
1364 if ((length > 1) &&
1365 (strncmp(argv[i], "-variable", length) == 0)) {
1366 if ((i + 1) == argc) {
1367 Tcl_AppendResult(interp,
1368 "no variable name supplied with \"",
1369 argv[i], "\" switch", (char *)NULL);
1370 goto error;
1371 }
1372 i++;
1373 varName = argv[i];
1374 } else if ((length > 1) &&
1375 (strncmp(argv[i], "-command", length) == 0)) {
1376 if ((i + 1) == argc) {
1377 Tcl_AppendResult(interp,
1378 "no command name supplied with \"",
1379 argv[i], "\" switch", (char *)NULL);
1380 goto error;
1381 }
1382 i++;
1383 cmdName = argv[i];
1384 } else if ((length > 1) &&
1385 (strncmp(argv[i], "-watchunset", length) == 0)) {
1386 int bool;
1387
1388 if ((i + 1) == argc) {
1389 Tcl_AppendResult(interp, "no value name supplied with \"",
1390 argv[i], "\" switch", (char *)NULL);
1391 goto error;
1392 }
1393 i++;
1394 if (Tcl_GetBoolean(interp, argv[i], &bool) != TCL_OK) {
1395 goto error;
1396 }
1397 freeOnUnset = bool;
1398 } else if ((length > 1) && (strncmp(argv[i], "-flush", length) == 0)) {
1399 int bool;
1400
1401 if ((i + 1) == argc) {
1402 Tcl_AppendResult(interp, "no value name supplied with \"",
1403 argv[i], "\" switch", (char *)NULL);
1404 goto error;
1405 }
1406 i++;
1407 if (Tcl_GetBoolean(interp, argv[i], &bool) != TCL_OK) {
1408 goto error;
1409 }
1410 flush = bool;
1411 } else if ((length > 1) && (argv[i][1] == '-') &&
1412 (argv[i][2] == '\0')) {
1413 inspectFlags = FALSE; /* Allow vector names to start with - */
1414 } else {
1415 Tcl_AppendResult(interp, "bad vector switch \"", argv[i], "\"",
1416 (char *)NULL);
1417 goto error;
1418 }
1419 } else {
1420 nameArr[count++] = argv[i];
1421 }
1422 }
1423 if (count == 0) {
1424 Tcl_AppendResult(interp, "no vector names supplied", (char *)NULL);
1425 goto error;
1426 }
1427 if (count > 1) {
1428 if ((cmdName != NULL) && (cmdName[0] != '\0')) {
1429 Tcl_AppendResult(interp,
1430 "can't specify more than one vector with \"-command\" switch",
1431 (char *)NULL);
1432 goto error;
1433 }
1434 if ((varName != NULL) && (varName[0] != '\0')) {
1435 Tcl_AppendResult(interp,
1436 "can't specify more than one vector with \"-variable\" switch",
1437 (char *)NULL);
1438 goto error;
1439 }
1440 }
1441 for (i = 0; i < count; i++) {
1442 size = first = last = 0;
1443 leftParen = strchr(nameArr[i], '(');
1444 rightParen = strchr(nameArr[i], ')');
1445 if (((leftParen != NULL) && (rightParen == NULL)) ||
1446 ((leftParen == NULL) && (rightParen != NULL)) ||
1447 (leftParen > rightParen)) {
1448 Tcl_AppendResult(interp, "bad vector specification \"", nameArr[i],
1449 "\"", (char *)NULL);
1450 goto error;
1451 }
1452 if (leftParen != NULL) {
1453 int result;
1454 char *colon;
1455
1456 *rightParen = '\0';
1457 colon = strchr(leftParen + 1, ':');
1458 if (colon != NULL) {
1459
1460 /* Specification is in the form vecName(first:last) */
1461 *colon = '\0';
1462 result = Tcl_GetInt(interp, leftParen + 1, &first);
1463 if ((*(colon + 1) != '\0') && (result == TCL_OK)) {
1464 result = Tcl_GetInt(interp, colon + 1, &last);
1465 if (first > last) {
1466 Tcl_AppendResult(interp, "bad vector range \"",
1467 nameArr[i], "\"", (char *)NULL);
1468 result = TCL_ERROR;
1469 }
1470 size = (last - first) + 1;
1471 }
1472 *colon = ':';
1473 } else {
1474 /* Specification is in the form vecName(size) */
1475 result = Tcl_GetInt(interp, leftParen + 1, &size);
1476 }
1477 *rightParen = ')';
1478 if (result != TCL_OK) {
1479 goto error;
1480 }
1481 if (size < 0) {
1482 Tcl_AppendResult(interp, "bad vector size \"", nameArr[i], "\"",
1483 (char *)NULL);
1484 goto error;
1485 }
1486 }
1487 if (leftParen != NULL) {
1488 *leftParen = '\0';
1489 }
1490 /*
1491 * By default, we create a Tcl command by the name of the vector.
1492 */
1493 vPtr = Blt_VectorCreate(dataPtr, nameArr[i],
1494 (cmdName == NULL) ? nameArr[i] : cmdName,
1495 (varName == NULL) ? nameArr[i] : varName,
1496 &isNew);
1497 if (leftParen != NULL) {
1498 *leftParen = '(';
1499 }
1500 if (vPtr == NULL) {
1501 goto error;
1502 }
1503 vPtr->freeOnUnset = freeOnUnset;
1504 vPtr->flush = flush;
1505 vPtr->offset = first;
1506 if (size > 0) {
1507 if (Blt_VectorChangeLength(vPtr, size) != TCL_OK) {
1508 goto error;
1509 }
1510 }
1511 if (!isNew) {
1512 if (vPtr->flush) {
1513 Blt_VectorFlushCache(vPtr);
1514 }
1515 Blt_VectorUpdateClients(vPtr);
1516 }
1517 }
1518 Blt_Free(nameArr);
1519 if (vPtr != NULL) {
1520 /* Return the name of the last vector created */
1521 Tcl_SetResult(interp, vPtr->name, TCL_VOLATILE);
1522 }
1523 return TCL_OK;
1524 error:
1525 Blt_Free(nameArr);
1526 return TCL_ERROR;
1527}
1528
1529/*
1530 *----------------------------------------------------------------------
1531 *
1532 * VectorCreateOp --
1533 *
1534 * Creates a Tcl command, and array variable representing an
1535 * instance of a vector.
1536 *
1537 * vector a
1538 * vector b(20)
1539 * vector c(-5:14)
1540 *
1541 * Results:
1542 * A standard Tcl result.
1543 *
1544 * Side effects:
1545 * See the user documentation.
1546 *
1547 *----------------------------------------------------------------------
1548 */
1549/*ARGSUSED*/
1550static int
1551VectorCreateOp(clientData, interp, argc, argv)
1552 ClientData clientData;
1553 Tcl_Interp *interp;
1554 int argc;
1555 char **argv;
1556{
1557 return VectorCreate2(clientData, interp, 2, argc, argv);
1558}
1559
1560/*
1561 *----------------------------------------------------------------------
1562 *
1563 * VectorDestroyOp --
1564 *
1565 * Destroys the vector and its related Tcl command and array
1566 * variable (if they exist).
1567 *
1568 * Results:
1569 * A standard Tcl result.
1570 *
1571 * Side effects:
1572 * Deletes the vector.
1573 *
1574 *----------------------------------------------------------------------
1575 */
1576/*ARGSUSED*/
1577static int
1578VectorDestroyOp(clientData, interp, argc, argv)
1579 ClientData clientData; /* Interpreter-specific data. */
1580 Tcl_Interp *interp;
1581 int argc;
1582 char **argv;
1583{
1584 VectorInterpData *dataPtr = clientData;
1585 VectorObject *vPtr;
1586 register int i;
1587
1588 for (i = 2; i < argc; i++) {
1589 if (Blt_VectorLookupName(dataPtr, argv[i], &vPtr) != TCL_OK) {
1590 return TCL_ERROR;
1591 }
1592 Blt_VectorFree(vPtr);
1593 }
1594 return TCL_OK;
1595}
1596
1597static Blt_OpSpec vectorCmdOps[] =
1598{
1599 {"create", 1, (Blt_Op)VectorCreateOp, 3, 0,
1600 "vecName ?vecName...? ?switches...?",},
1601 {"destroy", 1, (Blt_Op)VectorDestroyOp, 3, 0,
1602 "vecName ?vecName...?",},
1603 {"names", 1, (Blt_Op)VectorNamesOp, 2, 3, "?pattern?...",},
1604};
1605
1606static int nCmdOps = sizeof(vectorCmdOps) / sizeof(Blt_OpSpec);
1607
1608/*ARGSUSED*/
1609static int
1610VectorCmd(clientData, interp, argc, argv)
1611 ClientData clientData; /* Interpreter-specific data. */
1612 Tcl_Interp *interp;
1613 int argc;
1614 char **argv;
1615{
1616 Blt_Op proc;
1617
1618 /*
1619 * Try to replicate the old vector command's behavior:
1620 */
1621 if (argc > 1) {
1622 char c;
1623 register int i;
1624 register Blt_OpSpec *specPtr;
1625
1626 c = argv[1][0];
1627 for (specPtr = vectorCmdOps, i = 0; i < nCmdOps; i++, specPtr++) {
1628 if ((c == specPtr->name[0]) &&
1629 (strcmp(argv[1], specPtr->name) == 0)) {
1630 goto doOp;
1631 }
1632 }
1633 /*
1634 * The first argument is not an operation, so assume that its
1635 * actually the name of a vector to be created
1636 */
1637 return VectorCreate2(clientData, interp, 1, argc, argv);
1638 }
1639 doOp:
1640 /* Do the usual vector operation lookup now. */
1641 proc = Blt_GetOp(interp, nCmdOps, vectorCmdOps, BLT_OP_ARG1, argc, argv,0);
1642 if (proc == NULL) {
1643 return TCL_ERROR;
1644 }
1645 return (*proc) (clientData, interp, argc, argv);
1646}
1647
1648/*
1649 * -----------------------------------------------------------------------
1650 *
1651 * VectorInterpDeleteProc --
1652 *
1653 * This is called when the interpreter hosting the "vector" command
1654 * is deleted.
1655 *
1656 * Results:
1657 * None.
1658 *
1659 * Side effects:
1660 * Destroys the math and index hash tables. In addition removes
1661 * the hash table managing all vector names.
1662 *
1663 * ------------------------------------------------------------------------
1664 */
1665/* ARGSUSED */
1666static void
1667VectorInterpDeleteProc(clientData, interp)
1668 ClientData clientData; /* Interpreter-specific data. */
1669 Tcl_Interp *interp;
1670{
1671 VectorInterpData *dataPtr = clientData;
1672 Blt_HashEntry *hPtr;
1673 Blt_HashSearch cursor;
1674 VectorObject *vPtr;
1675
1676 for (hPtr = Blt_FirstHashEntry(&(dataPtr->vectorTable), &cursor);
1677 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1678 vPtr = (VectorObject *)Blt_GetHashValue(hPtr);
1679 vPtr->hashPtr = NULL;
1680 Blt_VectorFree(vPtr);
1681 }
1682 Blt_DeleteHashTable(&(dataPtr->vectorTable));
1683
1684 /* If any user-defined math functions were installed, remove them. */
1685 Blt_DeleteHashTable(&(dataPtr->mathProcTable));
1686
1687 Blt_DeleteHashTable(&(dataPtr->indexProcTable));
1688 Tcl_DeleteAssocData(interp, VECTOR_THREAD_KEY);
1689 Blt_Free(dataPtr);
1690}
1691
1692VectorInterpData *
1693Blt_VectorGetInterpData(interp)
1694 Tcl_Interp *interp;
1695{
1696 VectorInterpData *dataPtr;
1697 Tcl_InterpDeleteProc *proc;
1698
1699 dataPtr = (VectorInterpData *)
1700 Tcl_GetAssocData(interp, VECTOR_THREAD_KEY, &proc);
1701 if (dataPtr == NULL) {
1702 dataPtr = Blt_Malloc(sizeof(VectorInterpData));
1703 assert(dataPtr);
1704 dataPtr->interp = interp;
1705 dataPtr->nextId = 0;
1706 Tcl_SetAssocData(interp, VECTOR_THREAD_KEY, VectorInterpDeleteProc,
1707 dataPtr);
1708 Blt_InitHashTable(&(dataPtr->vectorTable), BLT_STRING_KEYS);
1709 Blt_InitHashTable(&(dataPtr->mathProcTable), BLT_STRING_KEYS);
1710 Blt_InitHashTable(&(dataPtr->indexProcTable), BLT_STRING_KEYS);
1711 srand48(time((time_t *) NULL));
1712 }
1713 return dataPtr;
1714}
1715
1716/*
1717 * -----------------------------------------------------------------------
1718 *
1719 * Blt_VectorInit --
1720 *
1721 * This procedure is invoked to initialize the "vector" command.
1722 *
1723 * Results:
1724 * None.
1725 *
1726 * Side effects:
1727 * Creates the new command and adds a new entry into a global Tcl
1728 * associative array.
1729 *
1730 * ------------------------------------------------------------------------
1731 */
1732
1733int
1734Blt_VectorInit(interp)
1735 Tcl_Interp *interp;
1736{
1737 VectorInterpData *dataPtr; /* Interpreter-specific data. */
1738 static Blt_CmdSpec cmdSpec = {"vector", VectorCmd, };
1739
1740 dataPtr = Blt_VectorGetInterpData(interp);
1741 /*
1742 * This routine may be run several times in the same interpreter.
1743 * For example, if someone tries to initial the BLT commands from
1744 * another namespace. Keep a reference count, so we know when it's
1745 * safe to clean up.
1746 */
1747 cmdSpec.clientData = dataPtr;
1748 if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
1749 return TCL_ERROR;
1750 }
1751 return TCL_OK;
1752}
1753
1754
1755
1756
1757/* C Application interface to vectors */
1758
1759/*
1760 * -----------------------------------------------------------------------
1761 *
1762 * Blt_CreateVector --
1763 *
1764 * Creates a new vector by the name and size.
1765 *
1766 * Results:
1767 * A standard Tcl result. If the new array size is invalid or a
1768 * vector already exists by that name, TCL_ERROR is returned.
1769 * Otherwise TCL_OK is returned and the new vector is created.
1770 *
1771 * Side Effects:
1772 * Memory will be allocated for the new vector. A new Tcl command
1773 * and Tcl array variable will be created.
1774 *
1775 * -----------------------------------------------------------------------
1776 */
1777
1778/*LINTLIBRARY*/
1779int
1780Blt_CreateVector2(interp, vecName, cmdName, varName, initialSize, vecPtrPtr)
1781 Tcl_Interp *interp;
1782 char *vecName;
1783 char *cmdName, *varName;
1784 int initialSize;
1785 Blt_Vector **vecPtrPtr;
1786{
1787 VectorInterpData *dataPtr; /* Interpreter-specific data. */
1788 VectorObject *vPtr;
1789 int isNew;
1790 char *nameCopy;
1791
1792 if (initialSize < 0) {
1793 Tcl_AppendResult(interp, "bad vector size \"", Blt_Itoa(initialSize),
1794 "\"", (char *)NULL);
1795 return TCL_ERROR;
1796 }
1797 dataPtr = Blt_VectorGetInterpData(interp);
1798
1799 nameCopy = Blt_Strdup(vecName);
1800 vPtr = Blt_VectorCreate(dataPtr, nameCopy, cmdName, varName, &isNew);
1801 Blt_Free(nameCopy);
1802
1803 if (vPtr == NULL) {
1804 return TCL_ERROR;
1805 }
1806 if (initialSize > 0) {
1807 if (Blt_VectorChangeLength(vPtr, initialSize) != TCL_OK) {
1808 return TCL_ERROR;
1809 }
1810 }
1811 if (vecPtrPtr != NULL) {
1812 *vecPtrPtr = (Blt_Vector *) vPtr;
1813 }
1814 return TCL_OK;
1815}
1816
1817int
1818Blt_CreateVector(interp, name, size, vecPtrPtr)
1819 Tcl_Interp *interp;
1820 char *name;
1821 int size;
1822 Blt_Vector **vecPtrPtr;
1823{
1824 return Blt_CreateVector2(interp, name, name, name, size, vecPtrPtr);
1825}
1826
1827/*
1828 * -----------------------------------------------------------------------
1829 *
1830 * Blt_DeleteVector --
1831 *
1832 * Deletes the vector of the given name. All clients with
1833 * designated callback routines will be notified.
1834 *
1835 * Results:
1836 * A standard Tcl result. If no vector exists by that name,
1837 * TCL_ERROR is returned. Otherwise TCL_OK is returned and
1838 * vector is deleted.
1839 *
1840 * Side Effects:
1841 * Memory will be released for the new vector. Both the Tcl
1842 * command and array variable will be deleted. All clients which
1843 * set call back procedures will be notified.
1844 *
1845 * -----------------------------------------------------------------------
1846 */
1847/*LINTLIBRARY*/
1848int
1849Blt_DeleteVector(vecPtr)
1850 Blt_Vector *vecPtr;
1851{
1852 VectorObject *vPtr = (VectorObject *)vecPtr;
1853
1854 Blt_VectorFree(vPtr);
1855 return TCL_OK;
1856}
1857
1858/*
1859 * -----------------------------------------------------------------------
1860 *
1861 * Blt_DeleteVectorByName --
1862 *
1863 * Deletes the vector of the given name. All clients with
1864 * designated callback routines will be notified.
1865 *
1866 * Results:
1867 * A standard Tcl result. If no vector exists by that name,
1868 * TCL_ERROR is returned. Otherwise TCL_OK is returned and
1869 * vector is deleted.
1870 *
1871 * Side Effects:
1872 * Memory will be released for the new vector. Both the Tcl
1873 * command and array variable will be deleted. All clients which
1874 * set call back procedures will be notified.
1875 *
1876 * -----------------------------------------------------------------------
1877 */
1878/*LINTLIBRARY*/
1879int
1880Blt_DeleteVectorByName(interp, name)
1881 Tcl_Interp *interp;
1882 char *name;
1883{
1884 VectorInterpData *dataPtr; /* Interpreter-specific data. */
1885 VectorObject *vPtr;
1886 char *nameCopy;
1887 int result;
1888
1889 /*
1890 * If the vector name was passed via a read-only string (e.g. "x"),
1891 * the Blt_VectorParseElement routine will segfault when it tries to write
1892 * into the string. Therefore make a writable copy and free it
1893 * when we're done.
1894 */
1895 nameCopy = Blt_Strdup(name);
1896 dataPtr = Blt_VectorGetInterpData(interp);
1897 result = Blt_VectorLookupName(dataPtr, nameCopy, &vPtr);
1898 Blt_Free(nameCopy);
1899
1900 if (result != TCL_OK) {
1901 return TCL_ERROR;
1902 }
1903 Blt_VectorFree(vPtr);
1904 return TCL_OK;
1905}
1906
1907/*
1908 * ----------------------------------------------------------------------
1909 *
1910 * Blt_VectorExists2 --
1911 *
1912 * Returns whether the vector associated with the client token
1913 * still exists.
1914 *
1915 * Results:
1916 * Returns 1 is the vector still exists, 0 otherwise.
1917 *
1918 * ----------------------------------------------------------------------
1919 */
1920int
1921Blt_VectorExists2(interp, vecName)
1922 Tcl_Interp *interp;
1923 char *vecName;
1924{
1925 VectorInterpData *dataPtr; /* Interpreter-specific data. */
1926
1927 dataPtr = Blt_VectorGetInterpData(interp);
1928 if (GetVectorObject(dataPtr, vecName, NS_SEARCH_BOTH) != NULL) {
1929 return TRUE;
1930 }
1931 return FALSE;
1932}
1933
1934/*
1935 * ----------------------------------------------------------------------
1936 *
1937 * Blt_VectorExists --
1938 *
1939 * Returns whether the vector associated with the client token
1940 * still exists.
1941 *
1942 * Results:
1943 * Returns 1 is the vector still exists, 0 otherwise.
1944 *
1945 * ----------------------------------------------------------------------
1946 */
1947int
1948Blt_VectorExists(interp, vecName)
1949 Tcl_Interp *interp;
1950 char *vecName;
1951{
1952 char *nameCopy;
1953 int result;
1954
1955 /*
1956 * If the vector name was passed via a read-only string (e.g. "x"),
1957 * the Blt_VectorParseName routine will segfault when it tries to write
1958 * into the string. Therefore make a writable copy and free it
1959 * when we're done.
1960 */
1961 nameCopy = Blt_Strdup(vecName);
1962 result = Blt_VectorExists2(interp, nameCopy);
1963 Blt_Free(nameCopy);
1964 return result;
1965}
1966
1967/*
1968 * -----------------------------------------------------------------------
1969 *
1970 * Blt_GetVector --
1971 *
1972 * Returns a pointer to the vector associated with the given name.
1973 *
1974 * Results:
1975 * A standard Tcl result. If there is no vector "name", TCL_ERROR
1976 * is returned. Otherwise TCL_OK is returned and vecPtrPtr will
1977 * point to the vector.
1978 *
1979 * -----------------------------------------------------------------------
1980 */
1981int
1982Blt_GetVector(interp, name, vecPtrPtr)
1983 Tcl_Interp *interp;
1984 char *name;
1985 Blt_Vector **vecPtrPtr;
1986{
1987 VectorInterpData *dataPtr; /* Interpreter-specific data. */
1988 VectorObject *vPtr;
1989 char *nameCopy;
1990 int result;
1991
1992 dataPtr = Blt_VectorGetInterpData(interp);
1993 /*
1994 * If the vector name was passed via a read-only string (e.g. "x"),
1995 * the Blt_VectorParseName routine will segfault when it tries to write
1996 * into the string. Therefore make a writable copy and free it
1997 * when we're done.
1998 */
1999 nameCopy = Blt_Strdup(name);
2000 result = Blt_VectorLookupName(dataPtr, nameCopy, &vPtr);
2001 Blt_Free(nameCopy);
2002 if (result != TCL_OK) {
2003 return TCL_ERROR;
2004 }
2005 Blt_VectorUpdateRange(vPtr);
2006 *vecPtrPtr = (Blt_Vector *) vPtr;
2007 return TCL_OK;
2008}
2009
2010/*
2011 * -----------------------------------------------------------------------
2012 *
2013 * Blt_ResetVector --
2014 *
2015 * Resets the vector data. This is called by a client to
2016 * indicate that the vector data has changed. The vector does
2017 * not need to point to different memory. Any clients of the
2018 * vector will be notified of the change.
2019 *
2020 * Results:
2021 * A standard Tcl result. If the new array size is invalid,
2022 * TCL_ERROR is returned. Otherwise TCL_OK is returned and the
2023 * new vector data is recorded.
2024 *
2025 * Side Effects:
2026 * Any client designated callbacks will be posted. Memory may
2027 * be changed for the vector array.
2028 *
2029 * -----------------------------------------------------------------------
2030 */
2031int
2032Blt_ResetVector(vecPtr, valueArr, length, size, freeProc)
2033 Blt_Vector *vecPtr;
2034 double *valueArr; /* Array containing the elements of the
2035 * vector. If NULL, indicates to reset the
2036 * vector.*/
2037 int length; /* The number of elements that the vector
2038 * currently holds. */
2039 int size; /* The maximum number of elements that the
2040 * array can hold. */
2041 Tcl_FreeProc *freeProc; /* Address of memory deallocation routine
2042 * for the array of values. Can also be
2043 * TCL_STATIC, TCL_DYNAMIC, or TCL_VOLATILE. */
2044{
2045 VectorObject *vPtr = (VectorObject *)vecPtr;
2046
2047 if (size < 0) {
2048 Tcl_AppendResult(vPtr->interp, "bad array size", (char *)NULL);
2049 return TCL_ERROR;
2050 }
2051 return Blt_VectorReset(vPtr, valueArr, length, size, freeProc);
2052}
2053
2054/*
2055 * -----------------------------------------------------------------------
2056 *
2057 * Blt_ResizeVector --
2058 *
2059 * Changes the size of the vector. All clients with designated
2060 * callback routines will be notified of the size change.
2061 *
2062 * Results:
2063 * A standard Tcl result. If no vector exists by that name,
2064 * TCL_ERROR is returned. Otherwise TCL_OK is returned and
2065 * vector is resized.
2066 *
2067 * Side Effects:
2068 * Memory may be reallocated for the new vector size. All clients
2069 * which set call back procedures will be notified.
2070 *
2071 * -----------------------------------------------------------------------
2072 */
2073int
2074Blt_ResizeVector(vecPtr, length)
2075 Blt_Vector *vecPtr;
2076 int length;
2077{
2078 VectorObject *vPtr = (VectorObject *)vecPtr;
2079
2080 if (Blt_VectorChangeLength(vPtr, length) != TCL_OK) {
2081 Tcl_AppendResult(vPtr->interp, "can't resize vector \"", vPtr->name,
2082 "\"", (char *)NULL);
2083 return TCL_ERROR;
2084 }
2085 if (vPtr->flush) {
2086 Blt_VectorFlushCache(vPtr);
2087 }
2088 Blt_VectorUpdateClients(vPtr);
2089 return TCL_OK;
2090}
2091
2092/*
2093 *--------------------------------------------------------------
2094 *
2095 * Blt_AllocVectorId --
2096 *
2097 * Creates an identifier token for an existing vector. The
2098 * identifier is used by the client routines to get call backs
2099 * when (and if) the vector changes.
2100 *
2101 * Results:
2102 * A standard Tcl result. If "vecName" is not associated with
2103 * a vector, TCL_ERROR is returned and interp->result is filled
2104 * with an error message.
2105 *
2106 *--------------------------------------------------------------
2107 */
2108Blt_VectorId
2109Blt_AllocVectorId(interp, name)
2110 Tcl_Interp *interp;
2111 char *name;
2112{
2113 VectorInterpData *dataPtr; /* Interpreter-specific data. */
2114 VectorObject *vPtr;
2115 VectorClient *clientPtr;
2116 Blt_VectorId clientId;
2117 int result;
2118 char *nameCopy;
2119
2120 dataPtr = Blt_VectorGetInterpData(interp);
2121 /*
2122 * If the vector name was passed via a read-only string (e.g. "x"),
2123 * the Blt_VectorParseName routine will segfault when it tries to write
2124 * into the string. Therefore make a writable copy and free it
2125 * when we're done.
2126 */
2127 nameCopy = Blt_Strdup(name);
2128 result = Blt_VectorLookupName(dataPtr, nameCopy, &vPtr);
2129 Blt_Free(nameCopy);
2130
2131 if (result != TCL_OK) {
2132 return (Blt_VectorId) 0;
2133 }
2134 /* Allocate a new client structure */
2135 clientPtr = Blt_Calloc(1, sizeof(VectorClient));
2136 assert(clientPtr);
2137 clientPtr->magic = VECTOR_MAGIC;
2138
2139 /* Add the new client to the server's list of clients */
2140 clientPtr->linkPtr = Blt_ChainAppend(vPtr->chainPtr, clientPtr);
2141 clientPtr->serverPtr = vPtr;
2142 clientId = (Blt_VectorId) clientPtr;
2143 return clientId;
2144}
2145
2146/*
2147 * -----------------------------------------------------------------------
2148 *
2149 * Blt_SetVectorChangedProc --
2150 *
2151 * Sets the routine to be called back when the vector is changed
2152 * or deleted. *clientData* will be provided as an argument. If
2153 * *proc* is NULL, no callback will be made.
2154 *
2155 * Results:
2156 * None.
2157 *
2158 * Side Effects:
2159 * The designated routine will be called when the vector is changed
2160 * or deleted.
2161 *
2162 * -----------------------------------------------------------------------
2163 */
2164void
2165Blt_SetVectorChangedProc(clientId, proc, clientData)
2166 Blt_VectorId clientId; /* Client token identifying the vector */
2167 Blt_VectorChangedProc *proc;/* Address of routine to call when the contents
2168 * of the vector change. If NULL, no routine
2169 * will be called */
2170 ClientData clientData; /* One word of information to pass along when
2171 * the above routine is called */
2172{
2173 VectorClient *clientPtr = (VectorClient *)clientId;
2174
2175 if (clientPtr->magic != VECTOR_MAGIC) {
2176 return; /* Not a valid token */
2177 }
2178 clientPtr->clientData = clientData;
2179 clientPtr->proc = proc;
2180}
2181
2182/*
2183 *--------------------------------------------------------------
2184 *
2185 * Blt_FreeVectorId --
2186 *
2187 * Releases the token for an existing vector. This indicates
2188 * that the client is no longer interested the vector. Any
2189 * previously specified callback routine will no longer be
2190 * invoked when (and if) the vector changes.
2191 *
2192 * Results:
2193 * None.
2194 *
2195 * Side Effects:
2196 * Any previously specified callback routine will no longer be
2197 * invoked when (and if) the vector changes.
2198 *
2199 *--------------------------------------------------------------
2200 */
2201void
2202Blt_FreeVectorId(clientId)
2203 Blt_VectorId clientId; /* Client token identifying the vector */
2204{
2205 VectorClient *clientPtr = (VectorClient *)clientId;
2206
2207 if (clientPtr->magic != VECTOR_MAGIC) {
2208 return; /* Not a valid token */
2209 }
2210 if (clientPtr->serverPtr != NULL) {
2211 /* Remove the client from the server's list */
2212 Blt_ChainDeleteLink(clientPtr->serverPtr->chainPtr, clientPtr->linkPtr);
2213 }
2214 Blt_Free(clientPtr);
2215}
2216
2217/*
2218 *--------------------------------------------------------------
2219 *
2220 * Blt_NameOfVectorId --
2221 *
2222 * Returns the name of the vector (and array variable).
2223 *
2224 * Results:
2225 * The name of the array variable is returned.
2226 *
2227 *--------------------------------------------------------------
2228 */
2229char *
2230Blt_NameOfVectorId(clientId)
2231 Blt_VectorId clientId; /* Client token identifying the vector */
2232{
2233 VectorClient *clientPtr = (VectorClient *)clientId;
2234
2235 if ((clientPtr->magic != VECTOR_MAGIC) || (clientPtr->serverPtr == NULL)) {
2236 return NULL;
2237 }
2238 return clientPtr->serverPtr->name;
2239}
2240
2241char *
2242Blt_NameOfVector(vecPtr)
2243 Blt_Vector *vecPtr; /* Vector to query. */
2244{
2245 VectorObject *vPtr = (VectorObject *)vecPtr;
2246 return vPtr->name;
2247}
2248
2249/*
2250 *--------------------------------------------------------------
2251 *
2252 * Blt_VectorNotifyPending --
2253 *
2254 * Returns the name of the vector (and array variable).
2255 *
2256 * Results:
2257 * The name of the array variable is returned.
2258 *
2259 *--------------------------------------------------------------
2260 */
2261int
2262Blt_VectorNotifyPending(clientId)
2263 Blt_VectorId clientId; /* Client token identifying the vector */
2264{
2265 VectorClient *clientPtr = (VectorClient *)clientId;
2266
2267 if ((clientPtr == NULL) || (clientPtr->magic != VECTOR_MAGIC) ||
2268 (clientPtr->serverPtr == NULL)) {
2269 return 0;
2270 }
2271 return (clientPtr->serverPtr->notifyFlags & NOTIFY_PENDING);
2272}
2273
2274/*
2275 * -----------------------------------------------------------------------
2276 *
2277 * Blt_GetVectorById --
2278 *
2279 * Returns a pointer to the vector associated with the client
2280 * token.
2281 *
2282 * Results:
2283 * A standard Tcl result. If the client token is not associated
2284 * with a vector any longer, TCL_ERROR is returned. Otherwise,
2285 * TCL_OK is returned and vecPtrPtr will point to vector.
2286 *
2287 * -----------------------------------------------------------------------
2288 */
2289int
2290Blt_GetVectorById(interp, clientId, vecPtrPtr)
2291 Tcl_Interp *interp;
2292 Blt_VectorId clientId; /* Client token identifying the vector */
2293 Blt_Vector **vecPtrPtr;
2294{
2295 VectorClient *clientPtr = (VectorClient *)clientId;
2296
2297 if (clientPtr->magic != VECTOR_MAGIC) {
2298 Tcl_AppendResult(interp, "bad vector token", (char *)NULL);
2299 return TCL_ERROR;
2300 }
2301 if (clientPtr->serverPtr == NULL) {
2302 Tcl_AppendResult(interp, "vector no longer exists", (char *)NULL);
2303 return TCL_ERROR;
2304 }
2305 Blt_VectorUpdateRange(clientPtr->serverPtr);
2306 *vecPtrPtr = (Blt_Vector *) clientPtr->serverPtr;
2307 return TCL_OK;
2308}
2309
2310/*LINTLIBRARY*/
2311void
2312Blt_InstallIndexProc(interp, string, procPtr)
2313 Tcl_Interp *interp;
2314 char *string;
2315 Blt_VectorIndexProc *procPtr; /* Pointer to function to be called
2316 * when the vector finds the named index.
2317 * If NULL, this indicates to remove
2318 * the index from the table.
2319 */
2320{
2321 VectorInterpData *dataPtr; /* Interpreter-specific data. */
2322 Blt_HashEntry *hPtr;
2323 int isNew;
2324
2325 dataPtr = Blt_VectorGetInterpData(interp);
2326 hPtr = Blt_CreateHashEntry(&(dataPtr->indexProcTable), string, &isNew);
2327 if (procPtr == NULL) {
2328 Blt_DeleteHashEntry(&(dataPtr->indexProcTable), hPtr);
2329 } else {
2330 Blt_SetHashValue(hPtr, procPtr);
2331 }
2332}
Note: See TracBrowser for help on using the repository browser.