source: trunk/kitgen/8.x/blt/generic/bltVecObjCmd.c@ 199

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

initial commit

File size: 52.3 KB
Line 
1
2/*
3 * bltVecCmd.c --
4 *
5 * This module implements vector data objects.
6 *
7 * Copyright 1995-1998 Lucent Technologies, Inc.
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
17 *
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
25 * software.
26 */
27
28/*
29 * TODO:
30 * o Add H. Kirsch's vector binary read operation
31 * x binread file0
32 * x binread -file file0
33 *
34 * o Add ASCII/binary file reader
35 * x read fileName
36 *
37 * o Allow Tcl-based client notifications.
38 * vector x
39 * x notify call Display
40 * x notify delete Display
41 * x notify reorder #1 #2
42 */
43
44#include "bltVecInt.h"
45
46#if (TCL_MAJOR_VERSION > 7)
47
48static
49int GetDouble(interp, objPtr, valuePtr)
50 Tcl_Interp *interp;
51 Tcl_Obj *objPtr;
52 double *valuePtr;
53{
54 /* First try to extract the value as a double precision number. */
55 if (Tcl_GetDoubleFromObj(interp, objPtr, valuePtr) == TCL_OK) {
56 return TCL_OK;
57 }
58 Tcl_ResetResult(interp);
59
60 /* Then try to parse it as an expression. */
61 if (Tcl_ExprDouble(interp, Tcl_GetString(objPtr), valuePtr) == TCL_OK) {
62 return TCL_OK;
63 }
64 return TCL_ERROR;
65}
66
67static Tcl_Obj *
68GetValues(VectorObject *vPtr, int first, int last)
69{
70 register int i;
71 Tcl_Obj *listObjPtr;
72
73 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
74 for (i = first; i <= last; i++) {
75 Tcl_ListObjAppendElement(vPtr->interp, listObjPtr,
76 Tcl_NewDoubleObj(vPtr->valueArr[i]));
77 }
78 return listObjPtr;
79}
80
81static void
82ReplicateValue(vPtr, first, last, value)
83 VectorObject *vPtr;
84 int first, last;
85 double value;
86{
87 register int i;
88
89 for (i = first; i <= last; i++) {
90 vPtr->valueArr[i] = value;
91 }
92 vPtr->notifyFlags |= UPDATE_RANGE;
93}
94
95static int
96CopyList(vPtr, objc, objv)
97 VectorObject *vPtr;
98 int objc;
99 Tcl_Obj *CONST *objv;
100{
101 register int i;
102 double value;
103
104 if (Blt_VectorChangeLength(vPtr, objc) != TCL_OK) {
105 return TCL_ERROR;
106 }
107 for (i = 0; i < objc; i++) {
108 if (GetDouble(vPtr->interp, objv[i], &value) != TCL_OK) {
109 Blt_VectorChangeLength(vPtr, i);
110 return TCL_ERROR;
111 }
112 vPtr->valueArr[i] = value;
113 }
114 return TCL_OK;
115}
116
117static int
118AppendVector(destPtr, srcPtr)
119 VectorObject *destPtr, *srcPtr;
120{
121 int nBytes;
122 int oldSize, newSize;
123
124 oldSize = destPtr->length;
125 newSize = oldSize + srcPtr->last - srcPtr->first + 1;
126 if (Blt_VectorChangeLength(destPtr, newSize) != TCL_OK) {
127 return TCL_ERROR;
128 }
129 nBytes = (newSize - oldSize) * sizeof(double);
130 memcpy((char *)(destPtr->valueArr + oldSize),
131 (srcPtr->valueArr + srcPtr->first), nBytes);
132 destPtr->notifyFlags |= UPDATE_RANGE;
133 return TCL_OK;
134}
135
136static int
137AppendList(vPtr, objc, objv)
138 VectorObject *vPtr;
139 int objc;
140 Tcl_Obj *CONST *objv;
141{
142 int count;
143 register int i;
144 double value;
145 int oldSize;
146
147 oldSize = vPtr->length;
148 if (Blt_VectorChangeLength(vPtr, vPtr->length + objc) != TCL_OK) {
149 return TCL_ERROR;
150 }
151 count = oldSize;
152 for (i = 0; i < objc; i++) {
153 if (GetDouble(vPtr->interp, objv[i], &value) != TCL_OK) {
154 Blt_VectorChangeLength(vPtr, count);
155 return TCL_ERROR;
156 }
157 vPtr->valueArr[count++] = value;
158 }
159 vPtr->notifyFlags |= UPDATE_RANGE;
160 return TCL_OK;
161}
162
163/* Vector instance option commands */
164
165/*
166 * -----------------------------------------------------------------------
167 *
168 * AppendOp --
169 *
170 * Appends one of more Tcl lists of values, or vector objects
171 * onto the end of the current vector object.
172 *
173 * Results:
174 * A standard Tcl result. If a current vector can't be created,
175 * resized, any of the named vectors can't be found, or one of
176 * lists of values is invalid, TCL_ERROR is returned.
177 *
178 * Side Effects:
179 * Clients of current vector will be notified of the change.
180 *
181 * -----------------------------------------------------------------------
182 */
183static int
184AppendOp(vPtr, interp, objc, objv)
185 VectorObject *vPtr;
186 Tcl_Interp *interp;
187 int objc;
188 Tcl_Obj *CONST *objv;
189{
190 register int i;
191 int result;
192 VectorObject *v2Ptr;
193
194 for (i = 2; i < objc; i++) {
195 v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr,
196 Tcl_GetString(objv[i]), (char **)NULL, NS_SEARCH_BOTH);
197 if (v2Ptr != NULL) {
198 result = AppendVector(vPtr, v2Ptr);
199 } else {
200 int nElem;
201 Tcl_Obj **elemObjArr;
202
203 if (Tcl_ListObjGetElements(interp, objv[i], &nElem, &elemObjArr)
204 != TCL_OK) {
205 return TCL_ERROR;
206 }
207 result = AppendList(vPtr, nElem, elemObjArr);
208 }
209 if (result != TCL_OK) {
210 return TCL_ERROR;
211 }
212 }
213 if (objc > 2) {
214 if (vPtr->flush) {
215 Blt_VectorFlushCache(vPtr);
216 }
217 Blt_VectorUpdateClients(vPtr);
218 }
219 return TCL_OK;
220}
221
222/*
223 * -----------------------------------------------------------------------
224 *
225 * ClearOp --
226 *
227 * Deletes all the accumulated array indices for the Tcl array
228 * associated will the vector. This routine can be used to
229 * free excess memory from a large vector.
230 *
231 * Results:
232 * Always returns TCL_OK.
233 *
234 * Side Effects:
235 * Memory used for the entries of the Tcl array variable is freed.
236 *
237 * -----------------------------------------------------------------------
238 */
239/*ARGSUSED*/
240static int
241ClearOp(vPtr, interp, objc, objv)
242 VectorObject *vPtr;
243 Tcl_Interp *interp; /* Not used. */
244 int objc; /* Not used. */
245 Tcl_Obj *CONST *objv; /* Not used. */
246{
247 Blt_VectorFlushCache(vPtr);
248 return TCL_OK;
249}
250
251/*
252 * -----------------------------------------------------------------------
253 *
254 * DeleteOp --
255 *
256 * Deletes the given indices from the vector. If no indices are
257 * provided the entire vector is deleted.
258 *
259 * Results:
260 * A standard Tcl result. If any of the given indices is invalid,
261 * interp->result will an error message and TCL_ERROR is returned.
262 *
263 * Side Effects:
264 * The clients of the vector will be notified of the vector
265 * deletions.
266 *
267 * -----------------------------------------------------------------------
268 */
269/*ARGSUSED*/
270static int
271DeleteOp(vPtr, interp, objc, objv)
272 VectorObject *vPtr;
273 Tcl_Interp *interp;
274 int objc;
275 Tcl_Obj *CONST *objv;
276{
277 unsigned char *unsetArr;
278 register int i, j;
279 register int count;
280 char *string;
281
282 /* FIXME: Don't delete vector with no indices. */
283 if (objc == 2) {
284 Blt_VectorFree(vPtr);
285 return TCL_OK;
286 }
287 /*
288 * Allocate an "unset" bitmap the size of the vector.
289 */
290 unsetArr = Blt_Calloc(sizeof(unsigned char), (vPtr->length + 7) / 8);
291 assert(unsetArr);
292
293#define SetBit(i) \
294 unsetArr[(i) >> 3] |= (1 << ((i) & 0x07))
295#define GetBit(i) \
296 (unsetArr[(i) >> 3] & (1 << ((i) & 0x07)))
297
298 for (i = 2; i < objc; i++) {
299 string = Tcl_GetString(objv[i]);
300 if (Blt_VectorGetIndexRange(interp, vPtr, string,
301 (INDEX_COLON | INDEX_CHECK), (Blt_VectorIndexProc **) NULL)
302 != TCL_OK) {
303 Blt_Free(unsetArr);
304 return TCL_ERROR;
305 }
306 for (j = vPtr->first; j <= vPtr->last; j++) {
307 SetBit(j); /* Mark the range of elements for deletion. */
308 }
309 }
310 count = 0;
311 for (i = 0; i < vPtr->length; i++) {
312 if (GetBit(i)) {
313 continue; /* Skip elements marked for deletion. */
314 }
315 if (count < i) {
316 vPtr->valueArr[count] = vPtr->valueArr[i];
317 }
318 count++;
319 }
320 Blt_Free(unsetArr);
321 vPtr->length = count;
322 if (vPtr->flush) {
323 Blt_VectorFlushCache(vPtr);
324 }
325 Blt_VectorUpdateClients(vPtr);
326 return TCL_OK;
327}
328
329/*
330 * -----------------------------------------------------------------------
331 *
332 * DupOp --
333 *
334 * Creates one or more duplicates of the vector object.
335 *
336 * Results:
337 * A standard Tcl result. If a new vector can't be created,
338 * or and existing vector resized, TCL_ERROR is returned.
339 *
340 * Side Effects:
341 * Clients of existing vectors will be notified of the change.
342 *
343 * -----------------------------------------------------------------------
344 */
345/*ARGSUSED*/
346static int
347DupOp(vPtr, interp, objc, objv)
348 VectorObject *vPtr;
349 Tcl_Interp *interp; /* Not used. */
350 int objc;
351 Tcl_Obj *CONST *objv;
352{
353 VectorObject *v2Ptr;
354 int isNew;
355 register int i;
356 char *string;
357
358 for (i = 2; i < objc; i++) {
359 string = Tcl_GetString(objv[i]);
360 v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string,&isNew);
361 if (v2Ptr == NULL) {
362 return TCL_ERROR;
363 }
364 if (v2Ptr == vPtr) {
365 continue;
366 }
367 if (Blt_VectorDuplicate(v2Ptr, vPtr) != TCL_OK) {
368 return TCL_ERROR;
369 }
370 if (!isNew) {
371 if (v2Ptr->flush) {
372 Blt_VectorFlushCache(v2Ptr);
373 }
374 Blt_VectorUpdateClients(v2Ptr);
375 }
376 }
377 return TCL_OK;
378}
379
380/*
381 * -----------------------------------------------------------------------
382 *
383 * IndexOp --
384 *
385 * Sets or reads the value of the index. This simulates what the
386 * vector's variable does.
387 *
388 * Results:
389 * A standard Tcl result. If the index is invalid,
390 * interp->result will an error message and TCL_ERROR is returned.
391 * Otherwise interp->result will contain the values.
392 *
393 * -----------------------------------------------------------------------
394 */
395static int
396IndexOp(vPtr, interp, objc, objv)
397 VectorObject *vPtr;
398 Tcl_Interp *interp;
399 int objc;
400 Tcl_Obj *CONST *objv;
401{
402 int first, last;
403 char *string;
404
405 string = Tcl_GetString(objv[2]);
406 if (Blt_VectorGetIndexRange(interp, vPtr, string, INDEX_ALL_FLAGS,
407 (Blt_VectorIndexProc **) NULL) != TCL_OK) {
408 return TCL_ERROR;
409 }
410 first = vPtr->first, last = vPtr->last;
411 if (objc == 3) {
412 Tcl_Obj *listObjPtr;
413
414 if (first == vPtr->length) {
415 Tcl_AppendResult(interp, "can't get index \"", string, "\"",
416 (char *)NULL);
417 return TCL_ERROR; /* Can't read from index "++end" */
418 }
419 listObjPtr = GetValues(vPtr, first, last);
420 Tcl_SetObjResult(interp, listObjPtr);
421 } else {
422 double value;
423
424 /* FIXME: huh? Why set values here?. */
425 if (first == SPECIAL_INDEX) {
426 Tcl_AppendResult(interp, "can't set index \"", string, "\"",
427 (char *)NULL);
428 return TCL_ERROR; /* Tried to set "min" or "max" */
429 }
430 if (GetDouble(vPtr->interp, objv[3], &value) != TCL_OK) {
431 return TCL_ERROR;
432 }
433 if (first == vPtr->length) {
434 if (Blt_VectorChangeLength(vPtr, vPtr->length + 1) != TCL_OK) {
435 return TCL_ERROR;
436 }
437 }
438 ReplicateValue(vPtr, first, last, value);
439 Tcl_SetObjResult(interp, objv[3]);
440 if (vPtr->flush) {
441 Blt_VectorFlushCache(vPtr);
442 }
443 Blt_VectorUpdateClients(vPtr);
444 }
445 return TCL_OK;
446}
447
448/*
449 * -----------------------------------------------------------------------
450 *
451 * LengthOp --
452 *
453 * Returns the length of the vector. If a new size is given, the
454 * vector is resized to the new vector.
455 *
456 * Results:
457 * A standard Tcl result. If the new length is invalid,
458 * interp->result will an error message and TCL_ERROR is returned.
459 * Otherwise interp->result will contain the length of the vector.
460 *
461 * -----------------------------------------------------------------------
462 */
463static int
464LengthOp(vPtr, interp, objc, objv)
465 VectorObject *vPtr;
466 Tcl_Interp *interp;
467 int objc;
468 Tcl_Obj *CONST *objv;
469{
470 if (objc == 3) {
471 int size;
472
473 if (Tcl_GetIntFromObj(interp, objv[2], &size) != TCL_OK) {
474 return TCL_ERROR;
475 }
476 if (size < 0) {
477 Tcl_AppendResult(interp, "bad vector size \"",
478 Tcl_GetString(objv[2]), "\"", (char *)NULL);
479 return TCL_ERROR;
480 }
481 if (Blt_VectorChangeLength(vPtr, size) != TCL_OK) {
482 return TCL_ERROR;
483 }
484 if (vPtr->flush) {
485 Blt_VectorFlushCache(vPtr);
486 }
487 Blt_VectorUpdateClients(vPtr);
488 }
489 Tcl_SetObjResult(interp, Tcl_NewIntObj(vPtr->length));
490 return TCL_OK;
491}
492
493/*
494 * -----------------------------------------------------------------------
495 *
496 * MapOp --
497 *
498 * Queries or sets the offset of the array index from the base
499 * address of the data array of values.
500 *
501 * Results:
502 * A standard Tcl result. If the source vector doesn't exist
503 * or the source list is not a valid list of numbers, TCL_ERROR
504 * returned. Otherwise TCL_OK is returned.
505 *
506 * -----------------------------------------------------------------------
507 */
508/*ARGSUSED*/
509static int
510MapOp(vPtr, interp, objc, objv)
511 VectorObject *vPtr;
512 Tcl_Interp *interp;
513 int objc; /* Not used. */
514 Tcl_Obj *CONST *objv;
515{
516 if (objc > 2) {
517 if (Blt_VectorMapVariable(interp, vPtr, Tcl_GetString(objv[2]))
518 != TCL_OK) {
519 return TCL_ERROR;
520 }
521 }
522 if (vPtr->arrayName != NULL) {
523 Tcl_SetResult(interp, vPtr->arrayName, TCL_VOLATILE);
524 }
525 return TCL_OK;
526}
527
528/*
529 * -----------------------------------------------------------------------
530 *
531 * MergeOp --
532 *
533 * Merges the values from the given vectors to the current vector.
534 *
535 * Results:
536 * A standard Tcl result. If any of the given vectors differ in size,
537 * TCL_ERROR is returned. Otherwise TCL_OK is returned and the
538 * vector data will contain merged values of the given vectors.
539 *
540 * -----------------------------------------------------------------------
541 */
542/*ARGSUSED*/
543static int
544MergeOp(vPtr, interp, objc, objv)
545 VectorObject *vPtr;
546 Tcl_Interp *interp;
547 int objc;
548 Tcl_Obj *CONST *objv;
549{
550 VectorObject *v2Ptr;
551 VectorObject **vecArr;
552 register VectorObject **vPtrPtr;
553 int refSize, length, nElem;
554 register int i;
555 double *valuePtr, *valueArr;
556
557 /* Allocate an array of vector pointers of each vector to be
558 * merged in the current vector. */
559 vecArr = Blt_Malloc(sizeof(VectorObject *) * objc);
560 assert(vecArr);
561 vPtrPtr = vecArr;
562
563 refSize = -1;
564 nElem = 0;
565 for (i = 2; i < objc; i++) {
566 if (Blt_VectorLookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), &v2Ptr)
567 != TCL_OK) {
568 Blt_Free(vecArr);
569 return TCL_ERROR;
570 }
571 /* Check that all the vectors are the same length */
572 length = v2Ptr->last - v2Ptr->first + 1;
573 if (refSize < 0) {
574 refSize = length;
575 } else if (length != refSize) {
576 Tcl_AppendResult(vPtr->interp, "vectors \"", vPtr->name,
577 "\" and \"", v2Ptr->name, "\" differ in length",
578 (char *)NULL);
579 Blt_Free(vecArr);
580 return TCL_ERROR;
581 }
582 *vPtrPtr++ = v2Ptr;
583 nElem += refSize;
584 }
585 *vPtrPtr = NULL;
586
587 valueArr = Blt_Malloc(sizeof(double) * nElem);
588 if (valueArr == NULL) {
589 Tcl_AppendResult(vPtr->interp, "not enough memory to allocate ",
590 Blt_Itoa(nElem), " vector elements", (char *)NULL);
591 return TCL_ERROR;
592 }
593 /* Merge the values from each of the vectors into the current vector */
594 valuePtr = valueArr;
595 for (i = 0; i < refSize; i++) {
596 for (vPtrPtr = vecArr; *vPtrPtr != NULL; vPtrPtr++) {
597 *valuePtr++ = (*vPtrPtr)->valueArr[i + (*vPtrPtr)->first];
598 }
599 }
600 Blt_Free(vecArr);
601 Blt_VectorReset(vPtr, valueArr, nElem, nElem, TCL_DYNAMIC);
602 return TCL_OK;
603}
604
605/*
606 * -----------------------------------------------------------------------
607 *
608 * NormalizeOp --
609 *
610 * Normalizes the vector.
611 *
612 * Results:
613 * A standard Tcl result. If the density is invalid, TCL_ERROR
614 * is returned. Otherwise TCL_OK is returned.
615 *
616 * -----------------------------------------------------------------------
617 */
618/*ARGSUSED*/
619static int
620NormalizeOp(vPtr, interp, objc, objv)
621 VectorObject *vPtr;
622 Tcl_Interp *interp;
623 int objc;
624 Tcl_Obj *CONST *objv;
625{
626 register int i;
627 double range;
628
629 Blt_VectorUpdateRange(vPtr);
630 range = vPtr->max - vPtr->min;
631 if (objc > 2) {
632 VectorObject *v2Ptr;
633 int isNew;
634 char *string;
635
636 string = Tcl_GetString(objv[2]);
637 v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string,
638 &isNew);
639 if (v2Ptr == NULL) {
640 return TCL_ERROR;
641 }
642 if (Blt_VectorChangeLength(v2Ptr, vPtr->length) != TCL_OK) {
643 return TCL_ERROR;
644 }
645 for (i = 0; i < vPtr->length; i++) {
646 v2Ptr->valueArr[i] = (vPtr->valueArr[i] - vPtr->min) / range;
647 }
648 Blt_VectorUpdateRange(v2Ptr);
649 if (!isNew) {
650 if (v2Ptr->flush) {
651 Blt_VectorFlushCache(v2Ptr);
652 }
653 Blt_VectorUpdateClients(v2Ptr);
654 }
655 } else {
656 double norm;
657 Tcl_Obj *listObjPtr;
658
659 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
660 for (i = 0; i < vPtr->length; i++) {
661 norm = (vPtr->valueArr[i] - vPtr->min) / range;
662 Tcl_ListObjAppendElement(interp, listObjPtr,
663 Tcl_NewDoubleObj(norm));
664 }
665 Tcl_SetObjResult(interp, listObjPtr);
666 }
667 return TCL_OK;
668}
669
670/*
671 * -----------------------------------------------------------------------
672 *
673 * NotifyOp --
674 *
675 * Notify clients of vector.
676 *
677 * Results:
678 * A standard Tcl result. If any of the given vectors differ in size,
679 * TCL_ERROR is returned. Otherwise TCL_OK is returned and the
680 * vector data will contain merged values of the given vectors.
681 *
682 * x vector notify now
683 * x vector notify always
684 * x vector notify whenidle
685 * x vector notify update {}
686 * x vector notify delete {}
687 *
688 * -----------------------------------------------------------------------
689 */
690/*ARGSUSED*/
691static int
692NotifyOp(vPtr, interp, objc, objv)
693 VectorObject *vPtr;
694 Tcl_Interp *interp;
695 int objc;
696 Tcl_Obj *CONST *objv;
697{
698 int option;
699 int bool;
700 enum optionIndices {
701 OPTION_ALWAYS, OPTION_NEVER, OPTION_WHENIDLE,
702 OPTION_NOW, OPTION_CANCEL, OPTION_PENDING
703 };
704 static char *optionArr[] = {
705 "always", "never", "whenidle", "now", "cancel", "pending", NULL
706 };
707
708 if (Tcl_GetIndexFromObj(interp, objv[2], optionArr, "qualifier", TCL_EXACT,
709 &option) != TCL_OK) {
710 return TCL_OK;
711 }
712 switch (option) {
713 case OPTION_ALWAYS:
714 vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK;
715 vPtr->notifyFlags |= NOTIFY_ALWAYS;
716 break;
717 case OPTION_NEVER:
718 vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK;
719 vPtr->notifyFlags |= NOTIFY_NEVER;
720 break;
721 case OPTION_WHENIDLE:
722 vPtr->notifyFlags &= ~NOTIFY_WHEN_MASK;
723 vPtr->notifyFlags |= NOTIFY_WHENIDLE;
724 break;
725 case OPTION_NOW:
726 /* FIXME: How does this play when an update is pending? */
727 Blt_VectorNotifyClients(vPtr);
728 break;
729 case OPTION_CANCEL:
730 if (vPtr->notifyFlags & NOTIFY_PENDING) {
731 vPtr->notifyFlags &= ~NOTIFY_PENDING;
732 Tcl_CancelIdleCall(Blt_VectorNotifyClients, (ClientData)vPtr);
733 }
734 break;
735 case OPTION_PENDING:
736 bool = (vPtr->notifyFlags & NOTIFY_PENDING);
737 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(bool));
738 break;
739 }
740 return TCL_OK;
741}
742
743/*
744 * -----------------------------------------------------------------------
745 *
746 * PopulateOp --
747 *
748 * Creates or resizes a new vector based upon the density specified.
749 *
750 * Results:
751 * A standard Tcl result. If the density is invalid, TCL_ERROR
752 * is returned. Otherwise TCL_OK is returned.
753 *
754 * -----------------------------------------------------------------------
755 */
756/*ARGSUSED*/
757static int
758PopulateOp(vPtr, interp, objc, objv)
759 VectorObject *vPtr;
760 Tcl_Interp *interp;
761 int objc;
762 Tcl_Obj *CONST *objv;
763{
764 VectorObject *v2Ptr;
765 int size, density;
766 int isNew;
767 register int i, j;
768 double slice, range;
769 register double *valuePtr;
770 int count;
771 char *string;
772
773 string = Tcl_GetString(objv[2]);
774 v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string, &isNew);
775 if (v2Ptr == NULL) {
776 return TCL_ERROR;
777 }
778 if (vPtr->length == 0) {
779 return TCL_OK; /* Source vector is empty. */
780 }
781 if (Tcl_GetIntFromObj(interp, objv[3], &density) != TCL_OK) {
782 return TCL_ERROR;
783 }
784 if (density < 1) {
785 Tcl_AppendResult(interp, "bad density \"", Tcl_GetString(objv[3]),
786 "\"", (char *)NULL);
787 return TCL_ERROR;
788 }
789 size = (vPtr->length - 1) * (density + 1) + 1;
790 if (Blt_VectorChangeLength(v2Ptr, size) != TCL_OK) {
791 return TCL_ERROR;
792 }
793 count = 0;
794 valuePtr = v2Ptr->valueArr;
795 for (i = 0; i < (vPtr->length - 1); i++) {
796 range = vPtr->valueArr[i + 1] - vPtr->valueArr[i];
797 slice = range / (double)(density + 1);
798 for (j = 0; j <= density; j++) {
799 *valuePtr = vPtr->valueArr[i] + (slice * (double)j);
800 valuePtr++;
801 count++;
802 }
803 }
804 count++;
805 *valuePtr = vPtr->valueArr[i];
806 assert(count == v2Ptr->length);
807 if (!isNew) {
808 if (v2Ptr->flush) {
809 Blt_VectorFlushCache(v2Ptr);
810 }
811 Blt_VectorUpdateClients(v2Ptr);
812 }
813 return TCL_OK;
814}
815
816/*
817 * -----------------------------------------------------------------------
818 *
819 * RangeOp --
820 *
821 * Returns a Tcl list of the range of vector values specified.
822 *
823 * Results:
824 * A standard Tcl result. If the given range is invalid, TCL_ERROR
825 * is returned. Otherwise TCL_OK is returned and interp->result
826 * will contain the list of values.
827 *
828 * -----------------------------------------------------------------------
829 */
830/*ARGSUSED*/
831static int
832RangeOp(vPtr, interp, objc, objv)
833 VectorObject *vPtr;
834 Tcl_Interp *interp;
835 int objc; /* Not used. */
836 Tcl_Obj *CONST *objv;
837{
838 Tcl_Obj *listObjPtr;
839 int first, last;
840 register int i;
841
842 if ((Blt_VectorGetIndex(interp, vPtr, Tcl_GetString(objv[2]), &first,
843 INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK) ||
844 (Blt_VectorGetIndex(interp, vPtr, Tcl_GetString(objv[3]), &last,
845 INDEX_CHECK, (Blt_VectorIndexProc **) NULL) != TCL_OK)) {
846 return TCL_ERROR;
847 }
848 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
849 if (first > last) {
850 /* Return the list reversed */
851 for (i = last; i <= first; i++) {
852 Tcl_ListObjAppendElement(interp, listObjPtr,
853 Tcl_NewDoubleObj(vPtr->valueArr[i]));
854 }
855 } else {
856 for (i = first; i <= last; i++) {
857 Tcl_ListObjAppendElement(interp, listObjPtr,
858 Tcl_NewDoubleObj(vPtr->valueArr[i]));
859 }
860 }
861 Tcl_SetObjResult(interp, listObjPtr);
862 return TCL_OK;
863}
864
865/*
866 * ----------------------------------------------------------------------
867 *
868 * InRange --
869 *
870 * Determines if a value lies within a given range.
871 *
872 * The value is normalized and compared against the interval
873 * [0..1], where 0.0 is the minimum and 1.0 is the maximum.
874 * DBL_EPSILON is the smallest number that can be represented
875 * on the host machine, such that (1.0 + epsilon) != 1.0.
876 *
877 * Please note, min cannot be greater than max.
878 *
879 * Results:
880 * If the value is within of the interval [min..max], 1 is
881 * returned; 0 otherwise.
882 *
883 * ----------------------------------------------------------------------
884 */
885INLINE static int
886InRange(value, min, max)
887 double value, min, max;
888{
889 double range;
890
891 range = max - min;
892 if (range < DBL_EPSILON) {
893 return (FABS(max - value) < DBL_EPSILON);
894 } else {
895 double norm;
896
897 norm = (value - min) / range;
898 return ((norm >= -DBL_EPSILON) && ((norm - 1.0) < DBL_EPSILON));
899 }
900}
901
902enum NativeFormats {
903 FMT_UNKNOWN = -1,
904 FMT_UCHAR, FMT_CHAR,
905 FMT_USHORT, FMT_SHORT,
906 FMT_UINT, FMT_INT,
907 FMT_ULONG, FMT_LONG,
908 FMT_FLOAT, FMT_DOUBLE
909};
910
911/*
912 * -----------------------------------------------------------------------
913 *
914 * GetBinaryFormat
915 *
916 * Translates a format string into a native type. Formats may be
917 * as follows.
918 *
919 * signed i1, i2, i4, i8
920 * unsigned u1, u2, u4, u8
921 * real r4, r8, r16
922 *
923 * But there must be a corresponding native type. For example,
924 * this for reading 2-byte binary integers from an instrument and
925 * converting them to unsigned shorts or ints.
926 *
927 * -----------------------------------------------------------------------
928 */
929static enum NativeFormats
930GetBinaryFormat(interp, string, sizePtr)
931 Tcl_Interp *interp;
932 char *string;
933 int *sizePtr;
934{
935 char c;
936
937 c = tolower(string[0]);
938 if (Tcl_GetInt(interp, string + 1, sizePtr) != TCL_OK) {
939 Tcl_AppendResult(interp, "unknown binary format \"", string,
940 "\": incorrect byte size", (char *)NULL);
941 return FMT_UNKNOWN;
942 }
943 switch (c) {
944 case 'r':
945 if (*sizePtr == sizeof(double)) {
946 return FMT_DOUBLE;
947 } else if (*sizePtr == sizeof(float)) {
948 return FMT_FLOAT;
949 }
950 break;
951
952 case 'i':
953 if (*sizePtr == sizeof(char)) {
954 return FMT_CHAR;
955 } else if (*sizePtr == sizeof(int)) {
956 return FMT_INT;
957 } else if (*sizePtr == sizeof(long)) {
958 return FMT_LONG;
959 } else if (*sizePtr == sizeof(short)) {
960 return FMT_SHORT;
961 }
962 break;
963
964 case 'u':
965 if (*sizePtr == sizeof(unsigned char)) {
966 return FMT_UCHAR;
967 } else if (*sizePtr == sizeof(unsigned int)) {
968 return FMT_UINT;
969 } else if (*sizePtr == sizeof(unsigned long)) {
970 return FMT_ULONG;
971 } else if (*sizePtr == sizeof(unsigned short)) {
972 return FMT_USHORT;
973 }
974 break;
975
976 default:
977 Tcl_AppendResult(interp, "unknown binary format \"", string,
978 "\": should be either i#, r#, u# (where # is size in bytes)",
979 (char *)NULL);
980 return FMT_UNKNOWN;
981 }
982 Tcl_AppendResult(interp, "can't handle format \"", string, "\"",
983 (char *)NULL);
984 return FMT_UNKNOWN;
985}
986
987static int
988CopyValues(vPtr, byteArr, fmt, size, length, swap, indexPtr)
989 VectorObject *vPtr;
990 char *byteArr;
991 enum NativeFormats fmt;
992 int size;
993 int length;
994 int swap;
995 int *indexPtr;
996{
997 register int i, n;
998 int newSize;
999
1000 if ((swap) && (size > 1)) {
1001 int nBytes = size * length;
1002 register unsigned char *p;
1003 register int left, right;
1004
1005 for (i = 0; i < nBytes; i += size) {
1006 p = (unsigned char *)(byteArr + i);
1007 for (left = 0, right = size - 1; left < right; left++, right--) {
1008 p[left] ^= p[right];
1009 p[right] ^= p[left];
1010 p[left] ^= p[right];
1011 }
1012
1013 }
1014 }
1015 newSize = *indexPtr + length;
1016 if (newSize > vPtr->length) {
1017 if (Blt_VectorChangeLength(vPtr, newSize) != TCL_OK) {
1018 return TCL_ERROR;
1019 }
1020 }
1021#define CopyArrayToVector(vPtr, arr) \
1022 for (i = 0, n = *indexPtr; i < length; i++, n++) { \
1023 (vPtr)->valueArr[n] = (double)(arr)[i]; \
1024 }
1025
1026 switch (fmt) {
1027 case FMT_CHAR:
1028 CopyArrayToVector(vPtr, (char *)byteArr);
1029 break;
1030
1031 case FMT_UCHAR:
1032 CopyArrayToVector(vPtr, (unsigned char *)byteArr);
1033 break;
1034
1035 case FMT_INT:
1036 CopyArrayToVector(vPtr, (int *)byteArr);
1037 break;
1038
1039 case FMT_UINT:
1040 CopyArrayToVector(vPtr, (unsigned int *)byteArr);
1041 break;
1042
1043 case FMT_LONG:
1044 CopyArrayToVector(vPtr, (long *)byteArr);
1045 break;
1046
1047 case FMT_ULONG:
1048 CopyArrayToVector(vPtr, (unsigned long *)byteArr);
1049 break;
1050
1051 case FMT_SHORT:
1052 CopyArrayToVector(vPtr, (short int *)byteArr);
1053 break;
1054
1055 case FMT_USHORT:
1056 CopyArrayToVector(vPtr, (unsigned short int *)byteArr);
1057 break;
1058
1059 case FMT_FLOAT:
1060 CopyArrayToVector(vPtr, (float *)byteArr);
1061 break;
1062
1063 case FMT_DOUBLE:
1064 CopyArrayToVector(vPtr, (double *)byteArr);
1065 break;
1066
1067 case FMT_UNKNOWN:
1068 break;
1069 }
1070 *indexPtr += length;
1071 return TCL_OK;
1072}
1073
1074/*
1075 * -----------------------------------------------------------------------
1076 *
1077 * BinreadOp --
1078 *
1079 * Reads binary values from a Tcl channel. Values are either appended
1080 * to the end of the vector or placed at a given index (using the
1081 * "-at" option), overwriting existing values. Data is read until EOF
1082 * is found on the channel or a specified number of values are read.
1083 * (note that this is not necessarily the same as the number of bytes).
1084 *
1085 * The following flags are supported:
1086 * -swap Swap bytes
1087 * -at index Start writing data at the index.
1088 * -format fmt Specifies the format of the data.
1089 *
1090 * This binary reader was created by Harald Kirsch (kir@iitb.fhg.de).
1091 * Anything that's wrong is due to my munging of his code.
1092 *
1093 * Results:
1094 * Returns a standard Tcl result. The interpreter result will contain
1095 * the number of values (not the number of bytes) read.
1096 *
1097 * Caveats:
1098 * Channel reads must end on an element boundary.
1099 *
1100 * -----------------------------------------------------------------------
1101 */
1102/*ARGSUSED*/
1103static int
1104BinreadOp(vPtr, interp, objc, objv)
1105 VectorObject *vPtr;
1106 Tcl_Interp *interp;
1107 int objc;
1108 Tcl_Obj *CONST *objv;
1109{
1110 Tcl_Channel channel;
1111 char *byteArr;
1112 char *string;
1113 enum NativeFormats fmt;
1114 int arraySize, bytesRead;
1115 int count, total;
1116 int first;
1117 int size, length, mode;
1118 int swap;
1119 register int i;
1120
1121 string = Tcl_GetString(objv[2]);
1122 channel = Tcl_GetChannel(interp, string, &mode);
1123 if (channel == NULL) {
1124 return TCL_ERROR;
1125 }
1126 if ((mode & TCL_READABLE) == 0) {
1127 Tcl_AppendResult(interp, "channel \"", string,
1128 "\" wasn't opened for reading", (char *)NULL);
1129 return TCL_ERROR;
1130 }
1131 first = vPtr->length;
1132 fmt = FMT_DOUBLE;
1133 size = sizeof(double);
1134 swap = FALSE;
1135 count = 0;
1136
1137 if (objc > 3) {
1138 string = Tcl_GetString(objv[3]);
1139 if (string[0] != '-') {
1140 long int value;
1141 /* Get the number of values to read. */
1142 if (Tcl_GetLongFromObj(interp, objv[3], &value) != TCL_OK) {
1143 return TCL_ERROR;
1144 }
1145 if (value < 0) {
1146 Tcl_AppendResult(interp, "count can't be negative",
1147 (char *)NULL);
1148 return TCL_ERROR;
1149 }
1150 count = (int)value;
1151 objc--, objv++;
1152 }
1153 }
1154 /* Process any option-value pairs that remain. */
1155 for (i = 3; i < objc; i++) {
1156 string = Tcl_GetString(objv[i]);
1157 if (strcmp(string, "-swap") == 0) {
1158 swap = TRUE;
1159 } else if (strcmp(string, "-format") == 0) {
1160 i++;
1161 if (i >= objc) {
1162 Tcl_AppendResult(interp, "missing arg after \"", string,
1163 "\"", (char *)NULL);
1164 return TCL_ERROR;
1165 }
1166 string = Tcl_GetString(objv[i]);
1167 fmt = GetBinaryFormat(interp, string, &size);
1168 if (fmt == FMT_UNKNOWN) {
1169 return TCL_ERROR;
1170 }
1171 } else if (strcmp(string, "-at") == 0) {
1172 i++;
1173 if (i >= objc) {
1174 Tcl_AppendResult(interp, "missing arg after \"", string,
1175 "\"", (char *)NULL);
1176 return TCL_ERROR;
1177 }
1178 string = Tcl_GetString(objv[i]);
1179 if (Blt_VectorGetIndex(interp, vPtr, string, &first, 0,
1180 (Blt_VectorIndexProc **)NULL) != TCL_OK) {
1181 return TCL_ERROR;
1182 }
1183 if (first > vPtr->length) {
1184 Tcl_AppendResult(interp, "index \"", string,
1185 "\" is out of range", (char *)NULL);
1186 return TCL_ERROR;
1187 }
1188 }
1189 }
1190
1191#define BUFFER_SIZE 1024
1192 if (count == 0) {
1193 arraySize = BUFFER_SIZE * size;
1194 } else {
1195 arraySize = count * size;
1196 }
1197
1198 byteArr = Blt_Malloc(arraySize);
1199 assert(byteArr);
1200
1201 /* FIXME: restore old channel translation later? */
1202 if (Tcl_SetChannelOption(interp, channel, "-translation",
1203 "binary") != TCL_OK) {
1204 return TCL_ERROR;
1205 }
1206 total = 0;
1207 while (!Tcl_Eof(channel)) {
1208 bytesRead = Tcl_Read(channel, byteArr, arraySize);
1209 if (bytesRead < 0) {
1210 Tcl_AppendResult(interp, "error reading channel: ",
1211 Tcl_PosixError(interp), (char *)NULL);
1212 return TCL_ERROR;
1213 }
1214 if ((bytesRead % size) != 0) {
1215 Tcl_AppendResult(interp, "error reading channel: short read",
1216 (char *)NULL);
1217 return TCL_ERROR;
1218 }
1219 length = bytesRead / size;
1220 if (CopyValues(vPtr, byteArr, fmt, size, length, swap, &first)
1221 != TCL_OK) {
1222 return TCL_ERROR;
1223 }
1224 total += length;
1225 if (count > 0) {
1226 break;
1227 }
1228 }
1229 Blt_Free(byteArr);
1230
1231 if (vPtr->flush) {
1232 Blt_VectorFlushCache(vPtr);
1233 }
1234 Blt_VectorUpdateClients(vPtr);
1235
1236 /* Set the result as the number of values read. */
1237 Tcl_SetObjResult(interp, Tcl_NewIntObj(total));
1238 return TCL_OK;
1239}
1240
1241/*
1242 * -----------------------------------------------------------------------
1243 *
1244 * SearchOp --
1245 *
1246 * Searchs for a value in the vector. Returns the indices of all
1247 * vector elements matching a particular value.
1248 *
1249 * Results:
1250 * Always returns TCL_OK. interp->result will contain a list of
1251 * the indices of array elements matching value. If no elements
1252 * match, interp->result will contain the empty string.
1253 *
1254 * -----------------------------------------------------------------------
1255 */
1256/*ARGSUSED*/
1257static int
1258SearchOp(vPtr, interp, objc, objv)
1259 VectorObject *vPtr;
1260 Tcl_Interp *interp;
1261 int objc;
1262 Tcl_Obj *CONST *objv;
1263{
1264 double min, max;
1265 register int i;
1266 int wantValue;
1267 char *string;
1268 Tcl_Obj *listObjPtr;
1269
1270 wantValue = FALSE;
1271 string = Tcl_GetString(objv[2]);
1272 if ((string[0] == '-') && (strcmp(string, "-value") == 0)) {
1273 wantValue = TRUE;
1274 objv++, objc--;
1275 }
1276 if (GetDouble(interp, objv[2], &min) != TCL_OK) {
1277 return TCL_ERROR;
1278 }
1279 max = min;
1280 if ((objc > 3) && (GetDouble(interp, objv[3], &max) != TCL_OK)) {
1281 return TCL_ERROR;
1282 }
1283 if ((min - max) >= DBL_EPSILON) {
1284 return TCL_OK; /* Bogus range. Don't bother looking. */
1285 }
1286 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1287 if (wantValue) {
1288 for (i = 0; i < vPtr->length; i++) {
1289 if (InRange(vPtr->valueArr[i], min, max)) {
1290 Tcl_ListObjAppendElement(interp, listObjPtr,
1291 Tcl_NewDoubleObj(vPtr->valueArr[i]));
1292 }
1293 }
1294 } else {
1295 for (i = 0; i < vPtr->length; i++) {
1296 if (InRange(vPtr->valueArr[i], min, max)) {
1297 Tcl_ListObjAppendElement(interp, listObjPtr,
1298 Tcl_NewIntObj(i + vPtr->offset));
1299 }
1300 }
1301 }
1302 Tcl_SetObjResult(interp, listObjPtr);
1303 return TCL_OK;
1304}
1305
1306/*
1307 * -----------------------------------------------------------------------
1308 *
1309 * OffsetOp --
1310 *
1311 * Queries or sets the offset of the array index from the base
1312 * address of the data array of values.
1313 *
1314 * Results:
1315 * A standard Tcl result. If the source vector doesn't exist
1316 * or the source list is not a valid list of numbers, TCL_ERROR
1317 * returned. Otherwise TCL_OK is returned.
1318 *
1319 * -----------------------------------------------------------------------
1320 */
1321/*ARGSUSED*/
1322static int
1323OffsetOp(vPtr, interp, objc, objv)
1324 VectorObject *vPtr;
1325 Tcl_Interp *interp;
1326 int objc;
1327 Tcl_Obj *CONST *objv;
1328{
1329 if (objc == 3) {
1330 int newOffset;
1331
1332 if (Tcl_GetIntFromObj(interp, objv[2], &newOffset) != TCL_OK) {
1333 return TCL_ERROR;
1334 }
1335 vPtr->offset = newOffset;
1336 }
1337 Tcl_SetObjResult(interp, Tcl_NewIntObj(vPtr->offset));
1338 return TCL_OK;
1339}
1340
1341/*
1342 * -----------------------------------------------------------------------
1343 *
1344 * RandomOp --
1345 *
1346 * Generates random values for the length of the vector.
1347 *
1348 * Results:
1349 * A standard Tcl result.
1350 *
1351 * -----------------------------------------------------------------------
1352 */
1353/*ARGSUSED*/
1354static int
1355RandomOp(vPtr, interp, objc, objv)
1356 VectorObject *vPtr;
1357 Tcl_Interp *interp;
1358 int objc; /* Not used. */
1359 Tcl_Obj *CONST *objv; /* Not used. */
1360{
1361#ifdef HAVE_DRAND48
1362 register int i;
1363
1364 for (i = 0; i < vPtr->length; i++) {
1365 vPtr->valueArr[i] = drand48();
1366 }
1367#endif /* HAVE_DRAND48 */
1368 if (vPtr->flush) {
1369 Blt_VectorFlushCache(vPtr);
1370 }
1371 Blt_VectorUpdateClients(vPtr);
1372 return TCL_OK;
1373}
1374
1375/*
1376 * -----------------------------------------------------------------------
1377 *
1378 * SeqOp --
1379 *
1380 * Generates a sequence of values in the vector.
1381 *
1382 * Results:
1383 * A standard Tcl result.
1384 *
1385 * -----------------------------------------------------------------------
1386 */
1387/*ARGSUSED*/
1388static int
1389SeqOp(vPtr, interp, objc, objv)
1390 VectorObject *vPtr;
1391 Tcl_Interp *interp;
1392 int objc; /* Not used. */
1393 Tcl_Obj *CONST *objv;
1394{
1395 register int i;
1396 double start, finish, step;
1397 int fillVector;
1398 int nSteps;
1399 char *string;
1400
1401 if (GetDouble(interp, objv[2], &start) != TCL_OK) {
1402 return TCL_ERROR;
1403 }
1404 fillVector = FALSE;
1405 string = Tcl_GetString(objv[3]);
1406 if ((string[0] == 'e') && (strcmp(string, "end") == 0)) {
1407 fillVector = TRUE;
1408 } else if (GetDouble(interp, objv[3], &finish) != TCL_OK) {
1409 return TCL_ERROR;
1410 }
1411 step = 1.0;
1412 if ((objc > 4) && (GetDouble(interp, objv[4], &step) != TCL_OK)) {
1413 return TCL_ERROR;
1414 }
1415 if (fillVector) {
1416 nSteps = vPtr->length;
1417 } else {
1418 nSteps = (int)((finish - start) / step) + 1;
1419 }
1420 if (nSteps > 0) {
1421 if (Blt_VectorChangeLength(vPtr, nSteps) != TCL_OK) {
1422 return TCL_ERROR;
1423 }
1424 for (i = 0; i < nSteps; i++) {
1425 vPtr->valueArr[i] = start + (step * (double)i);
1426 }
1427 if (vPtr->flush) {
1428 Blt_VectorFlushCache(vPtr);
1429 }
1430 Blt_VectorUpdateClients(vPtr);
1431 }
1432 return TCL_OK;
1433}
1434
1435/*
1436 * -----------------------------------------------------------------------
1437 *
1438 * SetOp --
1439 *
1440 * Sets the data of the vector object from a list of values.
1441 *
1442 * Results:
1443 * A standard Tcl result. If the source vector doesn't exist
1444 * or the source list is not a valid list of numbers, TCL_ERROR
1445 * returned. Otherwise TCL_OK is returned.
1446 *
1447 * Side Effects:
1448 * The vector data is reset. Clients of the vector are notified.
1449 * Any cached array indices are flushed.
1450 *
1451 * -----------------------------------------------------------------------
1452 */
1453/*ARGSUSED*/
1454static int
1455SetOp(vPtr, interp, objc, objv)
1456 VectorObject *vPtr;
1457 Tcl_Interp *interp;
1458 int objc; /* Not used. */
1459 Tcl_Obj *CONST *objv;
1460{
1461 int result;
1462 VectorObject *v2Ptr;
1463 int nElem;
1464 Tcl_Obj **elemObjArr;
1465
1466 /* The source can be either a list of numbers or another vector. */
1467
1468 v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr,
1469 Tcl_GetString(objv[2]), (char **)NULL, NS_SEARCH_BOTH);
1470 if (v2Ptr != NULL) {
1471 if (vPtr == v2Ptr) {
1472 VectorObject *tmpPtr;
1473 /*
1474 * Source and destination vectors are the same. Copy the
1475 * source first into a temporary vector to avoid memory
1476 * overlaps.
1477 */
1478 tmpPtr = Blt_VectorNew(vPtr->dataPtr);
1479 result = Blt_VectorDuplicate(tmpPtr, v2Ptr);
1480 if (result == TCL_OK) {
1481 result = Blt_VectorDuplicate(vPtr, tmpPtr);
1482 }
1483 Blt_VectorFree(tmpPtr);
1484 } else {
1485 result = Blt_VectorDuplicate(vPtr, v2Ptr);
1486 }
1487 } else if (Tcl_ListObjGetElements(interp, objv[2], &nElem, &elemObjArr)
1488 == TCL_OK) {
1489 result = CopyList(vPtr, nElem, elemObjArr);
1490 } else {
1491 return TCL_ERROR;
1492 }
1493
1494 if (result == TCL_OK) {
1495 /*
1496 * The vector has changed; so flush the array indices (they're
1497 * wrong now), find the new range of the data, and notify
1498 * the vector's clients that it's been modified.
1499 */
1500 if (vPtr->flush) {
1501 Blt_VectorFlushCache(vPtr);
1502 }
1503 Blt_VectorUpdateClients(vPtr);
1504 }
1505 return result;
1506}
1507
1508/*
1509 * -----------------------------------------------------------------------
1510 *
1511 * SplitOp --
1512 *
1513 * Copies the values from the vector evens into one of more
1514 * vectors.
1515 *
1516 * Results:
1517 * A standard Tcl result.
1518 *
1519 * -----------------------------------------------------------------------
1520 */
1521/*ARGSUSED*/
1522static int
1523SplitOp(vPtr, interp, objc, objv)
1524 VectorObject *vPtr;
1525 Tcl_Interp *interp;
1526 int objc;
1527 Tcl_Obj *CONST *objv;
1528{
1529 int nVectors;
1530
1531 nVectors = objc - 2;
1532 if ((vPtr->length % nVectors) != 0) {
1533 Tcl_AppendResult(interp, "can't split vector \"", vPtr->name,
1534 "\" into ", Blt_Itoa(nVectors), " even parts.", (char *)NULL);
1535 return TCL_ERROR;
1536 }
1537 if (nVectors > 0) {
1538 VectorObject *v2Ptr;
1539 char *string; /* Name of vector. */
1540 int i, j, k;
1541 int oldSize, newSize, extra, isNew;
1542
1543 extra = vPtr->length / nVectors;
1544 for (i = 0; i < nVectors; i++) {
1545 string = Tcl_GetString(objv[i+2]);
1546 v2Ptr = Blt_VectorCreate(vPtr->dataPtr, string, string, string,
1547 &isNew);
1548 oldSize = v2Ptr->length;
1549 newSize = oldSize + extra;
1550 if (Blt_VectorChangeLength(v2Ptr, newSize) != TCL_OK) {
1551 return TCL_ERROR;
1552 }
1553 for (j = i, k = oldSize; j < vPtr->length; j += nVectors, k++) {
1554 v2Ptr->valueArr[k] = vPtr->valueArr[j];
1555 }
1556 Blt_VectorUpdateClients(v2Ptr);
1557 if (v2Ptr->flush) {
1558 Blt_VectorFlushCache(v2Ptr);
1559 }
1560 }
1561 }
1562 return TCL_OK;
1563}
1564
1565
1566static VectorObject **sortVectorArr; /* Pointer to the array of values
1567 * currently being sorted. */
1568static int nSortVectors;
1569static int reverse; /* Indicates the ordering of the sort. If
1570 * non-zero, the vectors are sorted in
1571 * decreasing order */
1572
1573static int
1574CompareVectors(a, b)
1575 void *a;
1576 void *b;
1577{
1578 double delta;
1579 int i;
1580 int sign;
1581 register VectorObject *vPtr;
1582
1583 sign = (reverse) ? -1 : 1;
1584 for (i = 0; i < nSortVectors; i++) {
1585 vPtr = sortVectorArr[i];
1586 delta = vPtr->valueArr[*(int *)a] - vPtr->valueArr[*(int *)b];
1587 if (delta < 0.0) {
1588 return (-1 * sign);
1589 } else if (delta > 0.0) {
1590 return (1 * sign);
1591 }
1592 }
1593 return 0;
1594}
1595
1596int *
1597Blt_VectorSortIndex(vPtrPtr, nVectors)
1598 VectorObject **vPtrPtr;
1599 int nVectors;
1600{
1601 int *indexArr;
1602 register int i;
1603 VectorObject *vPtr = *vPtrPtr;
1604 int length;
1605
1606 length = vPtr->last - vPtr->first + 1;
1607 indexArr = Blt_Malloc(sizeof(int) * length);
1608 assert(indexArr);
1609 for (i = vPtr->first; i <= vPtr->last; i++) {
1610 indexArr[i] = i;
1611 }
1612 sortVectorArr = vPtrPtr;
1613 nSortVectors = nVectors;
1614 qsort((char *)indexArr, length, sizeof(int),
1615 (QSortCompareProc *)CompareVectors);
1616 return indexArr;
1617}
1618
1619static int *
1620SortVectors(vPtr, interp, objc, objv)
1621 VectorObject *vPtr;
1622 Tcl_Interp *interp;
1623 int objc;
1624 Tcl_Obj *CONST *objv;
1625{
1626 VectorObject **vPtrArray, *v2Ptr;
1627 int *iArr;
1628 register int i;
1629
1630 vPtrArray = Blt_Malloc(sizeof(VectorObject *) * (objc + 1));
1631 assert(vPtrArray);
1632 vPtrArray[0] = vPtr;
1633 iArr = NULL;
1634 for (i = 0; i < objc; i++) {
1635 if (Blt_VectorLookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), &v2Ptr)
1636 != TCL_OK) {
1637 goto error;
1638 }
1639 if (v2Ptr->length != vPtr->length) {
1640 Tcl_AppendResult(interp, "vector \"", v2Ptr->name,
1641 "\" is not the same size as \"", vPtr->name, "\"",
1642 (char *)NULL);
1643 goto error;
1644 }
1645 vPtrArray[i + 1] = v2Ptr;
1646 }
1647 iArr = Blt_VectorSortIndex(vPtrArray, objc + 1);
1648 error:
1649 Blt_Free(vPtrArray);
1650 return iArr;
1651}
1652
1653
1654/*
1655 * -----------------------------------------------------------------------
1656 *
1657 * SortOp --
1658 *
1659 * Sorts the vector object and any other vectors according to
1660 * sorting order of the vector object.
1661 *
1662 * Results:
1663 * A standard Tcl result. If any of the auxiliary vectors are
1664 * a different size than the sorted vector object, TCL_ERROR is
1665 * returned. Otherwise TCL_OK is returned.
1666 *
1667 * Side Effects:
1668 * The vectors are sorted.
1669 *
1670 * -----------------------------------------------------------------------
1671 */
1672
1673static int
1674SortOp(vPtr, interp, objc, objv)
1675 VectorObject *vPtr;
1676 Tcl_Interp *interp;
1677 int objc;
1678 Tcl_Obj *CONST *objv;
1679{
1680 VectorObject *v2Ptr;
1681 char *string;
1682 double *mergeArr;
1683 int *iArr;
1684 int refSize, nBytes;
1685 int result;
1686 register int i, n;
1687
1688 reverse = FALSE;
1689 if (objc > 2) {
1690 int length;
1691
1692 string = Tcl_GetStringFromObj(objv[2], &length);
1693 if (string[0] == '-') {
1694 if ((length > 1) && (strncmp(string, "-reverse", length) == 0)) {
1695 reverse = TRUE;
1696 } else {
1697 Tcl_AppendResult(interp, "unknown flag \"", string,
1698 "\": should be \"-reverse\"", (char *)NULL);
1699 return TCL_ERROR;
1700 }
1701 objc--, objv++;
1702 }
1703 }
1704 if (objc > 2) {
1705 iArr = SortVectors(vPtr, interp, objc - 2, objv + 2);
1706 } else {
1707 iArr = Blt_VectorSortIndex(&vPtr, 1);
1708 }
1709 if (iArr == NULL) {
1710 return TCL_ERROR;
1711 }
1712 refSize = vPtr->length;
1713
1714 /*
1715 * Create an array to store a copy of the current values of the
1716 * vector. We'll merge the values back into the vector based upon
1717 * the indices found in the index array.
1718 */
1719 nBytes = sizeof(double) * refSize;
1720 mergeArr = Blt_Malloc(nBytes);
1721 assert(mergeArr);
1722 memcpy((char *)mergeArr, (char *)vPtr->valueArr, nBytes);
1723 for (n = 0; n < refSize; n++) {
1724 vPtr->valueArr[n] = mergeArr[iArr[n]];
1725 }
1726 if (vPtr->flush) {
1727 Blt_VectorFlushCache(vPtr);
1728 }
1729 Blt_VectorUpdateClients(vPtr);
1730
1731 /* Now sort any other vectors in the same fashion. The vectors
1732 * must be the same size as the iArr though. */
1733 result = TCL_ERROR;
1734 for (i = 2; i < objc; i++) {
1735 if (Blt_VectorLookupName(vPtr->dataPtr, Tcl_GetString(objv[i]), &v2Ptr)
1736 != TCL_OK) {
1737 goto error;
1738 }
1739 if (v2Ptr->length != refSize) {
1740 Tcl_AppendResult(interp, "vector \"", v2Ptr->name,
1741 "\" is not the same size as \"", vPtr->name, "\"",
1742 (char *)NULL);
1743 goto error;
1744 }
1745 memcpy((char *)mergeArr, (char *)v2Ptr->valueArr, nBytes);
1746 for (n = 0; n < refSize; n++) {
1747 v2Ptr->valueArr[n] = mergeArr[iArr[n]];
1748 }
1749 Blt_VectorUpdateClients(v2Ptr);
1750 if (v2Ptr->flush) {
1751 Blt_VectorFlushCache(v2Ptr);
1752 }
1753 }
1754 result = TCL_OK;
1755 error:
1756 Blt_Free(mergeArr);
1757 Blt_Free(iArr);
1758 return result;
1759}
1760
1761/*
1762 * -----------------------------------------------------------------------
1763 *
1764 * ArithOp --
1765 *
1766 * Results:
1767 * A standard Tcl result. If the source vector doesn't exist
1768 * or the source list is not a valid list of numbers, TCL_ERROR
1769 * returned. Otherwise TCL_OK is returned.
1770 *
1771 * Side Effects:
1772 * The vector data is reset. Clients of the vector are notified.
1773 * Any cached array indices are flushed.
1774 *
1775 * -----------------------------------------------------------------------
1776 */
1777/*ARGSUSED*/
1778static int
1779ArithOp(vPtr, interp, objc, objv)
1780 VectorObject *vPtr;
1781 Tcl_Interp *interp;
1782 int objc; /* Not used. */
1783 Tcl_Obj *CONST *objv;
1784{
1785 register double value;
1786 register int i;
1787 VectorObject *v2Ptr;
1788 double scalar;
1789 Tcl_Obj *listObjPtr;
1790 char *string;
1791
1792 v2Ptr = Blt_VectorParseElement((Tcl_Interp *)NULL, vPtr->dataPtr,
1793 Tcl_GetString(objv[2]), (char **)NULL, NS_SEARCH_BOTH);
1794 if (v2Ptr != NULL) {
1795 register int j;
1796 int length;
1797
1798 length = v2Ptr->last - v2Ptr->first + 1;
1799 if (length != vPtr->length) {
1800 Tcl_AppendResult(interp, "vectors \"", Tcl_GetString(objv[0]),
1801 "\" and \"", Tcl_GetString(objv[2]),
1802 "\" are not the same length", (char *)NULL);
1803 return TCL_ERROR;
1804 }
1805 string = Tcl_GetString(objv[1]);
1806 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1807 switch (string[0]) {
1808 case '*':
1809 for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) {
1810 value = vPtr->valueArr[i] * v2Ptr->valueArr[j];
1811 Tcl_ListObjAppendElement(interp, listObjPtr,
1812 Tcl_NewDoubleObj(value));
1813 }
1814 break;
1815
1816 case '/':
1817 for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) {
1818 value = vPtr->valueArr[i] / v2Ptr->valueArr[j];
1819 Tcl_ListObjAppendElement(interp, listObjPtr,
1820 Tcl_NewDoubleObj(value));
1821 }
1822 break;
1823
1824 case '-':
1825 for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) {
1826 value = vPtr->valueArr[i] - v2Ptr->valueArr[j];
1827 Tcl_ListObjAppendElement(interp, listObjPtr,
1828 Tcl_NewDoubleObj(value));
1829 }
1830 break;
1831
1832 case '+':
1833 for (i = 0, j = v2Ptr->first; i < vPtr->length; i++, j++) {
1834 value = vPtr->valueArr[i] + v2Ptr->valueArr[j];
1835 Tcl_ListObjAppendElement(interp, listObjPtr,
1836 Tcl_NewDoubleObj(value));
1837 }
1838 break;
1839 }
1840 Tcl_SetObjResult(interp, listObjPtr);
1841
1842 } else if (GetDouble(interp, objv[2], &scalar) == TCL_OK) {
1843 listObjPtr = Tcl_NewListObj(0, (Tcl_Obj **)NULL);
1844 string = Tcl_GetString(objv[1]);
1845 switch (string[0]) {
1846 case '*':
1847 for (i = 0; i < vPtr->length; i++) {
1848 value = vPtr->valueArr[i] * scalar;
1849 Tcl_ListObjAppendElement(interp, listObjPtr,
1850 Tcl_NewDoubleObj(value));
1851 }
1852 break;
1853
1854 case '/':
1855 for (i = 0; i < vPtr->length; i++) {
1856 value = vPtr->valueArr[i] / scalar;
1857 Tcl_ListObjAppendElement(interp, listObjPtr,
1858 Tcl_NewDoubleObj(value));
1859 }
1860 break;
1861
1862 case '-':
1863 for (i = 0; i < vPtr->length; i++) {
1864 value = vPtr->valueArr[i] - scalar;
1865 Tcl_ListObjAppendElement(interp, listObjPtr,
1866 Tcl_NewDoubleObj(value));
1867 }
1868 break;
1869
1870 case '+':
1871 for (i = 0; i < vPtr->length; i++) {
1872 value = vPtr->valueArr[i] + scalar;
1873 Tcl_ListObjAppendElement(interp, listObjPtr,
1874 Tcl_NewDoubleObj(value));
1875 }
1876 break;
1877 }
1878 Tcl_SetObjResult(interp, listObjPtr);
1879 } else {
1880 return TCL_ERROR;
1881 }
1882 return TCL_OK;
1883}
1884
1885/*
1886 *----------------------------------------------------------------------
1887 *
1888 * VectorInstCmd --
1889 *
1890 * Parses and invokes the appropriate vector instance command
1891 * option.
1892 *
1893 * Results:
1894 * A standard Tcl result.
1895 *
1896 *----------------------------------------------------------------------
1897 */
1898static Blt_OpSpec vectorInstOps[] =
1899{
1900 {"*", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/
1901 {"+", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/
1902 {"-", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/
1903 {"/", 1, (Blt_Op)ArithOp, 3, 3, "item",}, /*Deprecated*/
1904 {"append", 1, (Blt_Op)AppendOp, 3, 0, "item ?item...?",},
1905 {"binread", 1, (Blt_Op)BinreadOp, 3, 0, "channel ?numValues? ?flags?",},
1906 {"clear", 1, (Blt_Op)ClearOp, 2, 2, "",},
1907 {"delete", 2, (Blt_Op)DeleteOp, 2, 0, "index ?index...?",},
1908 {"dup", 2, (Blt_Op)DupOp, 3, 0, "vecName",},
1909 {"index", 1, (Blt_Op)IndexOp, 3, 4, "index ?value?",},
1910 {"length", 1, (Blt_Op)LengthOp, 2, 3, "?newSize?",},
1911 {"merge", 1, (Blt_Op)MergeOp, 3, 0, "vecName ?vecName...?",},
1912 {"normalize", 3, (Blt_Op)NormalizeOp, 2, 3, "?vecName?",}, /*Deprecated*/
1913 {"notify", 3, (Blt_Op)NotifyOp, 3, 3, "keyword",},
1914 {"offset", 2, (Blt_Op)OffsetOp, 2, 3, "?offset?",},
1915 {"populate", 1, (Blt_Op)PopulateOp, 4, 4, "vecName density",},
1916 {"random", 4, (Blt_Op)RandomOp, 2, 2, "",}, /*Deprecated*/
1917 {"range", 4, (Blt_Op)RangeOp, 4, 4, "first last",},
1918 {"search", 3, (Blt_Op)SearchOp, 3, 4, "?-value? value ?value?",},
1919 {"seq", 3, (Blt_Op)SeqOp, 4, 5, "start end ?step?",},
1920 {"set", 3, (Blt_Op)SetOp, 3, 3, "list",},
1921 {"sort", 2, (Blt_Op)SortOp, 2, 0, "?-reverse? ?vecName...?",},
1922 {"split", 2, (Blt_Op)SplitOp, 2, 0, "?vecName...?",},
1923 {"variable", 1, (Blt_Op)MapOp, 2, 3, "?varName?",},
1924};
1925
1926static int nInstOps = sizeof(vectorInstOps) / sizeof(Blt_OpSpec);
1927
1928int
1929Blt_VectorInstCmd(clientData, interp, objc, objv)
1930 ClientData clientData;
1931 Tcl_Interp *interp;
1932 int objc;
1933 Tcl_Obj *CONST *objv;
1934{
1935 Blt_Op proc;
1936 VectorObject *vPtr = clientData;
1937
1938 vPtr->first = 0;
1939 vPtr->last = vPtr->length - 1;
1940 proc = Blt_GetOpFromObj(interp, nInstOps, vectorInstOps, BLT_OP_ARG1, objc,
1941 objv, 0);
1942 if (proc == NULL) {
1943 return TCL_ERROR;
1944 }
1945 return (*proc) (vPtr, interp, objc, objv);
1946}
1947
1948
1949
1950/*
1951 * ----------------------------------------------------------------------
1952 *
1953 * Blt_VectorVarTrace --
1954 *
1955 * Results:
1956 * Returns NULL on success. Only called from a variable trace.
1957 *
1958 * Side effects:
1959 *
1960 * ----------------------------------------------------------------------
1961 */
1962char *
1963Blt_VectorVarTrace(clientData, interp, part1, part2, flags)
1964 ClientData clientData; /* Vector object. */
1965 Tcl_Interp *interp;
1966 char *part1, *part2;
1967 int flags;
1968{
1969 Blt_VectorIndexProc *indexProc;
1970 VectorObject *vPtr = clientData;
1971 int first, last;
1972 int varFlags;
1973#define MAX_ERR_MSG 1023
1974 static char message[MAX_ERR_MSG + 1];
1975
1976 if (part2 == NULL) {
1977 if (flags & TCL_TRACE_UNSETS) {
1978 Blt_Free(vPtr->arrayName);
1979 vPtr->arrayName = NULL;
1980 vPtr->varNsPtr = NULL;
1981 if (vPtr->freeOnUnset) {
1982 Blt_VectorFree(vPtr);
1983 }
1984 }
1985 return NULL;
1986 }
1987 if (Blt_VectorGetIndexRange(interp, vPtr, part2, INDEX_ALL_FLAGS,
1988 &indexProc) != TCL_OK) {
1989 goto error;
1990 }
1991 first = vPtr->first, last = vPtr->last;
1992 varFlags = TCL_LEAVE_ERR_MSG | (TCL_GLOBAL_ONLY & flags);
1993 if (flags & TCL_TRACE_WRITES) {
1994 double value;
1995 Tcl_Obj *objPtr;
1996
1997 if (first == SPECIAL_INDEX) { /* Tried to set "min" or "max" */
1998 return "read-only index";
1999 }
2000 objPtr = Tcl_GetVar2Ex(interp, part1, part2, varFlags);
2001 if (objPtr == NULL) {
2002 goto error;
2003 }
2004 if (GetDouble(interp, objPtr, &value) != TCL_OK) {
2005 if ((last == first) && (first >= 0)) {
2006 /* Single numeric index. Reset the array element to
2007 * its old value on errors */
2008 Tcl_SetVar2Ex(interp, part1, part2, objPtr, varFlags);
2009 }
2010 goto error;
2011 }
2012 if (first == vPtr->length) {
2013 if (Blt_VectorChangeLength(vPtr, vPtr->length + 1) != TCL_OK) {
2014 return "error resizing vector";
2015 }
2016 }
2017 /* Set possibly an entire range of values */
2018 ReplicateValue(vPtr, first, last, value);
2019 } else if (flags & TCL_TRACE_READS) {
2020 double value;
2021 Tcl_Obj *objPtr;
2022
2023 if (vPtr->length == 0) {
2024 if (Tcl_SetVar2(interp, part1, part2, "", varFlags) == NULL) {
2025 goto error;
2026 }
2027 return NULL;
2028 }
2029 if (first == vPtr->length) {
2030 return "write-only index";
2031 }
2032 if (first == last) {
2033 if (first >= 0) {
2034 value = vPtr->valueArr[first];
2035 } else {
2036 vPtr->first = 0, vPtr->last = vPtr->length - 1;
2037 value = (*indexProc) ((Blt_Vector *) vPtr);
2038 }
2039 objPtr = Tcl_NewDoubleObj(value);
2040 if (Tcl_SetVar2Ex(interp, part1, part2, objPtr, varFlags) == NULL) {
2041 Tcl_DecrRefCount(objPtr);
2042 goto error;
2043 }
2044 } else {
2045 objPtr = GetValues(vPtr, first, last);
2046 if (Tcl_SetVar2Ex(interp, part1, part2, objPtr, varFlags) == NULL) {
2047 Tcl_DecrRefCount(objPtr);
2048 goto error;
2049 }
2050 }
2051 } else if (flags & TCL_TRACE_UNSETS) {
2052 register int i, j;
2053
2054 if ((first == vPtr->length) || (first == SPECIAL_INDEX)) {
2055 return "special vector index";
2056 }
2057 /*
2058 * Collapse the vector from the point of the first unset element.
2059 * Also flush any array variable entries so that the shift is
2060 * reflected when the array variable is read.
2061 */
2062 for (i = first, j = last + 1; j < vPtr->length; i++, j++) {
2063 vPtr->valueArr[i] = vPtr->valueArr[j];
2064 }
2065 vPtr->length -= ((last - first) + 1);
2066 if (vPtr->flush) {
2067 Blt_VectorFlushCache(vPtr);
2068 }
2069 } else {
2070 return "unknown variable trace flag";
2071 }
2072 if (flags & (TCL_TRACE_UNSETS | TCL_TRACE_WRITES)) {
2073 Blt_VectorUpdateClients(vPtr);
2074 }
2075 Tcl_ResetResult(interp);
2076 return NULL;
2077
2078 error:
2079 strncpy(message, Tcl_GetStringResult(interp), MAX_ERR_MSG);
2080 message[MAX_ERR_MSG] = '\0';
2081 return message;
2082}
2083
2084#endif /* TCL_MAJOR_VERSION > 7 */
Note: See TracBrowser for help on using the repository browser.