source: HiSusy/trunk/Delphes-3.0.0/external/tcl/tclCmdAH.c @ 1

Last change on this file since 1 was 1, checked in by zerwas, 11 years ago

first import of structure, PYTHIA8 and DELPHES

File size: 30.9 KB
Line 
1/*
2 * tclCmdAH.c --
3 *
4 *      This file contains the top-level command routines for most of
5 *      the Tcl built-in commands whose names begin with the letters
6 *      A to H.
7 *
8 * Copyright (c) 1987-1993 The Regents of the University of California.
9 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10 *
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 *
14 * RCS: @(#) $Id: tclCmdAH.c,v 1.1 2008-06-04 13:58:04 demin Exp $
15 */
16
17#include "tclInt.h"
18#include "tclPort.h"
19
20/*
21 *----------------------------------------------------------------------
22 *
23 * Tcl_BreakCmd --
24 *
25 *      This procedure is invoked to process the "break" Tcl command.
26 *      See the user documentation for details on what it does.
27 *
28 *      With the bytecode compiler, this procedure is only called when
29 *      a command name is computed at runtime, and is "break" or the name
30 *      to which "break" was renamed: e.g., "set z break; $z"
31 *
32 * Results:
33 *      A standard Tcl result.
34 *
35 * Side effects:
36 *      See the user documentation.
37 *
38 *----------------------------------------------------------------------
39 */
40
41        /* ARGSUSED */
42int
43Tcl_BreakCmd(dummy, interp, argc, argv)
44    ClientData dummy;                   /* Not used. */
45    Tcl_Interp *interp;                 /* Current interpreter. */
46    int argc;                           /* Number of arguments. */
47    char **argv;                        /* Argument strings. */
48{
49    if (argc != 1) {
50        Tcl_AppendResult(interp, "wrong # args: should be \"",
51                argv[0], "\"", (char *) NULL);
52        return TCL_ERROR;
53    }
54    return TCL_BREAK;
55}
56
57/*
58 *----------------------------------------------------------------------
59 *
60 * Tcl_CaseObjCmd --
61 *
62 *      This procedure is invoked to process the "case" Tcl command.
63 *      See the user documentation for details on what it does.
64 *
65 * Results:
66 *      A standard Tcl object result.
67 *
68 * Side effects:
69 *      See the user documentation.
70 *
71 *----------------------------------------------------------------------
72 */
73
74        /* ARGSUSED */
75int
76Tcl_CaseObjCmd(dummy, interp, objc, objv)
77    ClientData dummy;           /* Not used. */
78    Tcl_Interp *interp;         /* Current interpreter. */
79    int objc;                   /* Number of arguments. */
80    Tcl_Obj *CONST objv[];      /* Argument objects. */
81{
82    register int i;
83    int body, result;
84    char *string, *arg;
85    int argLen, caseObjc;
86    Tcl_Obj *CONST *caseObjv;
87    Tcl_Obj *armPtr;
88
89    if (objc < 3) {
90        Tcl_WrongNumArgs(interp, 1, objv,
91                "string ?in? patList body ... ?default body?");
92        return TCL_ERROR;
93    }
94
95    /*
96     * THIS FAILS IF AN OBJECT'S STRING REP HAS A NULL BYTE.
97     */
98   
99    string = Tcl_GetStringFromObj(objv[1], &argLen);
100    body = -1;
101
102    arg = Tcl_GetStringFromObj(objv[2], &argLen);
103    if (strcmp(arg, "in") == 0) {
104        i = 3;
105    } else {
106        i = 2;
107    }
108    caseObjc = objc - i;
109    caseObjv = objv + i;
110
111    /*
112     * If all of the pattern/command pairs are lumped into a single
113     * argument, split them out again.
114     * THIS FAILS IF THE ARG'S STRING REP CONTAINS A NULL
115     */
116
117    if (caseObjc == 1) {
118        Tcl_Obj **newObjv;
119       
120        Tcl_ListObjGetElements(interp, caseObjv[0], &caseObjc, &newObjv);
121        caseObjv = newObjv;
122    }
123
124    for (i = 0;  i < caseObjc;  i += 2) {
125        int patObjc, j;
126        char **patObjv;
127        char *pat;
128        register char *p;
129
130        if (i == (caseObjc-1)) {
131            Tcl_ResetResult(interp);
132            Tcl_AppendToObj(Tcl_GetObjResult(interp),
133                    "extra case pattern with no body", -1);
134            return TCL_ERROR;
135        }
136
137        /*
138         * Check for special case of single pattern (no list) with
139         * no backslash sequences.
140         */
141
142        pat = Tcl_GetStringFromObj(caseObjv[i], &argLen);
143        for (p = pat;  *p != 0;  p++) { /* FAILS IF NULL BYTE */
144            if (isspace(UCHAR(*p)) || (*p == '\\')) {
145                break;
146            }
147        }
148        if (*p == 0) {
149            if ((*pat == 'd') && (strcmp(pat, "default") == 0)) {
150                body = i+1;
151            }
152            if (Tcl_StringMatch(string, pat)) {
153                body = i+1;
154                goto match;
155            }
156            continue;
157        }
158
159
160        /*
161         * Break up pattern lists, then check each of the patterns
162         * in the list.
163         */
164
165        result = Tcl_SplitList(interp, pat, &patObjc, &patObjv);
166        if (result != TCL_OK) {
167            return result;
168        }
169        for (j = 0; j < patObjc; j++) {
170            if (Tcl_StringMatch(string, patObjv[j])) {
171                body = i+1;
172                break;
173            }
174        }
175        ckfree((char *) patObjv);
176        if (j < patObjc) {
177            break;
178        }
179    }
180
181    match:
182    if (body != -1) {
183        armPtr = caseObjv[body-1];
184        result = Tcl_EvalObj(interp, caseObjv[body]);
185        if (result == TCL_ERROR) {
186            char msg[100];
187           
188            arg = Tcl_GetStringFromObj(armPtr, &argLen);
189            sprintf(msg, "\n    (\"%.*s\" arm line %d)", argLen, arg,
190                    interp->errorLine);
191            Tcl_AddObjErrorInfo(interp, msg, -1);
192        }
193        return result;
194    }
195
196    /*
197     * Nothing matched: return nothing.
198     */
199
200    return TCL_OK;
201}
202
203/*
204 *----------------------------------------------------------------------
205 *
206 * Tcl_CatchObjCmd --
207 *
208 *      This object-based procedure is invoked to process the "catch" Tcl
209 *      command. See the user documentation for details on what it does.
210 *
211 * Results:
212 *      A standard Tcl object result.
213 *
214 * Side effects:
215 *      See the user documentation.
216 *
217 *----------------------------------------------------------------------
218 */
219
220        /* ARGSUSED */
221int
222Tcl_CatchObjCmd(dummy, interp, objc, objv)
223    ClientData dummy;           /* Not used. */
224    Tcl_Interp *interp;         /* Current interpreter. */
225    int objc;                   /* Number of arguments. */
226    Tcl_Obj *CONST objv[];      /* Argument objects. */
227{
228    Tcl_Obj *varNamePtr = NULL;
229    int result;
230
231    if ((objc != 2) && (objc != 3)) {
232        Tcl_WrongNumArgs(interp, 1, objv, "command ?varName?");
233        return TCL_ERROR;
234    }
235
236    /*
237     * Save a pointer to the variable name object, if any, in case the
238     * Tcl_EvalObj reallocates the bytecode interpreter's evaluation
239     * stack rendering objv invalid.
240     */
241   
242    if (objc == 3) {
243        varNamePtr = objv[2];
244    }
245   
246    result = Tcl_EvalObj(interp, objv[1]);
247   
248    if (objc == 3) {
249        if (Tcl_ObjSetVar2(interp, varNamePtr, NULL,
250                    Tcl_GetObjResult(interp), TCL_PARSE_PART1) == NULL) {
251            Tcl_ResetResult(interp);
252            Tcl_AppendToObj(Tcl_GetObjResult(interp), 
253                    "couldn't save command result in variable", -1);
254            return TCL_ERROR;
255        }
256    }
257
258    /*
259     * Set the interpreter's object result to an integer object holding the
260     * integer Tcl_EvalObj result. Note that we don't bother generating a
261     * string representation. We reset the interpreter's object result
262     * to an unshared empty object and then set it to be an integer object.
263     */
264
265    Tcl_ResetResult(interp);
266    Tcl_SetIntObj(Tcl_GetObjResult(interp), result);
267    return TCL_OK;
268}
269/*
270 *----------------------------------------------------------------------
271 *
272 * Tcl_ConcatObjCmd --
273 *
274 *      This object-based procedure is invoked to process the "concat" Tcl
275 *      command. See the user documentation for details on what it does/
276 *
277 * Results:
278 *      A standard Tcl object result.
279 *
280 * Side effects:
281 *      See the user documentation.
282 *
283 *----------------------------------------------------------------------
284 */
285
286        /* ARGSUSED */
287int
288Tcl_ConcatObjCmd(dummy, interp, objc, objv)
289    ClientData dummy;           /* Not used. */
290    Tcl_Interp *interp;         /* Current interpreter. */
291    int objc;                   /* Number of arguments. */
292    Tcl_Obj *CONST objv[];      /* Argument objects. */
293{
294    if (objc >= 2) {
295        Tcl_SetObjResult(interp, Tcl_ConcatObj(objc-1, objv+1));
296    }
297    return TCL_OK;
298}
299
300/*
301 *----------------------------------------------------------------------
302 *
303 * Tcl_ContinueCmd -
304 *
305 *      This procedure is invoked to process the "continue" Tcl command.
306 *      See the user documentation for details on what it does.
307 *
308 *      With the bytecode compiler, this procedure is only called when
309 *      a command name is computed at runtime, and is "continue" or the name
310 *      to which "continue" was renamed: e.g., "set z continue; $z"
311 *
312 * Results:
313 *      A standard Tcl result.
314 *
315 * Side effects:
316 *      See the user documentation.
317 *
318 *----------------------------------------------------------------------
319 */
320
321        /* ARGSUSED */
322int
323Tcl_ContinueCmd(dummy, interp, argc, argv)
324    ClientData dummy;                   /* Not used. */
325    Tcl_Interp *interp;                 /* Current interpreter. */
326    int argc;                           /* Number of arguments. */
327    char **argv;                        /* Argument strings. */
328{
329    if (argc != 1) {
330        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
331                "\"", (char *) NULL);
332        return TCL_ERROR;
333    }
334    return TCL_CONTINUE;
335}
336
337/*
338 *----------------------------------------------------------------------
339 *
340 * Tcl_ErrorObjCmd --
341 *
342 *      This procedure is invoked to process the "error" Tcl command.
343 *      See the user documentation for details on what it does.
344 *
345 * Results:
346 *      A standard Tcl object result.
347 *
348 * Side effects:
349 *      See the user documentation.
350 *
351 *----------------------------------------------------------------------
352 */
353
354        /* ARGSUSED */
355int
356Tcl_ErrorObjCmd(dummy, interp, objc, objv)
357    ClientData dummy;           /* Not used. */
358    Tcl_Interp *interp;         /* Current interpreter. */
359    int objc;                   /* Number of arguments. */
360    Tcl_Obj *CONST objv[];      /* Argument objects. */
361{
362    Interp *iPtr = (Interp *) interp;
363    register Tcl_Obj *namePtr;
364    char *info;
365    int infoLen;
366
367    if ((objc < 2) || (objc > 4)) {
368        Tcl_WrongNumArgs(interp, 1, objv, "message ?errorInfo? ?errorCode?");
369        return TCL_ERROR;
370    }
371   
372    if (objc >= 3) {            /* process the optional info argument */
373        info = Tcl_GetStringFromObj(objv[2], &infoLen);
374        if (*info != 0) {
375            Tcl_AddObjErrorInfo(interp, info, infoLen);
376            iPtr->flags |= ERR_ALREADY_LOGGED;
377        }
378    }
379   
380    if (objc == 4) {
381        namePtr = Tcl_NewStringObj("errorCode", -1);
382        Tcl_ObjSetVar2(interp, namePtr, (Tcl_Obj *) NULL, objv[3],
383                TCL_GLOBAL_ONLY);
384        iPtr->flags |= ERROR_CODE_SET;
385        Tcl_DecrRefCount(namePtr); /* we're done with name object */
386    }
387   
388    Tcl_SetObjResult(interp, objv[1]);
389    return TCL_ERROR;
390}
391
392/*
393 *----------------------------------------------------------------------
394 *
395 * Tcl_EvalObjCmd --
396 *
397 *      This object-based procedure is invoked to process the "eval" Tcl
398 *      command. See the user documentation for details on what it does.
399 *
400 * Results:
401 *      A standard Tcl object result.
402 *
403 * Side effects:
404 *      See the user documentation.
405 *
406 *----------------------------------------------------------------------
407 */
408
409        /* ARGSUSED */
410int
411Tcl_EvalObjCmd(dummy, interp, objc, objv)
412    ClientData dummy;           /* Not used. */
413    Tcl_Interp *interp;         /* Current interpreter. */
414    int objc;                   /* Number of arguments. */
415    Tcl_Obj *CONST objv[];      /* Argument objects. */
416{
417    int result;
418    register Tcl_Obj *objPtr;
419
420    if (objc < 2) {
421        Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?");
422        return TCL_ERROR;
423    }
424   
425    if (objc == 2) {
426        result = Tcl_EvalObj(interp, objv[1]);
427    } else {
428        /*
429         * More than one argument: concatenate them together with spaces
430         * between, then evaluate the result.
431         */
432   
433        objPtr = Tcl_ConcatObj(objc-1, objv+1);
434        result = Tcl_EvalObj(interp, objPtr);
435        Tcl_DecrRefCount(objPtr);  /* we're done with the object */
436    }
437    if (result == TCL_ERROR) {
438        char msg[60];
439        sprintf(msg, "\n    (\"eval\" body line %d)", interp->errorLine);
440        Tcl_AddObjErrorInfo(interp, msg, -1);
441    }
442    return result;
443}
444
445/*
446 *----------------------------------------------------------------------
447 *
448 * Tcl_ExprObjCmd --
449 *
450 *      This object-based procedure is invoked to process the "expr" Tcl
451 *      command. See the user documentation for details on what it does.
452 *
453 *      With the bytecode compiler, this procedure is called in two
454 *      circumstances: 1) to execute expr commands that are too complicated
455 *      or too unsafe to try compiling directly into an inline sequence of
456 *      instructions, and 2) to execute commands where the command name is
457 *      computed at runtime and is "expr" or the name to which "expr" was
458 *      renamed (e.g., "set z expr; $z 2+3")
459 *
460 * Results:
461 *      A standard Tcl object result.
462 *
463 * Side effects:
464 *      See the user documentation.
465 *
466 *----------------------------------------------------------------------
467 */
468
469        /* ARGSUSED */
470int
471Tcl_ExprObjCmd(dummy, interp, objc, objv)
472    ClientData dummy;           /* Not used. */
473    Tcl_Interp *interp;         /* Current interpreter. */
474    int objc;                   /* Number of arguments. */
475    Tcl_Obj *CONST objv[];      /* Argument objects. */
476{
477    register Tcl_Obj *objPtr;
478    Tcl_Obj *resultPtr;
479    register char *bytes;
480    int length, i, result;
481
482    if (objc < 2) {
483        Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?");
484        return TCL_ERROR;
485    }
486
487    if (objc == 2) {
488        result = Tcl_ExprObj(interp, objv[1], &resultPtr);
489        if (result == TCL_OK) {
490            Tcl_SetObjResult(interp, resultPtr);
491            Tcl_DecrRefCount(resultPtr);  /* done with the result object */
492        }
493        return result;
494    }
495
496    /*
497     * Create a new object holding the concatenated argument strings.
498     * THIS FAILS IF AN OBJECT'S STRING REP HAS A NULL BYTE.
499     */
500
501    bytes = Tcl_GetStringFromObj(objv[1], &length);
502    objPtr = Tcl_NewStringObj(bytes, length);
503    Tcl_IncrRefCount(objPtr);
504    for (i = 2;  i < objc;  i++) {
505        Tcl_AppendToObj(objPtr, " ", 1);
506        bytes = Tcl_GetStringFromObj(objv[i], &length);
507        Tcl_AppendToObj(objPtr, bytes, length);
508    }
509
510    /*
511     * Evaluate the concatenated string object.
512     */
513
514    result = Tcl_ExprObj(interp, objPtr, &resultPtr);
515    if (result == TCL_OK) {
516        Tcl_SetObjResult(interp, resultPtr);
517        Tcl_DecrRefCount(resultPtr);  /* done with the result object */
518    }
519
520    /*
521     * Free allocated resources.
522     */
523   
524    Tcl_DecrRefCount(objPtr);
525    return result;
526}
527
528/*
529 *----------------------------------------------------------------------
530 *
531 * Tcl_ForCmd --
532 *
533 *      This procedure is invoked to process the "for" Tcl command.
534 *      See the user documentation for details on what it does.
535 *
536 *      With the bytecode compiler, this procedure is only called when
537 *      a command name is computed at runtime, and is "for" or the name
538 *      to which "for" was renamed: e.g.,
539 *      "set z for; $z {set i 0} {$i<100} {incr i} {puts $i}"
540 *
541 * Results:
542 *      A standard Tcl result.
543 *
544 * Side effects:
545 *      See the user documentation.
546 *
547 *----------------------------------------------------------------------
548 */
549
550        /* ARGSUSED */
551int
552Tcl_ForCmd(dummy, interp, argc, argv)
553    ClientData dummy;                   /* Not used. */
554    Tcl_Interp *interp;                 /* Current interpreter. */
555    int argc;                           /* Number of arguments. */
556    char **argv;                        /* Argument strings. */
557{
558    int result, value;
559
560    if (argc != 5) {
561        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
562                " start test next command\"", (char *) NULL);
563        return TCL_ERROR;
564    }
565
566    result = Tcl_Eval(interp, argv[1]);
567    if (result != TCL_OK) {
568        if (result == TCL_ERROR) {
569            Tcl_AddErrorInfo(interp, "\n    (\"for\" initial command)");
570        }
571        return result;
572    }
573    while (1) {
574        result = Tcl_ExprBoolean(interp, argv[2], &value);
575        if (result != TCL_OK) {
576            return result;
577        }
578        if (!value) {
579            break;
580        }
581        result = Tcl_Eval(interp, argv[4]);
582        if ((result != TCL_OK) && (result != TCL_CONTINUE)) {
583            if (result == TCL_ERROR) {
584                char msg[60];
585                sprintf(msg, "\n    (\"for\" body line %d)",interp->errorLine);
586                Tcl_AddErrorInfo(interp, msg);
587            }
588            break;
589        }
590        result = Tcl_Eval(interp, argv[3]);
591        if (result == TCL_BREAK) {
592            break;
593        } else if (result != TCL_OK) {
594            if (result == TCL_ERROR) {
595                Tcl_AddErrorInfo(interp, "\n    (\"for\" loop-end command)");
596            }
597            return result;
598        }
599    }
600    if (result == TCL_BREAK) {
601        result = TCL_OK;
602    }
603    if (result == TCL_OK) {
604        Tcl_ResetResult(interp);
605    }
606    return result;
607}
608
609/*
610 *----------------------------------------------------------------------
611 *
612 * Tcl_ForeachObjCmd --
613 *
614 *      This object-based procedure is invoked to process the "foreach" Tcl
615 *      command.  See the user documentation for details on what it does.
616 *
617 * Results:
618 *      A standard Tcl object result.
619 *
620 * Side effects:
621 *      See the user documentation.
622 *
623 *----------------------------------------------------------------------
624 */
625
626        /* ARGSUSED */
627int
628Tcl_ForeachObjCmd(dummy, interp, objc, objv)
629    ClientData dummy;           /* Not used. */
630    Tcl_Interp *interp;         /* Current interpreter. */
631    int objc;                   /* Number of arguments. */
632    Tcl_Obj *CONST objv[];      /* Argument objects. */
633{
634    int result = TCL_OK;
635    int i;                      /* i selects a value list */
636    int j, maxj;                /* Number of loop iterations */
637    int v;                      /* v selects a loop variable */
638    int numLists;               /* Count of value lists */
639    Tcl_Obj *bodyPtr;
640
641    /*
642     * We copy the argument object pointers into a local array to avoid
643     * the problem that "objv" might become invalid. It is a pointer into
644     * the evaluation stack and that stack might be grown and reallocated
645     * if the loop body requires a large amount of stack space.
646     */
647   
648#define NUM_ARGS 9
649    Tcl_Obj *(argObjStorage[NUM_ARGS]);
650    Tcl_Obj **argObjv = argObjStorage;
651   
652#define STATIC_LIST_SIZE 4
653    int indexArray[STATIC_LIST_SIZE];     /* Array of value list indices */
654    int varcListArray[STATIC_LIST_SIZE];  /* # loop variables per list */
655    Tcl_Obj **varvListArray[STATIC_LIST_SIZE]; /* Array of var name lists */
656    int argcListArray[STATIC_LIST_SIZE];  /* Array of value list sizes */
657    Tcl_Obj **argvListArray[STATIC_LIST_SIZE]; /* Array of value lists */
658
659    int *index = indexArray;
660    int *varcList = varcListArray;
661    Tcl_Obj ***varvList = varvListArray;
662    int *argcList = argcListArray;
663    Tcl_Obj ***argvList = argvListArray;
664
665    if (objc < 4 || (objc%2 != 0)) {
666        Tcl_WrongNumArgs(interp, 1, objv,
667                "varList list ?varList list ...? command");
668        return TCL_ERROR;
669    }
670
671    /*
672     * Create the object argument array "argObjv". Make sure argObjv is
673     * large enough to hold the objc arguments.
674     */
675
676    if (objc > NUM_ARGS) {
677        argObjv = (Tcl_Obj **) ckalloc(objc * sizeof(Tcl_Obj *));
678    }
679    for (i = 0;  i < objc;  i++) {
680        argObjv[i] = objv[i];
681    }
682
683    /*
684     * Manage numList parallel value lists.
685     * argvList[i] is a value list counted by argcList[i]
686     * varvList[i] is the list of variables associated with the value list
687     * varcList[i] is the number of variables associated with the value list
688     * index[i] is the current pointer into the value list argvList[i]
689     */
690
691    numLists = (objc-2)/2;
692    if (numLists > STATIC_LIST_SIZE) {
693        index = (int *) ckalloc(numLists * sizeof(int));
694        varcList = (int *) ckalloc(numLists * sizeof(int));
695        varvList = (Tcl_Obj ***) ckalloc(numLists * sizeof(Tcl_Obj **));
696        argcList = (int *) ckalloc(numLists * sizeof(int));
697        argvList = (Tcl_Obj ***) ckalloc(numLists * sizeof(Tcl_Obj **));
698    }
699    for (i = 0;  i < numLists;  i++) {
700        index[i] = 0;
701        varcList[i] = 0;
702        varvList[i] = (Tcl_Obj **) NULL;
703        argcList[i] = 0;
704        argvList[i] = (Tcl_Obj **) NULL;
705    }
706
707    /*
708     * Break up the value lists and variable lists into elements
709     * THIS FAILS IF THE OBJECT'S STRING REP HAS A NULL BYTE.
710     */
711
712    maxj = 0;
713    for (i = 0;  i < numLists;  i++) {
714        result = Tcl_ListObjGetElements(interp, argObjv[1+i*2],
715                &varcList[i], &varvList[i]);
716        if (result != TCL_OK) {
717            goto done;
718        }
719        if (varcList[i] < 1) {
720            Tcl_AppendToObj(Tcl_GetObjResult(interp),
721                    "foreach varlist is empty", -1);
722            result = TCL_ERROR;
723            goto done;
724        }
725       
726        result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
727                &argcList[i], &argvList[i]);
728        if (result != TCL_OK) {
729            goto done;
730        }
731       
732        j = argcList[i] / varcList[i];
733        if ((argcList[i] % varcList[i]) != 0) {
734            j++;
735        }
736        if (j > maxj) {
737            maxj = j;
738        }
739    }
740
741    /*
742     * Iterate maxj times through the lists in parallel
743     * If some value lists run out of values, set loop vars to ""
744     */
745   
746    bodyPtr = argObjv[objc-1];
747    for (j = 0;  j < maxj;  j++) {
748        for (i = 0;  i < numLists;  i++) {
749            /*
750             * If a variable or value list object has been converted to
751             * another kind of Tcl object, convert it back to a list object
752             * and refetch the pointer to its element array.
753             */
754
755            if (argObjv[1+i*2]->typePtr != &tclListType) {
756                result = Tcl_ListObjGetElements(interp, argObjv[1+i*2],
757                        &varcList[i], &varvList[i]);
758                if (result != TCL_OK) {
759                    panic("Tcl_ForeachObjCmd: could not reconvert variable list %d to a list object\n", i);
760                }
761            }
762            if (argObjv[2+i*2]->typePtr != &tclListType) {
763                result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
764                        &argcList[i], &argvList[i]);
765                if (result != TCL_OK) {
766                    panic("Tcl_ForeachObjCmd: could not reconvert value list %d to a list object\n", i);
767                }
768            }
769           
770            for (v = 0;  v < varcList[i];  v++) {
771                int k = index[i]++;
772                Tcl_Obj *valuePtr, *varValuePtr;
773                int isEmptyObj = 0;
774               
775                if (k < argcList[i]) {
776                    valuePtr = argvList[i][k];
777                } else {
778                    valuePtr = Tcl_NewObj(); /* empty string */
779                    isEmptyObj = 1;
780                }
781                varValuePtr = Tcl_ObjSetVar2(interp, varvList[i][v], NULL,
782                        valuePtr, TCL_PARSE_PART1);
783                if (varValuePtr == NULL) {
784                    if (isEmptyObj) {
785                        Tcl_DecrRefCount(valuePtr);
786                    }
787                    Tcl_ResetResult(interp);
788                    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
789                        "couldn't set loop variable: \"",
790                        Tcl_GetStringFromObj(varvList[i][v], (int *) NULL),
791                        "\"", (char *) NULL);
792                    result = TCL_ERROR;
793                    goto done;
794                }
795
796            }
797        }
798
799        result = Tcl_EvalObj(interp, bodyPtr);
800        if (result != TCL_OK) {
801            if (result == TCL_CONTINUE) {
802                result = TCL_OK;
803            } else if (result == TCL_BREAK) {
804                result = TCL_OK;
805                break;
806            } else if (result == TCL_ERROR) {
807                char msg[100];
808                sprintf(msg, "\n    (\"foreach\" body line %d)",
809                        interp->errorLine);
810                Tcl_AddObjErrorInfo(interp, msg, -1);
811                break;
812            } else {
813                break;
814            }
815        }
816    }
817    if (result == TCL_OK) {
818        Tcl_ResetResult(interp);
819    }
820
821    done:
822    if (numLists > STATIC_LIST_SIZE) {
823        ckfree((char *) index);
824        ckfree((char *) varcList);
825        ckfree((char *) argcList);
826        ckfree((char *) varvList);
827        ckfree((char *) argvList);
828    }
829    if (argObjv != argObjStorage) {
830        ckfree((char *) argObjv);
831    }
832    return result;
833#undef STATIC_LIST_SIZE
834#undef NUM_ARGS
835}
836
837/*
838 *----------------------------------------------------------------------
839 *
840 * Tcl_FormatObjCmd --
841 *
842 *      This procedure is invoked to process the "format" Tcl command.
843 *      See the user documentation for details on what it does.
844 *
845 * Results:
846 *      A standard Tcl result.
847 *
848 * Side effects:
849 *      See the user documentation.
850 *
851 *----------------------------------------------------------------------
852 */
853
854        /* ARGSUSED */
855int
856Tcl_FormatObjCmd(dummy, interp, objc, objv)
857    ClientData dummy;           /* Not used. */
858    Tcl_Interp *interp;         /* Current interpreter. */
859    int objc;                   /* Number of arguments. */
860    Tcl_Obj *CONST objv[];      /* Argument objects. */
861{
862    register char *format;      /* Used to read characters from the format
863                                 * string. */
864    int formatLen;              /* The length of the format string */
865    char *endPtr;               /* Points to the last char in format array */
866    char newFormat[40];         /* A new format specifier is generated here. */
867    int width;                  /* Field width from field specifier, or 0 if
868                                 * no width given. */
869    int precision;              /* Field precision from field specifier, or 0
870                                 * if no precision given. */
871    int size;                   /* Number of bytes needed for result of
872                                 * conversion, based on type of conversion
873                                 * ("e", "s", etc.), width, and precision. */
874    int intValue;               /* Used to hold value to pass to sprintf, if
875                                 * it's a one-word integer or char value */
876    char *ptrValue = NULL;      /* Used to hold value to pass to sprintf, if
877                                 * it's a one-word value. */
878    double doubleValue;         /* Used to hold value to pass to sprintf if
879                                 * it's a double value. */
880    int whichValue;             /* Indicates which of intValue, ptrValue,
881                                 * or doubleValue has the value to pass to
882                                 * sprintf, according to the following
883                                 * definitions: */
884#   define INT_VALUE 0
885#   define PTR_VALUE 1
886#   define DOUBLE_VALUE 2
887#   define MAX_FLOAT_SIZE 320
888   
889    Tcl_Obj *resultPtr;         /* Where result is stored finally. */
890    char staticBuf[MAX_FLOAT_SIZE + 1];
891                                /* A static buffer to copy the format results
892                                 * into */
893    char *dst = staticBuf;      /* The buffer that sprintf writes into each
894                                 * time the format processes a specifier */
895    int dstSize = MAX_FLOAT_SIZE;
896                                /* The size of the dst buffer */
897    int noPercent;              /* Special case for speed:  indicates there's
898                                 * no field specifier, just a string to copy.*/
899    int objIndex;               /* Index of argument to substitute next. */
900    int gotXpg = 0;             /* Non-zero means that an XPG3 %n$-style
901                                 * specifier has been seen. */
902    int gotSequential = 0;      /* Non-zero means that a regular sequential
903                                 * (non-XPG3) conversion specifier has been
904                                 * seen. */
905    int useShort;               /* Value to be printed is short (half word). */
906    char *end;                  /* Used to locate end of numerical fields. */
907
908    /*
909     * This procedure is a bit nasty.  The goal is to use sprintf to
910     * do most of the dirty work.  There are several problems:
911     * 1. this procedure can't trust its arguments.
912     * 2. we must be able to provide a large enough result area to hold
913     *    whatever's generated.  This is hard to estimate.
914     * 2. there's no way to move the arguments from objv to the call
915     *    to sprintf in a reasonable way.  This is particularly nasty
916     *    because some of the arguments may be two-word values (doubles).
917     * So, what happens here is to scan the format string one % group
918     * at a time, making many individual calls to sprintf.
919     */
920
921    if (objc < 2) {
922        Tcl_WrongNumArgs(interp, 1, objv,
923                "formatString ?arg arg ...?");
924        return TCL_ERROR;
925    }
926
927    format = Tcl_GetStringFromObj(objv[1], &formatLen);
928    endPtr = format + formatLen;
929    resultPtr = Tcl_NewObj();
930    objIndex = 2;
931
932    while (format < endPtr) {
933        register char *newPtr = newFormat;
934
935        width = precision = noPercent = useShort = 0;
936        whichValue = PTR_VALUE;
937
938        /*
939         * Get rid of any characters before the next field specifier.
940         */
941        if (*format != '%') {
942            ptrValue = format;
943            while ((*format != '%') && (format < endPtr)) {
944                format++;
945            }
946            size = format - ptrValue;
947            noPercent = 1;
948            goto doField;
949        }
950
951        if (format[1] == '%') {
952            ptrValue = format;
953            size = 1;
954            noPercent = 1;
955            format += 2;
956            goto doField;
957        }
958
959        /*
960         * Parse off a field specifier, compute how many characters
961         * will be needed to store the result, and substitute for
962         * "*" size specifiers.
963         */
964        *newPtr = '%';
965        newPtr++;
966        format++;
967        if (isdigit(UCHAR(*format))) {
968            int tmp;
969
970            /*
971             * Check for an XPG3-style %n$ specification.  Note: there
972             * must not be a mixture of XPG3 specs and non-XPG3 specs
973             * in the same format string.
974             */
975
976            tmp = strtoul(format, &end, 10);
977            if (*end != '$') {
978                goto notXpg;
979            }
980            format = end+1;
981            gotXpg = 1;
982            if (gotSequential) {
983                goto mixedXPG;
984            }
985            objIndex = tmp+1;
986            if ((objIndex < 2) || (objIndex >= objc)) {
987                goto badIndex;
988            }
989            goto xpgCheckDone;
990        }
991
992        notXpg:
993        gotSequential = 1;
994        if (gotXpg) {
995            goto mixedXPG;
996        }
997
998        xpgCheckDone:
999        while ((*format == '-') || (*format == '#') || (*format == '0')
1000                || (*format == ' ') || (*format == '+')) {
1001            *newPtr = *format;
1002            newPtr++;
1003            format++;
1004        }
1005        if (isdigit(UCHAR(*format))) {
1006            width = strtoul(format, &end, 10);
1007            format = end;
1008        } else if (*format == '*') {
1009            if (objIndex >= objc) {
1010                goto badIndex;
1011            }
1012            if (Tcl_GetIntFromObj(interp, objv[objIndex], 
1013                    &width) != TCL_OK) {
1014                goto fmtError;
1015            }
1016            objIndex++;
1017            format++;
1018        }
1019        if (width > 100000) {
1020            /*
1021             * Don't allow arbitrarily large widths:  could cause core
1022             * dump when we try to allocate a zillion bytes of memory
1023             * below.
1024             */
1025
1026            width = 100000;
1027        } else if (width < 0) {
1028            width = 0;
1029        }
1030        if (width != 0) {
1031            TclFormatInt(newPtr, width);
1032            while (*newPtr != 0) {
1033                newPtr++;
1034            }
1035        }
1036        if (*format == '.') {
1037            *newPtr = '.';
1038            newPtr++;
1039            format++;
1040        }
1041        if (isdigit(UCHAR(*format))) {
1042            precision = strtoul(format, &end, 10);
1043            format = end;
1044        } else if (*format == '*') {
1045            if (objIndex >= objc) {
1046                goto badIndex;
1047            }
1048            if (Tcl_GetIntFromObj(interp, objv[objIndex], 
1049                    &precision) != TCL_OK) {
1050                goto fmtError;
1051            }
1052            objIndex++;
1053            format++;
1054        }
1055        if (precision != 0) {
1056            TclFormatInt(newPtr, precision);
1057            while (*newPtr != 0) {
1058                newPtr++;
1059            }
1060        }
1061        if (*format == 'l') {
1062            format++;
1063        } else if (*format == 'h') {
1064            useShort = 1;
1065            *newPtr = 'h';
1066            newPtr++;
1067            format++;
1068        }
1069        *newPtr = *format;
1070        newPtr++;
1071        *newPtr = 0;
1072        if (objIndex >= objc) {
1073            goto badIndex;
1074        }
1075        switch (*format) {
1076            case 'i':
1077                newPtr[-1] = 'd';
1078            case 'd':
1079            case 'o':
1080            case 'u':
1081            case 'x':
1082            case 'X':
1083                if (Tcl_GetIntFromObj(interp, objv[objIndex], 
1084                        (int *) &intValue) != TCL_OK) {
1085                    goto fmtError;
1086                }
1087                whichValue = INT_VALUE;
1088                size = 40 + precision;
1089                break;
1090            case 's':
1091                ptrValue = Tcl_GetStringFromObj(objv[objIndex], &size);
1092                break;
1093            case 'c':
1094                if (Tcl_GetIntFromObj(interp, objv[objIndex], 
1095                        (int *) &intValue) != TCL_OK) {
1096                    goto fmtError;
1097                }
1098                whichValue = INT_VALUE;
1099                size = 1;
1100                break;
1101            case 'e':
1102            case 'E':
1103            case 'f':
1104            case 'g':
1105            case 'G':
1106                if (Tcl_GetDoubleFromObj(interp, objv[objIndex], 
1107                        &doubleValue) != TCL_OK) {
1108                    goto fmtError;
1109                }
1110                whichValue = DOUBLE_VALUE;
1111                size = MAX_FLOAT_SIZE;
1112                if (precision > 10) {
1113                    size += precision;
1114                }
1115                break;
1116            case 0:
1117                Tcl_SetResult(interp,
1118                        "format string ended in middle of field specifier",
1119                        TCL_STATIC);
1120                goto fmtError;
1121            default:
1122                {
1123                    char buf[40];
1124                    sprintf(buf, "bad field specifier \"%c\"", *format);
1125                    Tcl_SetResult(interp, buf, TCL_VOLATILE);
1126                    goto fmtError;
1127                }
1128        }
1129        objIndex++;
1130        format++;
1131
1132        /*
1133         * Make sure that there's enough space to hold the formatted
1134         * result, then format it.
1135         */
1136
1137        doField:
1138        if (width > size) {
1139            size = width;
1140        }
1141        if (noPercent) {
1142            Tcl_AppendToObj(resultPtr, ptrValue, size);
1143        } else {
1144            if (size > dstSize) {
1145                if (dst != staticBuf) {
1146                    ckfree(dst);
1147                }
1148                dst = (char *) ckalloc((unsigned) (size + 1));
1149                dstSize = size;
1150            }
1151
1152            if (whichValue == DOUBLE_VALUE) {
1153                sprintf(dst, newFormat, doubleValue);
1154            } else if (whichValue == INT_VALUE) {
1155                if (useShort) {
1156                    sprintf(dst, newFormat, (short) intValue);
1157                } else {
1158                    sprintf(dst, newFormat, intValue);
1159                }
1160            } else {
1161                sprintf(dst, newFormat, ptrValue);
1162            }
1163            Tcl_AppendToObj(resultPtr, dst, -1);
1164        }
1165    }
1166
1167    Tcl_SetObjResult(interp, resultPtr);
1168    if(dst != staticBuf) {
1169        ckfree(dst);
1170    }
1171    return TCL_OK;
1172
1173    mixedXPG:
1174    Tcl_SetResult(interp, 
1175            "cannot mix \"%\" and \"%n$\" conversion specifiers", TCL_STATIC);
1176    goto fmtError;
1177
1178    badIndex:
1179    if (gotXpg) {
1180        Tcl_SetResult(interp, 
1181                "\"%n$\" argument index out of range", TCL_STATIC);
1182    } else {
1183        Tcl_SetResult(interp, 
1184                "not enough arguments for all format specifiers", TCL_STATIC);
1185    }
1186
1187    fmtError:
1188    if(dst != staticBuf) {
1189        ckfree(dst);
1190    }
1191    Tcl_DecrRefCount(resultPtr);
1192    return TCL_ERROR;
1193}
Note: See TracBrowser for help on using the repository browser.