tclUtil.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:67k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclUtil.c --
  3.  *
  4.  * This file contains utility procedures that are used by many Tcl
  5.  * commands.
  6.  *
  7.  * Copyright (c) 1987-1993 The Regents of the University of California.
  8.  * Copyright (c) 1994-1998 Sun Microsystems, Inc.
  9.  * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
  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: tclUtil.c,v 1.36.2.8 2007/05/10 18:23:58 dgp Exp $
  15.  */
  16. #include "tclInt.h"
  17. #include "tclPort.h"
  18. /*
  19.  * The following variable holds the full path name of the binary
  20.  * from which this application was executed, or NULL if it isn't
  21.  * know.  The value of the variable is set by the procedure
  22.  * Tcl_FindExecutable.  The storage space is dynamically allocated.
  23.  */
  24. char *tclExecutableName = NULL;
  25. char *tclNativeExecutableName = NULL;
  26. /*
  27.  * The following values are used in the flags returned by Tcl_ScanElement
  28.  * and used by Tcl_ConvertElement.  The value TCL_DONT_USE_BRACES is also
  29.  * defined in tcl.h;  make sure its value doesn't overlap with any of the
  30.  * values below.
  31.  *
  32.  * TCL_DONT_USE_BRACES - 1 means the string mustn't be enclosed in
  33.  * braces (e.g. it contains unmatched braces,
  34.  * or ends in a backslash character, or user
  35.  * just doesn't want braces);  handle all
  36.  * special characters by adding backslashes.
  37.  * USE_BRACES - 1 means the string contains a special
  38.  * character that can be handled simply by
  39.  * enclosing the entire argument in braces.
  40.  * BRACES_UNMATCHED - 1 means that braces aren't properly matched
  41.  * in the argument.
  42.  */
  43. #define USE_BRACES 2
  44. #define BRACES_UNMATCHED 4
  45. /*
  46.  * The following values determine the precision used when converting
  47.  * floating-point values to strings.  This information is linked to all
  48.  * of the tcl_precision variables in all interpreters via the procedure
  49.  * TclPrecTraceProc.
  50.  */
  51. static char precisionString[10] = "12";
  52. /* The string value of all the tcl_precision
  53.  * variables. */
  54. static char precisionFormat[10] = "%.12g";
  55. /* The format string actually used in calls
  56.  * to sprintf. */
  57. TCL_DECLARE_MUTEX(precisionMutex)
  58. /*
  59.  * Prototypes for procedures defined later in this file.
  60.  */
  61. static void UpdateStringOfEndOffset _ANSI_ARGS_((Tcl_Obj* objPtr));
  62. static int SetEndOffsetFromAny _ANSI_ARGS_((Tcl_Interp* interp,
  63.     Tcl_Obj* objPtr));
  64. /*
  65.  * The following is the Tcl object type definition for an object
  66.  * that represents a list index in the form, "end-offset".  It is
  67.  * used as a performance optimization in TclGetIntForIndex.  The
  68.  * internal rep is an integer, so no memory management is required
  69.  * for it.
  70.  */
  71. Tcl_ObjType tclEndOffsetType = {
  72.     "end-offset", /* name */
  73.     (Tcl_FreeInternalRepProc*) NULL,    /* freeIntRepProc */
  74.     (Tcl_DupInternalRepProc*) NULL,     /* dupIntRepProc */
  75.     UpdateStringOfEndOffset, /* updateStringProc */
  76.     SetEndOffsetFromAny    
  77. };
  78. /*
  79.  *----------------------------------------------------------------------
  80.  *
  81.  * TclFindElement --
  82.  *
  83.  * Given a pointer into a Tcl list, locate the first (or next)
  84.  * element in the list.
  85.  *
  86.  * Results:
  87.  * The return value is normally TCL_OK, which means that the
  88.  * element was successfully located.  If TCL_ERROR is returned
  89.  * it means that list didn't have proper list structure;
  90.  * the interp's result contains a more detailed error message.
  91.  *
  92.  * If TCL_OK is returned, then *elementPtr will be set to point to the
  93.  * first element of list, and *nextPtr will be set to point to the
  94.  * character just after any white space following the last character
  95.  * that's part of the element. If this is the last argument in the
  96.  * list, then *nextPtr will point just after the last character in the
  97.  * list (i.e., at the character at list+listLength). If sizePtr is
  98.  * non-NULL, *sizePtr is filled in with the number of characters in the
  99.  * element.  If the element is in braces, then *elementPtr will point
  100.  * to the character after the opening brace and *sizePtr will not
  101.  * include either of the braces. If there isn't an element in the list,
  102.  * *sizePtr will be zero, and both *elementPtr and *termPtr will point
  103.  * just after the last character in the list. Note: this procedure does
  104.  * NOT collapse backslash sequences.
  105.  *
  106.  * Side effects:
  107.  * None.
  108.  *
  109.  *----------------------------------------------------------------------
  110.  */
  111. int
  112. TclFindElement(interp, list, listLength, elementPtr, nextPtr, sizePtr,
  113.        bracePtr)
  114.     Tcl_Interp *interp; /* Interpreter to use for error reporting. 
  115.  * If NULL, then no error message is left
  116.  * after errors. */
  117.     CONST char *list; /* Points to the first byte of a string
  118.  * containing a Tcl list with zero or more
  119.  * elements (possibly in braces). */
  120.     int listLength; /* Number of bytes in the list's string. */
  121.     CONST char **elementPtr; /* Where to put address of first significant
  122.  * character in first element of list. */
  123.     CONST char **nextPtr; /* Fill in with location of character just
  124.  * after all white space following end of
  125.  * argument (next arg or end of list). */
  126.     int *sizePtr; /* If non-zero, fill in with size of
  127.  * element. */
  128.     int *bracePtr; /* If non-zero, fill in with non-zero/zero
  129.  * to indicate that arg was/wasn't
  130.  * in braces. */
  131. {
  132.     CONST char *p = list;
  133.     CONST char *elemStart; /* Points to first byte of first element. */
  134.     CONST char *limit; /* Points just after list's last byte. */
  135.     int openBraces = 0; /* Brace nesting level during parse. */
  136.     int inQuotes = 0;
  137.     int size = 0; /* lint. */
  138.     int numChars;
  139.     CONST char *p2;
  140.     
  141.     /*
  142.      * Skim off leading white space and check for an opening brace or
  143.      * quote. We treat embedded NULLs in the list as bytes belonging to
  144.      * a list element.
  145.      */
  146.     limit = (list + listLength);
  147.     while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
  148. p++;
  149.     }
  150.     if (p == limit) { /* no element found */
  151. elemStart = limit;
  152. goto done;
  153.     }
  154.     if (*p == '{') {
  155. openBraces = 1;
  156. p++;
  157.     } else if (*p == '"') {
  158. inQuotes = 1;
  159. p++;
  160.     }
  161.     elemStart = p;
  162.     if (bracePtr != 0) {
  163. *bracePtr = openBraces;
  164.     }
  165.     /*
  166.      * Find element's end (a space, close brace, or the end of the string).
  167.      */
  168.     while (p < limit) {
  169. switch (*p) {
  170.     /*
  171.      * Open brace: don't treat specially unless the element is in
  172.      * braces. In this case, keep a nesting count.
  173.      */
  174.     case '{':
  175. if (openBraces != 0) {
  176.     openBraces++;
  177. }
  178. break;
  179.     /*
  180.      * Close brace: if element is in braces, keep nesting count and
  181.      * quit when the last close brace is seen.
  182.      */
  183.     case '}':
  184. if (openBraces > 1) {
  185.     openBraces--;
  186. } else if (openBraces == 1) {
  187.     size = (p - elemStart);
  188.     p++;
  189.     if ((p >= limit)
  190.     || isspace(UCHAR(*p))) { /* INTL: ISO space. */
  191. goto done;
  192.     }
  193.     /*
  194.      * Garbage after the closing brace; return an error.
  195.      */
  196.     
  197.     if (interp != NULL) {
  198. char buf[100];
  199. p2 = p;
  200. while ((p2 < limit)
  201. && (!isspace(UCHAR(*p2))) /* INTL: ISO space. */
  202.         && (p2 < p+20)) {
  203.     p2++;
  204. }
  205. sprintf(buf,
  206. "list element in braces followed by "%.*s" instead of space",
  207. (int) (p2-p), p);
  208. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  209.     }
  210.     return TCL_ERROR;
  211. }
  212. break;
  213.     /*
  214.      * Backslash:  skip over everything up to the end of the
  215.      * backslash sequence.
  216.      */
  217.     case '\': {
  218. Tcl_UtfBackslash(p, &numChars, NULL);
  219. p += (numChars - 1);
  220. break;
  221.     }
  222.     /*
  223.      * Space: ignore if element is in braces or quotes; otherwise
  224.      * terminate element.
  225.      */
  226.     case ' ':
  227.     case 'f':
  228.     case 'n':
  229.     case 'r':
  230.     case 't':
  231.     case 'v':
  232. if ((openBraces == 0) && !inQuotes) {
  233.     size = (p - elemStart);
  234.     goto done;
  235. }
  236. break;
  237.     /*
  238.      * Double-quote: if element is in quotes then terminate it.
  239.      */
  240.     case '"':
  241. if (inQuotes) {
  242.     size = (p - elemStart);
  243.     p++;
  244.     if ((p >= limit)
  245.     || isspace(UCHAR(*p))) { /* INTL: ISO space */
  246. goto done;
  247.     }
  248.     /*
  249.      * Garbage after the closing quote; return an error.
  250.      */
  251.     
  252.     if (interp != NULL) {
  253. char buf[100];
  254. p2 = p;
  255. while ((p2 < limit)
  256. && (!isspace(UCHAR(*p2))) /* INTL: ISO space */
  257.  && (p2 < p+20)) {
  258.     p2++;
  259. }
  260. sprintf(buf,
  261. "list element in quotes followed by "%.*s" %s",
  262. (int) (p2-p), p, "instead of space");
  263. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  264.     }
  265.     return TCL_ERROR;
  266. }
  267. break;
  268. }
  269. p++;
  270.     }
  271.     /*
  272.      * End of list: terminate element.
  273.      */
  274.     if (p == limit) {
  275. if (openBraces != 0) {
  276.     if (interp != NULL) {
  277. Tcl_SetResult(interp, "unmatched open brace in list",
  278. TCL_STATIC);
  279.     }
  280.     return TCL_ERROR;
  281. } else if (inQuotes) {
  282.     if (interp != NULL) {
  283. Tcl_SetResult(interp, "unmatched open quote in list",
  284. TCL_STATIC);
  285.     }
  286.     return TCL_ERROR;
  287. }
  288. size = (p - elemStart);
  289.     }
  290.     done:
  291.     while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
  292. p++;
  293.     }
  294.     *elementPtr = elemStart;
  295.     *nextPtr = p;
  296.     if (sizePtr != 0) {
  297. *sizePtr = size;
  298.     }
  299.     return TCL_OK;
  300. }
  301. /*
  302.  *----------------------------------------------------------------------
  303.  *
  304.  * TclCopyAndCollapse --
  305.  *
  306.  * Copy a string and eliminate any backslashes that aren't in braces.
  307.  *
  308.  * Results:
  309.  * Count characters get copied from src to dst. Along the way, if
  310.  * backslash sequences are found outside braces, the backslashes are
  311.  * eliminated in the copy. After scanning count chars from source, a
  312.  * null character is placed at the end of dst.  Returns the number
  313.  * of characters that got copied.
  314.  *
  315.  * Side effects:
  316.  * None.
  317.  *
  318.  *----------------------------------------------------------------------
  319.  */
  320. int
  321. TclCopyAndCollapse(count, src, dst)
  322.     int count; /* Number of characters to copy from src. */
  323.     CONST char *src; /* Copy from here... */
  324.     char *dst; /* ... to here. */
  325. {
  326.     register char c;
  327.     int numRead;
  328.     int newCount = 0;
  329.     int backslashCount;
  330.     for (c = *src;  count > 0;  src++, c = *src, count--) {
  331. if (c == '\') {
  332.     backslashCount = Tcl_UtfBackslash(src, &numRead, dst);
  333.     dst += backslashCount;
  334.     newCount += backslashCount;
  335.     src += numRead-1;
  336.     count -= numRead-1;
  337. } else {
  338.     *dst = c;
  339.     dst++;
  340.     newCount++;
  341. }
  342.     }
  343.     *dst = 0;
  344.     return newCount;
  345. }
  346. /*
  347.  *----------------------------------------------------------------------
  348.  *
  349.  * Tcl_SplitList --
  350.  *
  351.  * Splits a list up into its constituent fields.
  352.  *
  353.  * Results
  354.  * The return value is normally TCL_OK, which means that
  355.  * the list was successfully split up.  If TCL_ERROR is
  356.  * returned, it means that "list" didn't have proper list
  357.  * structure;  the interp's result will contain a more detailed
  358.  * error message.
  359.  *
  360.  * *argvPtr will be filled in with the address of an array
  361.  * whose elements point to the elements of list, in order.
  362.  * *argcPtr will get filled in with the number of valid elements
  363.  * in the array.  A single block of memory is dynamically allocated
  364.  * to hold both the argv array and a copy of the list (with
  365.  * backslashes and braces removed in the standard way).
  366.  * The caller must eventually free this memory by calling free()
  367.  * on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
  368.  * if the procedure returns normally.
  369.  *
  370.  * Side effects:
  371.  * Memory is allocated.
  372.  *
  373.  *----------------------------------------------------------------------
  374.  */
  375. int
  376. Tcl_SplitList(interp, list, argcPtr, argvPtr)
  377.     Tcl_Interp *interp; /* Interpreter to use for error reporting. 
  378.  * If NULL, no error message is left. */
  379.     CONST char *list; /* Pointer to string with list structure. */
  380.     int *argcPtr; /* Pointer to location to fill in with
  381.  * the number of elements in the list. */
  382.     CONST char ***argvPtr; /* Pointer to place to store pointer to
  383.  * array of pointers to list elements. */
  384. {
  385.     CONST char **argv;
  386.     CONST char *l;
  387.     char *p;
  388.     int length, size, i, result, elSize, brace;
  389.     CONST char *element;
  390.     /*
  391.      * Figure out how much space to allocate.  There must be enough
  392.      * space for both the array of pointers and also for a copy of
  393.      * the list.  To estimate the number of pointers needed, count
  394.      * the number of space characters in the list.
  395.      */
  396.     for (size = 2, l = list; *l != 0; l++) {
  397. if (isspace(UCHAR(*l))) { /* INTL: ISO space. */
  398.     size++;
  399.     /* Consecutive space can only count as a single list delimiter */
  400.     while (1) {
  401. char next = *(l + 1);
  402. if (next == '') {
  403.     break;
  404. }
  405. ++l;
  406. if (isspace(UCHAR(next))) {
  407.     continue;
  408. }
  409. break;
  410.     }
  411. }
  412.     }
  413.     length = l - list;
  414.     argv = (CONST char **) ckalloc((unsigned)
  415.     ((size * sizeof(char *)) + length + 1));
  416.     for (i = 0, p = ((char *) argv) + size*sizeof(char *);
  417.     *list != 0;  i++) {
  418. CONST char *prevList = list;
  419. result = TclFindElement(interp, list, length, &element,
  420. &list, &elSize, &brace);
  421. length -= (list - prevList);
  422. if (result != TCL_OK) {
  423.     ckfree((char *) argv);
  424.     return result;
  425. }
  426. if (*element == 0) {
  427.     break;
  428. }
  429. if (i >= size) {
  430.     ckfree((char *) argv);
  431.     if (interp != NULL) {
  432. Tcl_SetResult(interp, "internal error in Tcl_SplitList",
  433. TCL_STATIC);
  434.     }
  435.     return TCL_ERROR;
  436. }
  437. argv[i] = p;
  438. if (brace) {
  439.     memcpy((VOID *) p, (VOID *) element, (size_t) elSize);
  440.     p += elSize;
  441.     *p = 0;
  442.     p++;
  443. } else {
  444.     TclCopyAndCollapse(elSize, element, p);
  445.     p += elSize+1;
  446. }
  447.     }
  448.     argv[i] = NULL;
  449.     *argvPtr = argv;
  450.     *argcPtr = i;
  451.     return TCL_OK;
  452. }
  453. /*
  454.  *----------------------------------------------------------------------
  455.  *
  456.  * Tcl_ScanElement --
  457.  *
  458.  * This procedure is a companion procedure to Tcl_ConvertElement.
  459.  * It scans a string to see what needs to be done to it (e.g. add
  460.  * backslashes or enclosing braces) to make the string into a
  461.  * valid Tcl list element.
  462.  *
  463.  * Results:
  464.  * The return value is an overestimate of the number of characters
  465.  * that will be needed by Tcl_ConvertElement to produce a valid
  466.  * list element from string.  The word at *flagPtr is filled in
  467.  * with a value needed by Tcl_ConvertElement when doing the actual
  468.  * conversion.
  469.  *
  470.  * Side effects:
  471.  * None.
  472.  *
  473.  *----------------------------------------------------------------------
  474.  */
  475. int
  476. Tcl_ScanElement(string, flagPtr)
  477.     register CONST char *string; /* String to convert to list element. */
  478.     register int *flagPtr;  /* Where to store information to guide
  479.   * Tcl_ConvertCountedElement. */
  480. {
  481.     return Tcl_ScanCountedElement(string, -1, flagPtr);
  482. }
  483. /*
  484.  *----------------------------------------------------------------------
  485.  *
  486.  * Tcl_ScanCountedElement --
  487.  *
  488.  * This procedure is a companion procedure to
  489.  * Tcl_ConvertCountedElement.  It scans a string to see what
  490.  * needs to be done to it (e.g. add backslashes or enclosing
  491.  * braces) to make the string into a valid Tcl list element.
  492.  * If length is -1, then the string is scanned up to the first
  493.  * null byte.
  494.  *
  495.  * Results:
  496.  * The return value is an overestimate of the number of characters
  497.  * that will be needed by Tcl_ConvertCountedElement to produce a
  498.  * valid list element from string.  The word at *flagPtr is
  499.  * filled in with a value needed by Tcl_ConvertCountedElement
  500.  * when doing the actual conversion.
  501.  *
  502.  * Side effects:
  503.  * None.
  504.  *
  505.  *----------------------------------------------------------------------
  506.  */
  507. int
  508. Tcl_ScanCountedElement(string, length, flagPtr)
  509.     CONST char *string; /* String to convert to Tcl list element. */
  510.     int length; /* Number of bytes in string, or -1. */
  511.     int *flagPtr; /* Where to store information to guide
  512.  * Tcl_ConvertElement. */
  513. {
  514.     int flags, nestingLevel;
  515.     register CONST char *p, *lastChar;
  516.     /*
  517.      * This procedure and Tcl_ConvertElement together do two things:
  518.      *
  519.      * 1. They produce a proper list, one that will yield back the
  520.      * argument strings when evaluated or when disassembled with
  521.      * Tcl_SplitList.  This is the most important thing.
  522.      * 
  523.      * 2. They try to produce legible output, which means minimizing the
  524.      * use of backslashes (using braces instead).  However, there are
  525.      * some situations where backslashes must be used (e.g. an element
  526.      * like "{abc": the leading brace will have to be backslashed.
  527.      * For each element, one of three things must be done:
  528.      *
  529.      * (a) Use the element as-is (it doesn't contain any special
  530.      * characters).  This is the most desirable option.
  531.      *
  532.      * (b) Enclose the element in braces, but leave the contents alone.
  533.      * This happens if the element contains embedded space, or if it
  534.      * contains characters with special interpretation ($, [, ;, or ),
  535.      * or if it starts with a brace or double-quote, or if there are
  536.      * no characters in the element.
  537.      *
  538.      * (c) Don't enclose the element in braces, but add backslashes to
  539.      * prevent special interpretation of special characters.  This is a
  540.      * last resort used when the argument would normally fall under case
  541.      * (b) but contains unmatched braces.  It also occurs if the last
  542.      * character of the argument is a backslash or if the element contains
  543.      * a backslash followed by newline.
  544.      *
  545.      * The procedure figures out how many bytes will be needed to store
  546.      * the result (actually, it overestimates). It also collects information
  547.      * about the element in the form of a flags word.
  548.      *
  549.      * Note: list elements produced by this procedure and
  550.      * Tcl_ConvertCountedElement must have the property that they can be
  551.      * enclosing in curly braces to make sub-lists.  This means, for
  552.      * example, that we must not leave unmatched curly braces in the
  553.      * resulting list element.  This property is necessary in order for
  554.      * procedures like Tcl_DStringStartSublist to work.
  555.      */
  556.     nestingLevel = 0;
  557.     flags = 0;
  558.     if (string == NULL) {
  559. string = "";
  560.     }
  561.     if (length == -1) {
  562. length = strlen(string);
  563.     }
  564.     lastChar = string + length;
  565.     p = string;
  566.     if ((p == lastChar) || (*p == '{') || (*p == '"')) {
  567. flags |= USE_BRACES;
  568.     }
  569.     for ( ; p < lastChar; p++) {
  570. switch (*p) {
  571.     case '{':
  572. nestingLevel++;
  573. break;
  574.     case '}':
  575. nestingLevel--;
  576. if (nestingLevel < 0) {
  577.     flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;
  578. }
  579. break;
  580.     case '[':
  581.     case '$':
  582.     case ';':
  583.     case ' ':
  584.     case 'f':
  585.     case 'n':
  586.     case 'r':
  587.     case 't':
  588.     case 'v':
  589. flags |= USE_BRACES;
  590. break;
  591.     case '\':
  592. if ((p+1 == lastChar) || (p[1] == 'n')) {
  593.     flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
  594. } else {
  595.     int size;
  596.     Tcl_UtfBackslash(p, &size, NULL);
  597.     p += size-1;
  598.     flags |= USE_BRACES;
  599. }
  600. break;
  601. }
  602.     }
  603.     if (nestingLevel != 0) {
  604. flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
  605.     }
  606.     *flagPtr = flags;
  607.     /*
  608.      * Allow enough space to backslash every character plus leave
  609.      * two spaces for braces.
  610.      */
  611.     return 2*(p-string) + 2;
  612. }
  613. /*
  614.  *----------------------------------------------------------------------
  615.  *
  616.  * Tcl_ConvertElement --
  617.  *
  618.  * This is a companion procedure to Tcl_ScanElement.  Given
  619.  * the information produced by Tcl_ScanElement, this procedure
  620.  * converts a string to a list element equal to that string.
  621.  *
  622.  * Results:
  623.  * Information is copied to *dst in the form of a list element
  624.  * identical to src (i.e. if Tcl_SplitList is applied to dst it
  625.  * will produce a string identical to src).  The return value is
  626.  * a count of the number of characters copied (not including the
  627.  * terminating NULL character).
  628.  *
  629.  * Side effects:
  630.  * None.
  631.  *
  632.  *----------------------------------------------------------------------
  633.  */
  634. int
  635. Tcl_ConvertElement(src, dst, flags)
  636.     register CONST char *src; /* Source information for list element. */
  637.     register char *dst; /* Place to put list-ified element. */
  638.     register int flags; /* Flags produced by Tcl_ScanElement. */
  639. {
  640.     return Tcl_ConvertCountedElement(src, -1, dst, flags);
  641. }
  642. /*
  643.  *----------------------------------------------------------------------
  644.  *
  645.  * Tcl_ConvertCountedElement --
  646.  *
  647.  * This is a companion procedure to Tcl_ScanCountedElement.  Given
  648.  * the information produced by Tcl_ScanCountedElement, this
  649.  * procedure converts a string to a list element equal to that
  650.  * string.
  651.  *
  652.  * Results:
  653.  * Information is copied to *dst in the form of a list element
  654.  * identical to src (i.e. if Tcl_SplitList is applied to dst it
  655.  * will produce a string identical to src).  The return value is
  656.  * a count of the number of characters copied (not including the
  657.  * terminating NULL character).
  658.  *
  659.  * Side effects:
  660.  * None.
  661.  *
  662.  *----------------------------------------------------------------------
  663.  */
  664. int
  665. Tcl_ConvertCountedElement(src, length, dst, flags)
  666.     register CONST char *src; /* Source information for list element. */
  667.     int length; /* Number of bytes in src, or -1. */
  668.     char *dst; /* Place to put list-ified element. */
  669.     int flags; /* Flags produced by Tcl_ScanElement. */
  670. {
  671.     register char *p = dst;
  672.     register CONST char *lastChar;
  673.     /*
  674.      * See the comment block at the beginning of the Tcl_ScanElement
  675.      * code for details of how this works.
  676.      */
  677.     if (src && length == -1) {
  678. length = strlen(src);
  679.     }
  680.     if ((src == NULL) || (length == 0)) {
  681. p[0] = '{';
  682. p[1] = '}';
  683. p[2] = 0;
  684. return 2;
  685.     }
  686.     lastChar = src + length;
  687.     if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
  688. *p = '{';
  689. p++;
  690. for ( ; src != lastChar; src++, p++) {
  691.     *p = *src;
  692. }
  693. *p = '}';
  694. p++;
  695.     } else {
  696. if (*src == '{') {
  697.     /*
  698.      * Can't have a leading brace unless the whole element is
  699.      * enclosed in braces.  Add a backslash before the brace.
  700.      * Furthermore, this may destroy the balance between open
  701.      * and close braces, so set BRACES_UNMATCHED.
  702.      */
  703.     p[0] = '\';
  704.     p[1] = '{';
  705.     p += 2;
  706.     src++;
  707.     flags |= BRACES_UNMATCHED;
  708. }
  709. for (; src != lastChar; src++) {
  710.     switch (*src) {
  711. case ']':
  712. case '[':
  713. case '$':
  714. case ';':
  715. case ' ':
  716. case '\':
  717. case '"':
  718.     *p = '\';
  719.     p++;
  720.     break;
  721. case '{':
  722. case '}':
  723.     /*
  724.      * It may not seem necessary to backslash braces, but
  725.      * it is.  The reason for this is that the resulting
  726.      * list element may actually be an element of a sub-list
  727.      * enclosed in braces (e.g. if Tcl_DStringStartSublist
  728.      * has been invoked), so there may be a brace mismatch
  729.      * if the braces aren't backslashed.
  730.      */
  731.     if (flags & BRACES_UNMATCHED) {
  732. *p = '\';
  733. p++;
  734.     }
  735.     break;
  736. case 'f':
  737.     *p = '\';
  738.     p++;
  739.     *p = 'f';
  740.     p++;
  741.     continue;
  742. case 'n':
  743.     *p = '\';
  744.     p++;
  745.     *p = 'n';
  746.     p++;
  747.     continue;
  748. case 'r':
  749.     *p = '\';
  750.     p++;
  751.     *p = 'r';
  752.     p++;
  753.     continue;
  754. case 't':
  755.     *p = '\';
  756.     p++;
  757.     *p = 't';
  758.     p++;
  759.     continue;
  760. case 'v':
  761.     *p = '\';
  762.     p++;
  763.     *p = 'v';
  764.     p++;
  765.     continue;
  766.     }
  767.     *p = *src;
  768.     p++;
  769. }
  770.     }
  771.     *p = '';
  772.     return p-dst;
  773. }
  774. /*
  775.  *----------------------------------------------------------------------
  776.  *
  777.  * Tcl_Merge --
  778.  *
  779.  * Given a collection of strings, merge them together into a
  780.  * single string that has proper Tcl list structured (i.e.
  781.  * Tcl_SplitList may be used to retrieve strings equal to the
  782.  * original elements, and Tcl_Eval will parse the string back
  783.  * into its original elements).
  784.  *
  785.  * Results:
  786.  * The return value is the address of a dynamically-allocated
  787.  * string containing the merged list.
  788.  *
  789.  * Side effects:
  790.  * None.
  791.  *
  792.  *----------------------------------------------------------------------
  793.  */
  794. char *
  795. Tcl_Merge(argc, argv)
  796.     int argc; /* How many strings to merge. */
  797.     CONST char * CONST *argv; /* Array of string values. */
  798. {
  799. #   define LOCAL_SIZE 20
  800.     int localFlags[LOCAL_SIZE], *flagPtr;
  801.     int numChars;
  802.     char *result;
  803.     char *dst;
  804.     int i;
  805.     /*
  806.      * Pass 1: estimate space, gather flags.
  807.      */
  808.     if (argc <= LOCAL_SIZE) {
  809. flagPtr = localFlags;
  810.     } else {
  811. flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
  812.     }
  813.     numChars = 1;
  814.     for (i = 0; i < argc; i++) {
  815. numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
  816.     }
  817.     /*
  818.      * Pass two: copy into the result area.
  819.      */
  820.     result = (char *) ckalloc((unsigned) numChars);
  821.     dst = result;
  822.     for (i = 0; i < argc; i++) {
  823. numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
  824. dst += numChars;
  825. *dst = ' ';
  826. dst++;
  827.     }
  828.     if (dst == result) {
  829. *dst = 0;
  830.     } else {
  831. dst[-1] = 0;
  832.     }
  833.     if (flagPtr != localFlags) {
  834. ckfree((char *) flagPtr);
  835.     }
  836.     return result;
  837. }
  838. /*
  839.  *----------------------------------------------------------------------
  840.  *
  841.  * Tcl_Backslash --
  842.  *
  843.  * Figure out how to handle a backslash sequence.
  844.  *
  845.  * Results:
  846.  * The return value is the character that should be substituted
  847.  * in place of the backslash sequence that starts at src.  If
  848.  * readPtr isn't NULL then it is filled in with a count of the
  849.  * number of characters in the backslash sequence.
  850.  *
  851.  * Side effects:
  852.  * None.
  853.  *
  854.  *----------------------------------------------------------------------
  855.  */
  856. char
  857. Tcl_Backslash(src, readPtr)
  858.     CONST char *src; /* Points to the backslash character of
  859.  * a backslash sequence. */
  860.     int *readPtr; /* Fill in with number of characters read
  861.  * from src, unless NULL. */
  862. {
  863.     char buf[TCL_UTF_MAX];
  864.     Tcl_UniChar ch;
  865.     Tcl_UtfBackslash(src, readPtr, buf);
  866.     TclUtfToUniChar(buf, &ch);
  867.     return (char) ch;
  868. }
  869. /*
  870.  *----------------------------------------------------------------------
  871.  *
  872.  * Tcl_Concat --
  873.  *
  874.  * Concatenate a set of strings into a single large string.
  875.  *
  876.  * Results:
  877.  * The return value is dynamically-allocated string containing
  878.  * a concatenation of all the strings in argv, with spaces between
  879.  * the original argv elements.
  880.  *
  881.  * Side effects:
  882.  * Memory is allocated for the result;  the caller is responsible
  883.  * for freeing the memory.
  884.  *
  885.  *----------------------------------------------------------------------
  886.  */
  887. char *
  888. Tcl_Concat(argc, argv)
  889.     int argc; /* Number of strings to concatenate. */
  890.     CONST char * CONST *argv; /* Array of strings to concatenate. */
  891. {
  892.     int totalSize, i;
  893.     char *p;
  894.     char *result;
  895.     for (totalSize = 1, i = 0; i < argc; i++) {
  896. totalSize += strlen(argv[i]) + 1;
  897.     }
  898.     result = (char *) ckalloc((unsigned) totalSize);
  899.     if (argc == 0) {
  900. *result = '';
  901. return result;
  902.     }
  903.     for (p = result, i = 0; i < argc; i++) {
  904. CONST char *element;
  905. int length;
  906. /*
  907.  * Clip white space off the front and back of the string
  908.  * to generate a neater result, and ignore any empty
  909.  * elements.
  910.  */
  911. element = argv[i];
  912. while (isspace(UCHAR(*element))) { /* INTL: ISO space. */
  913.     element++;
  914. }
  915. for (length = strlen(element);
  916. (length > 0)
  917. && (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */
  918. && ((length < 2) || (element[length-2] != '\'));
  919.         length--) {
  920.     /* Null loop body. */
  921. }
  922. if (length == 0) {
  923.     continue;
  924. }
  925. memcpy((VOID *) p, (VOID *) element, (size_t) length);
  926. p += length;
  927. *p = ' ';
  928. p++;
  929.     }
  930.     if (p != result) {
  931. p[-1] = 0;
  932.     } else {
  933. *p = 0;
  934.     }
  935.     return result;
  936. }
  937. /*
  938.  *----------------------------------------------------------------------
  939.  *
  940.  * Tcl_ConcatObj --
  941.  *
  942.  * Concatenate the strings from a set of objects into a single string
  943.  * object with spaces between the original strings.
  944.  *
  945.  * Results:
  946.  * The return value is a new string object containing a concatenation
  947.  * of the strings in objv. Its ref count is zero.
  948.  *
  949.  * Side effects:
  950.  * A new object is created.
  951.  *
  952.  *----------------------------------------------------------------------
  953.  */
  954. Tcl_Obj *
  955. Tcl_ConcatObj(objc, objv)
  956.     int objc; /* Number of objects to concatenate. */
  957.     Tcl_Obj *CONST objv[]; /* Array of objects to concatenate. */
  958. {
  959.     int allocSize, finalSize, length, elemLength, i;
  960.     char *p;
  961.     char *element;
  962.     char *concatStr;
  963.     Tcl_Obj *objPtr;
  964.     /*
  965.      * Check first to see if all the items are of list type.  If so,
  966.      * we will concat them together as lists, and return a list object.
  967.      * This is only valid when the lists have no current string
  968.      * representation, since we don't know what the original type was.
  969.      * An original string rep may have lost some whitespace info when
  970.      * converted which could be important.
  971.      */
  972.     for (i = 0;  i < objc;  i++) {
  973. objPtr = objv[i];
  974. if ((objPtr->typePtr != &tclListType) || (objPtr->bytes != NULL)) {
  975.     break;
  976. }
  977.     }
  978.     if (i == objc) {
  979. Tcl_Obj **listv;
  980. int listc;
  981. objPtr = Tcl_NewListObj(0, NULL);
  982. for (i = 0;  i < objc;  i++) {
  983.     /*
  984.      * Tcl_ListObjAppendList could be used here, but this saves
  985.      * us a bit of type checking (since we've already done it)
  986.      * Use of INT_MAX tells us to always put the new stuff on
  987.      * the end.  It will be set right in Tcl_ListObjReplace.
  988.      */
  989.     Tcl_ListObjGetElements(NULL, objv[i], &listc, &listv);
  990.     Tcl_ListObjReplace(NULL, objPtr, INT_MAX, 0, listc, listv);
  991. }
  992. return objPtr;
  993.     }
  994.     allocSize = 0;
  995.     for (i = 0;  i < objc;  i++) {
  996. objPtr = objv[i];
  997. element = Tcl_GetStringFromObj(objPtr, &length);
  998. if ((element != NULL) && (length > 0)) {
  999.     allocSize += (length + 1);
  1000. }
  1001.     }
  1002.     if (allocSize == 0) {
  1003. allocSize = 1; /* enough for the NULL byte at end */
  1004.     }
  1005.     /*
  1006.      * Allocate storage for the concatenated result. Note that allocSize
  1007.      * is one more than the total number of characters, and so includes
  1008.      * room for the terminating NULL byte.
  1009.      */
  1010.     
  1011.     concatStr = (char *) ckalloc((unsigned) allocSize);
  1012.     /*
  1013.      * Now concatenate the elements. Clip white space off the front and back
  1014.      * to generate a neater result, and ignore any empty elements. Also put
  1015.      * a null byte at the end.
  1016.      */
  1017.     finalSize = 0;
  1018.     if (objc == 0) {
  1019. *concatStr = '';
  1020.     } else {
  1021. p = concatStr;
  1022.         for (i = 0;  i < objc;  i++) {
  1023.     objPtr = objv[i];
  1024.     element = Tcl_GetStringFromObj(objPtr, &elemLength);
  1025.     while ((elemLength > 0) && (UCHAR(*element) < 127)
  1026.     && isspace(UCHAR(*element))) { /* INTL: ISO C space. */
  1027.          element++;
  1028.  elemLength--;
  1029.     }
  1030.     /*
  1031.      * Trim trailing white space.  But, be careful not to trim
  1032.      * a space character if it is preceded by a backslash: in
  1033.      * this case it could be significant.
  1034.      */
  1035.     while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127)
  1036.     && isspace(UCHAR(element[elemLength-1])) /* INTL: ISO C space. */
  1037.     && ((elemLength < 2) || (element[elemLength-2] != '\'))) {
  1038. elemLength--;
  1039.     }
  1040.     if (elemLength == 0) {
  1041.          continue; /* nothing left of this element */
  1042.     }
  1043.     memcpy((VOID *) p, (VOID *) element, (size_t) elemLength);
  1044.     p += elemLength;
  1045.     *p = ' ';
  1046.     p++;
  1047.     finalSize += (elemLength + 1);
  1048.         }
  1049.         if (p != concatStr) {
  1050.     p[-1] = 0;
  1051.     finalSize -= 1; /* we overwrote the final ' ' */
  1052.         } else {
  1053.     *p = 0;
  1054.         }
  1055.     }
  1056.     
  1057.     TclNewObj(objPtr);
  1058.     objPtr->bytes  = concatStr;
  1059.     objPtr->length = finalSize;
  1060.     return objPtr;
  1061. }
  1062. /*
  1063.  *----------------------------------------------------------------------
  1064.  *
  1065.  * Tcl_StringMatch --
  1066.  *
  1067.  * See if a particular string matches a particular pattern.
  1068.  *
  1069.  * Results:
  1070.  * The return value is 1 if string matches pattern, and
  1071.  * 0 otherwise.  The matching operation permits the following
  1072.  * special characters in the pattern: *?[] (see the manual
  1073.  * entry for details on what these mean).
  1074.  *
  1075.  * Side effects:
  1076.  * None.
  1077.  *
  1078.  *----------------------------------------------------------------------
  1079.  */
  1080. int
  1081. Tcl_StringMatch(string, pattern)
  1082.     CONST char *string; /* String. */
  1083.     CONST char *pattern; /* Pattern, which may contain special
  1084.  * characters. */
  1085. {
  1086.     return Tcl_StringCaseMatch(string, pattern, 0);
  1087. }
  1088. /*
  1089.  *----------------------------------------------------------------------
  1090.  *
  1091.  * Tcl_StringCaseMatch --
  1092.  *
  1093.  * See if a particular string matches a particular pattern.
  1094.  * Allows case insensitivity.
  1095.  *
  1096.  * Results:
  1097.  * The return value is 1 if string matches pattern, and
  1098.  * 0 otherwise.  The matching operation permits the following
  1099.  * special characters in the pattern: *?[] (see the manual
  1100.  * entry for details on what these mean).
  1101.  *
  1102.  * Side effects:
  1103.  * None.
  1104.  *
  1105.  *----------------------------------------------------------------------
  1106.  */
  1107. int
  1108. Tcl_StringCaseMatch(string, pattern, nocase)
  1109.     CONST char *string; /* String. */
  1110.     CONST char *pattern; /* Pattern, which may contain special
  1111.  * characters. */
  1112.     int nocase; /* 0 for case sensitive, 1 for insensitive */
  1113. {
  1114.     int p, charLen;
  1115.     CONST char *pstart = pattern;
  1116.     Tcl_UniChar ch1, ch2;
  1117.     
  1118.     while (1) {
  1119. p = *pattern;
  1120. /*
  1121.  * See if we're at the end of both the pattern and the string.  If
  1122.  * so, we succeeded.  If we're at the end of the pattern but not at
  1123.  * the end of the string, we failed.
  1124.  */
  1125. if (p == '') {
  1126.     return (*string == '');
  1127. }
  1128. if ((*string == '') && (p != '*')) {
  1129.     return 0;
  1130. }
  1131. /*
  1132.  * Check for a "*" as the next pattern character.  It matches
  1133.  * any substring.  We handle this by calling ourselves
  1134.  * recursively for each postfix of string, until either we
  1135.  * match or we reach the end of the string.
  1136.  */
  1137. if (p == '*') {
  1138.     /*
  1139.      * Skip all successive *'s in the pattern
  1140.      */
  1141.     while (*(++pattern) == '*') {}
  1142.     p = *pattern;
  1143.     if (p == '') {
  1144. return 1;
  1145.     }
  1146.     /*
  1147.      * This is a special case optimization for single-byte utf.
  1148.      */
  1149.     if (UCHAR(*pattern) < 0x80) {
  1150. ch2 = (Tcl_UniChar)
  1151.     (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
  1152.     } else {
  1153. Tcl_UtfToUniChar(pattern, &ch2);
  1154. if (nocase) {
  1155.     ch2 = Tcl_UniCharToLower(ch2);
  1156. }
  1157.     }
  1158.     while (1) {
  1159. /*
  1160.  * Optimization for matching - cruise through the string
  1161.  * quickly if the next char in the pattern isn't a special
  1162.  * character
  1163.  */
  1164. if ((p != '[') && (p != '?') && (p != '\')) {
  1165.     if (nocase) {
  1166. while (*string) {
  1167.     charLen = TclUtfToUniChar(string, &ch1);
  1168.     if (ch2==ch1 || ch2==Tcl_UniCharToLower(ch1)) {
  1169. break;
  1170.     }
  1171.     string += charLen;
  1172. }
  1173.     } else {
  1174. /*
  1175.  * There's no point in trying to make this code
  1176.  * shorter, as the number of bytes you want to
  1177.  * compare each time is non-constant.
  1178.  */
  1179. while (*string) {
  1180.     charLen = TclUtfToUniChar(string, &ch1);
  1181.     if (ch2 == ch1) {
  1182. break;
  1183.     }
  1184.     string += charLen;
  1185. }
  1186.     }
  1187. }
  1188. if (Tcl_StringCaseMatch(string, pattern, nocase)) {
  1189.     return 1;
  1190. }
  1191. if (*string == '') {
  1192.     return 0;
  1193. }
  1194. string += TclUtfToUniChar(string, &ch1);
  1195.     }
  1196. }
  1197. /*
  1198.  * Check for a "?" as the next pattern character.  It matches
  1199.  * any single character.
  1200.  */
  1201. if (p == '?') {
  1202.     pattern++;
  1203.     string += TclUtfToUniChar(string, &ch1);
  1204.     continue;
  1205. }
  1206. /*
  1207.  * Check for a "[" as the next pattern character.  It is followed
  1208.  * by a list of characters that are acceptable, or by a range
  1209.  * (two characters separated by "-").
  1210.  */
  1211. if (p == '[') {
  1212.     Tcl_UniChar startChar, endChar;
  1213.     pattern++;
  1214.     if (UCHAR(*string) < 0x80) {
  1215. ch1 = (Tcl_UniChar)
  1216.     (nocase ? tolower(UCHAR(*string)) : UCHAR(*string));
  1217. string++;
  1218.     } else {
  1219. string += Tcl_UtfToUniChar(string, &ch1);
  1220. if (nocase) {
  1221.     ch1 = Tcl_UniCharToLower(ch1);
  1222. }
  1223.     }
  1224.     while (1) {
  1225. if ((*pattern == ']') || (*pattern == '')) {
  1226.     return 0;
  1227. }
  1228. if (UCHAR(*pattern) < 0x80) {
  1229.     startChar = (Tcl_UniChar)
  1230. (nocase ? tolower(UCHAR(*pattern)) : UCHAR(*pattern));
  1231.     pattern++;
  1232. } else {
  1233.     pattern += Tcl_UtfToUniChar(pattern, &startChar);
  1234.     if (nocase) {
  1235. startChar = Tcl_UniCharToLower(startChar);
  1236.     }
  1237. }
  1238. if (*pattern == '-') {
  1239.     pattern++;
  1240.     if (*pattern == '') {
  1241. return 0;
  1242.     }
  1243.     if (UCHAR(*pattern) < 0x80) {
  1244. endChar = (Tcl_UniChar)
  1245.     (nocase ? tolower(UCHAR(*pattern))
  1246.     : UCHAR(*pattern));
  1247. pattern++;
  1248.     } else {
  1249. pattern += Tcl_UtfToUniChar(pattern, &endChar);
  1250. if (nocase) {
  1251.     endChar = Tcl_UniCharToLower(endChar);
  1252. }
  1253.     }
  1254.     if (((startChar <= ch1) && (ch1 <= endChar))
  1255.     || ((endChar <= ch1) && (ch1 <= startChar))) {
  1256. /*
  1257.  * Matches ranges of form [a-z] or [z-a].
  1258.  */
  1259. break;
  1260.     }
  1261. } else if (startChar == ch1) {
  1262.     break;
  1263. }
  1264.     }
  1265.     while (*pattern != ']') {
  1266. if (*pattern == '') {
  1267.     pattern = Tcl_UtfPrev(pattern, pstart);
  1268.     break;
  1269. }
  1270. pattern++;
  1271.     }
  1272.     pattern++;
  1273.     continue;
  1274. }
  1275. /*
  1276.  * If the next pattern character is '', just strip off the ''
  1277.  * so we do exact matching on the character that follows.
  1278.  */
  1279. if (p == '\') {
  1280.     pattern++;
  1281.     if (*pattern == '') {
  1282. return 0;
  1283.     }
  1284. }
  1285. /*
  1286.  * There's no special character.  Just make sure that the next
  1287.  * bytes of each string match.
  1288.  */
  1289. string  += TclUtfToUniChar(string, &ch1);
  1290. pattern += TclUtfToUniChar(pattern, &ch2);
  1291. if (nocase) {
  1292.     if (Tcl_UniCharToLower(ch1) != Tcl_UniCharToLower(ch2)) {
  1293. return 0;
  1294.     }
  1295. } else if (ch1 != ch2) {
  1296.     return 0;
  1297. }
  1298.     }
  1299. }
  1300. /*
  1301.  *----------------------------------------------------------------------
  1302.  *
  1303.  * TclMatchIsTrivial --
  1304.  *
  1305.  * Test whether a particular glob pattern is a trivial pattern.
  1306.  * (i.e. where matching is the same as equality testing).
  1307.  *
  1308.  * Results:
  1309.  * A boolean indicating whether the pattern is free of all of the
  1310.  * glob special chars.
  1311.  *
  1312.  * Side effects:
  1313.  * None.
  1314.  *
  1315.  *----------------------------------------------------------------------
  1316.  */
  1317. int
  1318. TclMatchIsTrivial(pattern)
  1319.     CONST char *pattern;
  1320. {
  1321.     CONST char *p = pattern;
  1322.     while (1) {
  1323. switch (*p++) {
  1324. case '':
  1325.     return 1;
  1326. case '*':
  1327. case '?':
  1328. case '[':
  1329. case '\':
  1330.     return 0;
  1331. }
  1332.     }
  1333. }
  1334. /*
  1335.  *----------------------------------------------------------------------
  1336.  *
  1337.  * Tcl_DStringInit --
  1338.  *
  1339.  * Initializes a dynamic string, discarding any previous contents
  1340.  * of the string (Tcl_DStringFree should have been called already
  1341.  * if the dynamic string was previously in use).
  1342.  *
  1343.  * Results:
  1344.  * None.
  1345.  *
  1346.  * Side effects:
  1347.  * The dynamic string is initialized to be empty.
  1348.  *
  1349.  *----------------------------------------------------------------------
  1350.  */
  1351. void
  1352. Tcl_DStringInit(dsPtr)
  1353.     Tcl_DString *dsPtr; /* Pointer to structure for dynamic string. */
  1354. {
  1355.     dsPtr->string = dsPtr->staticSpace;
  1356.     dsPtr->length = 0;
  1357.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1358.     dsPtr->staticSpace[0] = '';
  1359. }
  1360. /*
  1361.  *----------------------------------------------------------------------
  1362.  *
  1363.  * Tcl_DStringAppend --
  1364.  *
  1365.  * Append more characters to the current value of a dynamic string.
  1366.  *
  1367.  * Results:
  1368.  * The return value is a pointer to the dynamic string's new value.
  1369.  *
  1370.  * Side effects:
  1371.  * Length bytes from string (or all of string if length is less
  1372.  * than zero) are added to the current value of the string. Memory
  1373.  * gets reallocated if needed to accomodate the string's new size.
  1374.  *
  1375.  *----------------------------------------------------------------------
  1376.  */
  1377. char *
  1378. Tcl_DStringAppend(dsPtr, string, length)
  1379.     Tcl_DString *dsPtr; /* Structure describing dynamic string. */
  1380.     CONST char *string; /* String to append.  If length is -1 then
  1381.  * this must be null-terminated. */
  1382.     int length; /* Number of characters from string to
  1383.  * append.  If < 0, then append all of string,
  1384.  * up to null at end. */
  1385. {
  1386.     int newSize;
  1387.     char *dst;
  1388.     CONST char *end;
  1389.     if (length < 0) {
  1390. length = strlen(string);
  1391.     }
  1392.     newSize = length + dsPtr->length;
  1393.     /*
  1394.      * Allocate a larger buffer for the string if the current one isn't
  1395.      * large enough. Allocate extra space in the new buffer so that there
  1396.      * will be room to grow before we have to allocate again.
  1397.      */
  1398.     if (newSize >= dsPtr->spaceAvl) {
  1399. dsPtr->spaceAvl = newSize * 2;
  1400. if (dsPtr->string == dsPtr->staticSpace) {
  1401.     char *newString;
  1402.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1403.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1404.     (size_t) dsPtr->length);
  1405.     dsPtr->string = newString;
  1406. } else {
  1407.     dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string,
  1408.     (size_t) dsPtr->spaceAvl);
  1409. }
  1410.     }
  1411.     /*
  1412.      * Copy the new string into the buffer at the end of the old
  1413.      * one.
  1414.      */
  1415.     for (dst = dsPtr->string + dsPtr->length, end = string+length;
  1416.     string < end; string++, dst++) {
  1417. *dst = *string;
  1418.     }
  1419.     *dst = '';
  1420.     dsPtr->length += length;
  1421.     return dsPtr->string;
  1422. }
  1423. /*
  1424.  *----------------------------------------------------------------------
  1425.  *
  1426.  * Tcl_DStringAppendElement --
  1427.  *
  1428.  * Append a list element to the current value of a dynamic string.
  1429.  *
  1430.  * Results:
  1431.  * The return value is a pointer to the dynamic string's new value.
  1432.  *
  1433.  * Side effects:
  1434.  * String is reformatted as a list element and added to the current
  1435.  * value of the string.  Memory gets reallocated if needed to
  1436.  * accomodate the string's new size.
  1437.  *
  1438.  *----------------------------------------------------------------------
  1439.  */
  1440. char *
  1441. Tcl_DStringAppendElement(dsPtr, string)
  1442.     Tcl_DString *dsPtr; /* Structure describing dynamic string. */
  1443.     CONST char *string; /* String to append.  Must be
  1444.  * null-terminated. */
  1445. {
  1446.     int newSize, flags, strSize;
  1447.     char *dst;
  1448.     strSize = ((string == NULL) ? 0 : strlen(string));
  1449.     newSize = Tcl_ScanCountedElement(string, strSize, &flags)
  1450. + dsPtr->length + 1;
  1451.     /*
  1452.      * Allocate a larger buffer for the string if the current one isn't
  1453.      * large enough.  Allocate extra space in the new buffer so that there
  1454.      * will be room to grow before we have to allocate again.
  1455.      * SPECIAL NOTE: must use memcpy, not strcpy, to copy the string
  1456.      * to a larger buffer, since there may be embedded NULLs in the
  1457.      * string in some cases.
  1458.      */
  1459.     if (newSize >= dsPtr->spaceAvl) {
  1460. dsPtr->spaceAvl = newSize * 2;
  1461. if (dsPtr->string == dsPtr->staticSpace) {
  1462.     char *newString;
  1463.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1464.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1465.     (size_t) dsPtr->length);
  1466.     dsPtr->string = newString;
  1467. } else {
  1468.     dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string,
  1469.     (size_t) dsPtr->spaceAvl);
  1470. }
  1471.     }
  1472.     /*
  1473.      * Convert the new string to a list element and copy it into the
  1474.      * buffer at the end, with a space, if needed.
  1475.      */
  1476.     dst = dsPtr->string + dsPtr->length;
  1477.     if (TclNeedSpace(dsPtr->string, dst)) {
  1478. *dst = ' ';
  1479. dst++;
  1480. dsPtr->length++;
  1481.     }
  1482.     dsPtr->length += Tcl_ConvertCountedElement(string, strSize, dst, flags);
  1483.     return dsPtr->string;
  1484. }
  1485. /*
  1486.  *----------------------------------------------------------------------
  1487.  *
  1488.  * Tcl_DStringSetLength --
  1489.  *
  1490.  * Change the length of a dynamic string.  This can cause the
  1491.  * string to either grow or shrink, depending on the value of
  1492.  * length.
  1493.  *
  1494.  * Results:
  1495.  * None.
  1496.  *
  1497.  * Side effects:
  1498.  * The length of dsPtr is changed to length and a null byte is
  1499.  * stored at that position in the string.  If length is larger
  1500.  * than the space allocated for dsPtr, then a panic occurs.
  1501.  *
  1502.  *----------------------------------------------------------------------
  1503.  */
  1504. void
  1505. Tcl_DStringSetLength(dsPtr, length)
  1506.     Tcl_DString *dsPtr; /* Structure describing dynamic string. */
  1507.     int length; /* New length for dynamic string. */
  1508. {
  1509.     int newsize;
  1510.     if (length < 0) {
  1511. length = 0;
  1512.     }
  1513.     if (length >= dsPtr->spaceAvl) {
  1514. /*
  1515.  * There are two interesting cases here.  In the first case, the user
  1516.  * may be trying to allocate a large buffer of a specific size.  It
  1517.  * would be wasteful to overallocate that buffer, so we just allocate
  1518.  * enough for the requested size plus the trailing null byte.  In the
  1519.  * second case, we are growing the buffer incrementally, so we need
  1520.  * behavior similar to Tcl_DStringAppend.  The requested length will
  1521.  * usually be a small delta above the current spaceAvl, so we'll end up
  1522.  * doubling the old size.  This won't grow the buffer quite as quickly,
  1523.  * but it should be close enough.
  1524.  */
  1525. newsize = dsPtr->spaceAvl * 2;
  1526. if (length < newsize) {
  1527.     dsPtr->spaceAvl = newsize;
  1528. } else {
  1529.     dsPtr->spaceAvl = length + 1;
  1530. }
  1531. if (dsPtr->string == dsPtr->staticSpace) {
  1532.     char *newString;
  1533.     newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
  1534.     memcpy((VOID *) newString, (VOID *) dsPtr->string,
  1535.     (size_t) dsPtr->length);
  1536.     dsPtr->string = newString;
  1537. } else {
  1538.     dsPtr->string = (char *) ckrealloc((VOID *) dsPtr->string,
  1539.     (size_t) dsPtr->spaceAvl);
  1540. }
  1541.     }
  1542.     dsPtr->length = length;
  1543.     dsPtr->string[length] = 0;
  1544. }
  1545. /*
  1546.  *----------------------------------------------------------------------
  1547.  *
  1548.  * Tcl_DStringFree --
  1549.  *
  1550.  * Frees up any memory allocated for the dynamic string and
  1551.  * reinitializes the string to an empty state.
  1552.  *
  1553.  * Results:
  1554.  * None.
  1555.  *
  1556.  * Side effects:
  1557.  * The previous contents of the dynamic string are lost, and
  1558.  * the new value is an empty string.
  1559.  *
  1560.  *---------------------------------------------------------------------- */
  1561. void
  1562. Tcl_DStringFree(dsPtr)
  1563.     Tcl_DString *dsPtr; /* Structure describing dynamic string. */
  1564. {
  1565.     if (dsPtr->string != dsPtr->staticSpace) {
  1566. ckfree(dsPtr->string);
  1567.     }
  1568.     dsPtr->string = dsPtr->staticSpace;
  1569.     dsPtr->length = 0;
  1570.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1571.     dsPtr->staticSpace[0] = '';
  1572. }
  1573. /*
  1574.  *----------------------------------------------------------------------
  1575.  *
  1576.  * Tcl_DStringResult --
  1577.  *
  1578.  * This procedure moves the value of a dynamic string into an
  1579.  * interpreter as its string result. Afterwards, the dynamic string
  1580.  * is reset to an empty string.
  1581.  *
  1582.  * Results:
  1583.  * None.
  1584.  *
  1585.  * Side effects:
  1586.  * The string is "moved" to interp's result, and any existing
  1587.  * string result for interp is freed. dsPtr is reinitialized to
  1588.  * an empty string.
  1589.  *
  1590.  *----------------------------------------------------------------------
  1591.  */
  1592. void
  1593. Tcl_DStringResult(interp, dsPtr)
  1594.     Tcl_Interp *interp; /* Interpreter whose result is to be reset. */
  1595.     Tcl_DString *dsPtr; /* Dynamic string that is to become the
  1596.  * result of interp. */
  1597. {
  1598.     Tcl_ResetResult(interp);
  1599.     
  1600.     if (dsPtr->string != dsPtr->staticSpace) {
  1601. interp->result = dsPtr->string;
  1602. interp->freeProc = TCL_DYNAMIC;
  1603.     } else if (dsPtr->length < TCL_RESULT_SIZE) {
  1604. interp->result = ((Interp *) interp)->resultSpace;
  1605. strcpy(interp->result, dsPtr->string);
  1606.     } else {
  1607. Tcl_SetResult(interp, dsPtr->string, TCL_VOLATILE);
  1608.     }
  1609.     
  1610.     dsPtr->string = dsPtr->staticSpace;
  1611.     dsPtr->length = 0;
  1612.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1613.     dsPtr->staticSpace[0] = '';
  1614. }
  1615. /*
  1616.  *----------------------------------------------------------------------
  1617.  *
  1618.  * Tcl_DStringGetResult --
  1619.  *
  1620.  * This procedure moves an interpreter's result into a dynamic string.
  1621.  *
  1622.  * Results:
  1623.  * None.
  1624.  *
  1625.  * Side effects:
  1626.  * The interpreter's string result is cleared, and the previous
  1627.  * contents of dsPtr are freed.
  1628.  *
  1629.  * If the string result is empty, the object result is moved to the
  1630.  * string result, then the object result is reset.
  1631.  *
  1632.  *----------------------------------------------------------------------
  1633.  */
  1634. void
  1635. Tcl_DStringGetResult(interp, dsPtr)
  1636.     Tcl_Interp *interp; /* Interpreter whose result is to be reset. */
  1637.     Tcl_DString *dsPtr; /* Dynamic string that is to become the
  1638.  * result of interp. */
  1639. {
  1640.     Interp *iPtr = (Interp *) interp;
  1641.     
  1642.     if (dsPtr->string != dsPtr->staticSpace) {
  1643. ckfree(dsPtr->string);
  1644.     }
  1645.     /*
  1646.      * If the string result is empty, move the object result to the
  1647.      * string result, then reset the object result.
  1648.      */
  1649.     if (*(iPtr->result) == 0) {
  1650. Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
  1651.         TCL_VOLATILE);
  1652.     }
  1653.     dsPtr->length = strlen(iPtr->result);
  1654.     if (iPtr->freeProc != NULL) {
  1655. if (iPtr->freeProc == TCL_DYNAMIC) {
  1656.     dsPtr->string = iPtr->result;
  1657.     dsPtr->spaceAvl = dsPtr->length+1;
  1658. } else {
  1659.     dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length+1));
  1660.     strcpy(dsPtr->string, iPtr->result);
  1661.     (*iPtr->freeProc)(iPtr->result);
  1662. }
  1663. dsPtr->spaceAvl = dsPtr->length+1;
  1664. iPtr->freeProc = NULL;
  1665.     } else {
  1666. if (dsPtr->length < TCL_DSTRING_STATIC_SIZE) {
  1667.     dsPtr->string = dsPtr->staticSpace;
  1668.     dsPtr->spaceAvl = TCL_DSTRING_STATIC_SIZE;
  1669. } else {
  1670.     dsPtr->string = (char *) ckalloc((unsigned) (dsPtr->length + 1));
  1671.     dsPtr->spaceAvl = dsPtr->length + 1;
  1672. }
  1673. strcpy(dsPtr->string, iPtr->result);
  1674.     }
  1675.     
  1676.     iPtr->result = iPtr->resultSpace;
  1677.     iPtr->resultSpace[0] = 0;
  1678. }
  1679. /*
  1680.  *----------------------------------------------------------------------
  1681.  *
  1682.  * Tcl_DStringStartSublist --
  1683.  *
  1684.  * This procedure adds the necessary information to a dynamic
  1685.  * string (e.g. " {" to start a sublist.  Future element
  1686.  * appends will be in the sublist rather than the main list.
  1687.  *
  1688.  * Results:
  1689.  * None.
  1690.  *
  1691.  * Side effects:
  1692.  * Characters get added to the dynamic string.
  1693.  *
  1694.  *----------------------------------------------------------------------
  1695.  */
  1696. void
  1697. Tcl_DStringStartSublist(dsPtr)
  1698.     Tcl_DString *dsPtr; /* Dynamic string. */
  1699. {
  1700.     if (TclNeedSpace(dsPtr->string, dsPtr->string + dsPtr->length)) {
  1701. Tcl_DStringAppend(dsPtr, " {", -1);
  1702.     } else {
  1703. Tcl_DStringAppend(dsPtr, "{", -1);
  1704.     }
  1705. }
  1706. /*
  1707.  *----------------------------------------------------------------------
  1708.  *
  1709.  * Tcl_DStringEndSublist --
  1710.  *
  1711.  * This procedure adds the necessary characters to a dynamic
  1712.  * string to end a sublist (e.g. "}").  Future element appends
  1713.  * will be in the enclosing (sub)list rather than the current
  1714.  * sublist.
  1715.  *
  1716.  * Results:
  1717.  * None.
  1718.  *
  1719.  * Side effects:
  1720.  * None.
  1721.  *
  1722.  *----------------------------------------------------------------------
  1723.  */
  1724. void
  1725. Tcl_DStringEndSublist(dsPtr)
  1726.     Tcl_DString *dsPtr; /* Dynamic string. */
  1727. {
  1728.     Tcl_DStringAppend(dsPtr, "}", -1);
  1729. }
  1730. /*
  1731.  *----------------------------------------------------------------------
  1732.  *
  1733.  * Tcl_PrintDouble --
  1734.  *
  1735.  * Given a floating-point value, this procedure converts it to
  1736.  * an ASCII string using.
  1737.  *
  1738.  * Results:
  1739.  * The ASCII equivalent of "value" is written at "dst".  It is
  1740.  * written using the current precision, and it is guaranteed to
  1741.  * contain a decimal point or exponent, so that it looks like
  1742.  * a floating-point value and not an integer.
  1743.  *
  1744.  * Side effects:
  1745.  * None.
  1746.  *
  1747.  *----------------------------------------------------------------------
  1748.  */
  1749. void
  1750. Tcl_PrintDouble(interp, value, dst)
  1751.     Tcl_Interp *interp; /* Interpreter whose tcl_precision
  1752.  * variable used to be used to control
  1753.  * printing.  It's ignored now. */
  1754.     double value; /* Value to print as string. */
  1755.     char *dst; /* Where to store converted value;
  1756.  * must have at least TCL_DOUBLE_SPACE
  1757.  * characters. */
  1758. {
  1759.     char *p, c;
  1760.     Tcl_UniChar ch;
  1761.     Tcl_MutexLock(&precisionMutex);
  1762.     sprintf(dst, precisionFormat, value);
  1763.     Tcl_MutexUnlock(&precisionMutex);
  1764.     /*
  1765.      * If the ASCII result looks like an integer, add ".0" so that it
  1766.      * doesn't look like an integer anymore.  This prevents floating-point
  1767.      * values from being converted to integers unintentionally.
  1768.      * Check for ASCII specifically to speed up the function.
  1769.      */
  1770.     for (p = dst; *p != 0; ) {
  1771. if (UCHAR(*p) < 0x80) {
  1772.     c = *p++;
  1773. } else {
  1774.     p += Tcl_UtfToUniChar(p, &ch);
  1775.     c = UCHAR(ch);
  1776. }
  1777. if ((c == '.') || isalpha(UCHAR(c))) { /* INTL: ISO only. */
  1778.     return;
  1779. }
  1780.     }
  1781.     p[0] = '.';
  1782.     p[1] = '0';
  1783.     p[2] = 0;
  1784. }
  1785. /*
  1786.  *----------------------------------------------------------------------
  1787.  *
  1788.  * TclPrecTraceProc --
  1789.  *
  1790.  * This procedure is invoked whenever the variable "tcl_precision"
  1791.  * is written.
  1792.  *
  1793.  * Results:
  1794.  * Returns NULL if all went well, or an error message if the
  1795.  * new value for the variable doesn't make sense.
  1796.  *
  1797.  * Side effects:
  1798.  * If the new value doesn't make sense then this procedure
  1799.  * undoes the effect of the variable modification.  Otherwise
  1800.  * it modifies the format string that's used by Tcl_PrintDouble.
  1801.  *
  1802.  *----------------------------------------------------------------------
  1803.  */
  1804. /* ARGSUSED */
  1805. char *
  1806. TclPrecTraceProc(clientData, interp, name1, name2, flags)
  1807.     ClientData clientData; /* Not used. */
  1808.     Tcl_Interp *interp; /* Interpreter containing variable. */
  1809.     CONST char *name1; /* Name of variable. */
  1810.     CONST char *name2; /* Second part of variable name. */
  1811.     int flags; /* Information about what happened. */
  1812. {
  1813.     CONST char *value;
  1814.     char *end;
  1815.     int prec;
  1816.     /*
  1817.      * If the variable is unset, then recreate the trace.
  1818.      */
  1819.     if (flags & TCL_TRACE_UNSETS) {
  1820. if ((flags & TCL_TRACE_DESTROYED) && !Tcl_InterpDeleted(interp)) {
  1821.     Tcl_TraceVar2(interp, name1, name2,
  1822.     TCL_GLOBAL_ONLY|TCL_TRACE_READS|TCL_TRACE_WRITES
  1823.     |TCL_TRACE_UNSETS, TclPrecTraceProc, clientData);
  1824. }
  1825. return (char *) NULL;
  1826.     }
  1827.     /*
  1828.      * When the variable is read, reset its value from our shared
  1829.      * value.  This is needed in case the variable was modified in
  1830.      * some other interpreter so that this interpreter's value is
  1831.      * out of date.
  1832.      */
  1833.     Tcl_MutexLock(&precisionMutex);
  1834.     if (flags & TCL_TRACE_READS) {
  1835. Tcl_SetVar2(interp, name1, name2, precisionString,
  1836. flags & TCL_GLOBAL_ONLY);
  1837. Tcl_MutexUnlock(&precisionMutex);
  1838. return (char *) NULL;
  1839.     }
  1840.     /*
  1841.      * The variable is being written.  Check the new value and disallow
  1842.      * it if it isn't reasonable or if this is a safe interpreter (we
  1843.      * don't want safe interpreters messing up the precision of other
  1844.      * interpreters).
  1845.      */
  1846.     if (Tcl_IsSafe(interp)) {
  1847. Tcl_SetVar2(interp, name1, name2, precisionString,
  1848. flags & TCL_GLOBAL_ONLY);
  1849. Tcl_MutexUnlock(&precisionMutex);
  1850. return "can't modify precision from a safe interpreter";
  1851.     }
  1852.     value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
  1853.     if (value == NULL) {
  1854. value = "";
  1855.     }
  1856.     prec = strtoul(value, &end, 10);
  1857.     if ((prec <= 0) || (prec > TCL_MAX_PREC) || (prec > 100) ||
  1858.     (end == value) || (*end != 0)) {
  1859. Tcl_SetVar2(interp, name1, name2, precisionString,
  1860. flags & TCL_GLOBAL_ONLY);
  1861. Tcl_MutexUnlock(&precisionMutex);
  1862. return "improper value for precision";
  1863.     }
  1864.     TclFormatInt(precisionString, prec);
  1865.     sprintf(precisionFormat, "%%.%dg", prec);
  1866.     Tcl_MutexUnlock(&precisionMutex);
  1867.     return (char *) NULL;
  1868. }
  1869. /*
  1870.  *----------------------------------------------------------------------
  1871.  *
  1872.  * TclNeedSpace --
  1873.  *
  1874.  * This procedure checks to see whether it is appropriate to
  1875.  * add a space before appending a new list element to an
  1876.  * existing string.
  1877.  *
  1878.  * Results:
  1879.  * The return value is 1 if a space is appropriate, 0 otherwise.
  1880.  *
  1881.  * Side effects:
  1882.  * None.
  1883.  *
  1884.  *----------------------------------------------------------------------
  1885.  */
  1886. int
  1887. TclNeedSpace(start, end)
  1888.     CONST char *start; /* First character in string. */
  1889.     CONST char *end; /* End of string (place where space will
  1890.  * be added, if appropriate). */
  1891. {
  1892.     /*
  1893.      * A space is needed unless either
  1894.      * (a) we're at the start of the string, or
  1895.      */
  1896.     if (end == start) {
  1897. return 0;
  1898.     }
  1899.     /*
  1900.      * (b) we're at the start of a nested list-element, quoted with an
  1901.      *     open curly brace; we can be nested arbitrarily deep, so long
  1902.      *     as the first curly brace starts an element, so backtrack over
  1903.      *     open curly braces that are trailing characters of the string; and
  1904.      */
  1905.     end = Tcl_UtfPrev(end, start);
  1906.     while (*end == '{') {
  1907. if (end == start) {
  1908.     return 0;
  1909. }
  1910. end = Tcl_UtfPrev(end, start);
  1911.     }
  1912.     /*
  1913.      * (c) the trailing character of the string is already a list-element
  1914.      *     separator (according to TclFindElement); that is, one of these
  1915.      *     characters:
  1916.      *      u0009 t TAB
  1917.      *      u000A n NEWLINE
  1918.      *      u000B v VERTICAL TAB
  1919.      *      u000C f FORM FEED
  1920.      *      u000D r CARRIAGE RETURN
  1921.      *      u0020 SPACE
  1922.      *     with the condition that the penultimate character is not a
  1923.      *     backslash.
  1924.      */
  1925.     if (*end > 0x20) {
  1926. /*
  1927.  * Performance tweak.  All ASCII spaces are <= 0x20. So get
  1928.  * a quick answer for most characters before comparing against
  1929.  * all spaces in the switch below.
  1930.  *
  1931.  * NOTE: Remove this if other Unicode spaces ever get accepted
  1932.  * as list-element separators.
  1933.  */
  1934. return 1;
  1935.     }
  1936.     switch (*end) {
  1937. case ' ':
  1938.         case 't':
  1939.         case 'n':
  1940.         case 'r':
  1941.         case 'v':
  1942.         case 'f':
  1943.     if ((end == start) || (end[-1] != '\')) {
  1944. return 0;
  1945.     }
  1946.     }
  1947.     return 1;
  1948. }
  1949. /*
  1950.  *----------------------------------------------------------------------
  1951.  *
  1952.  * TclFormatInt --
  1953.  *
  1954.  * This procedure formats an integer into a sequence of decimal digit
  1955.  * characters in a buffer. If the integer is negative, a minus sign is
  1956.  * inserted at the start of the buffer. A null character is inserted at
  1957.  * the end of the formatted characters. It is the caller's
  1958.  * responsibility to ensure that enough storage is available. This
  1959.  * procedure has the effect of sprintf(buffer, "%d", n) but is faster.
  1960.  *
  1961.  * Results:
  1962.  * An integer representing the number of characters formatted, not
  1963.  * including the terminating .
  1964.  *
  1965.  * Side effects:
  1966.  * The formatted characters are written into the storage pointer to
  1967.  * by the "buffer" argument.
  1968.  *
  1969.  *----------------------------------------------------------------------
  1970.  */
  1971. int
  1972. TclFormatInt(buffer, n)
  1973.     char *buffer; /* Points to the storage into which the
  1974.  * formatted characters are written. */
  1975.     long n; /* The integer to format. */
  1976. {
  1977.     long intVal;
  1978.     int i;
  1979.     int numFormatted, j;
  1980.     char *digits = "0123456789";
  1981.     /*
  1982.      * Check first whether "n" is zero.
  1983.      */
  1984.     if (n == 0) {
  1985. buffer[0] = '0';
  1986. buffer[1] = 0;
  1987. return 1;
  1988.     }
  1989.     /*
  1990.      * Check whether "n" is the maximum negative value. This is
  1991.      * -2^(m-1) for an m-bit word, and has no positive equivalent;
  1992.      * negating it produces the same value.
  1993.      */
  1994.     if (n == -n) {
  1995. sprintf(buffer, "%ld", n);
  1996. return strlen(buffer);
  1997.     }
  1998.     /*
  1999.      * Generate the characters of the result backwards in the buffer.
  2000.      */
  2001.     intVal = (n < 0? -n : n);
  2002.     i = 0;
  2003.     buffer[0] = '';
  2004.     do {
  2005. i++;
  2006. buffer[i] = digits[intVal % 10];
  2007. intVal = intVal/10;
  2008.     } while (intVal > 0);
  2009.     if (n < 0) {
  2010. i++;
  2011. buffer[i] = '-';
  2012.     }
  2013.     numFormatted = i;
  2014.     /*
  2015.      * Now reverse the characters.
  2016.      */
  2017.     for (j = 0;  j < i;  j++, i--) {
  2018. char tmp = buffer[i];
  2019. buffer[i] = buffer[j];
  2020. buffer[j] = tmp;
  2021.     }
  2022.     return numFormatted;
  2023. }
  2024. /*
  2025.  *----------------------------------------------------------------------
  2026.  *
  2027.  * TclLooksLikeInt --
  2028.  *
  2029.  * This procedure decides whether the leading characters of a
  2030.  * string look like an integer or something else (such as a
  2031.  * floating-point number or string).
  2032.  *
  2033.  * Results:
  2034.  * The return value is 1 if the leading characters of p look
  2035.  * like a valid Tcl integer.  If they look like a floating-point
  2036.  * number (e.g. "e01" or "2.4"), or if they don't look like a
  2037.  * number at all, then 0 is returned.
  2038.  *
  2039.  * Side effects:
  2040.  * None.
  2041.  *
  2042.  *----------------------------------------------------------------------
  2043.  */
  2044. int
  2045. TclLooksLikeInt(bytes, length)
  2046.     register CONST char *bytes; /* Points to first byte of the string. */
  2047.     int length; /* Number of bytes in the string. If < 0
  2048.  * bytes up to the first null byte are
  2049.  * considered (if they may appear in an 
  2050.  * integer). */
  2051. {
  2052.     register CONST char *p;
  2053.     if ((bytes == NULL) && (length > 0)) {
  2054. Tcl_Panic("TclLooksLikeInt: cannot scan %d bytes from NULL", length);
  2055.     }
  2056.     if (length < 0) {
  2057.         length = (bytes? strlen(bytes) : 0);
  2058.     }
  2059.     p = bytes;
  2060.     while (length && isspace(UCHAR(*p))) { /* INTL: ISO space. */
  2061. length--; p++;
  2062.     }
  2063.     if (length == 0) {
  2064.         return 0;
  2065.     }
  2066.     if ((*p == '+') || (*p == '-')) {
  2067.         p++; length--;
  2068.     }
  2069.     return (0 != TclParseInteger(p, length));
  2070. }
  2071. /*
  2072.  *----------------------------------------------------------------------
  2073.  *
  2074.  * TclGetIntForIndex --
  2075.  *
  2076.  * This procedure returns an integer corresponding to the list index
  2077.  * held in a Tcl object. The Tcl object's value is expected to be
  2078.  * either an integer or a string of the form "end([+-]integer)?". 
  2079.  *
  2080.  * Results:
  2081.  * The return value is normally TCL_OK, which means that the index was
  2082.  * successfully stored into the location referenced by "indexPtr".  If
  2083.  * the Tcl object referenced by "objPtr" has the value "end", the
  2084.  * value stored is "endValue". If "objPtr"s values is not of the form
  2085.  * "end([+-]integer)?" and
  2086.  * can not be converted to an integer, TCL_ERROR is returned and, if
  2087.  * "interp" is non-NULL, an error message is left in the interpreter's
  2088.  * result object.
  2089.  *
  2090.  * Side effects:
  2091.  * The object referenced by "objPtr" might be converted to an
  2092.  * integer, wide integer, or end-based-index object.
  2093.  *
  2094.  *----------------------------------------------------------------------
  2095.  */
  2096. int
  2097. TclGetIntForIndex(interp, objPtr, endValue, indexPtr)
  2098.     Tcl_Interp *interp; /* Interpreter to use for error reporting. 
  2099.  * If NULL, then no error message is left
  2100.  * after errors. */
  2101.     Tcl_Obj *objPtr; /* Points to an object containing either
  2102.  * "end" or an integer. */
  2103.     int endValue; /* The value to be stored at "indexPtr" if
  2104.  * "objPtr" holds "end". */
  2105.     int *indexPtr; /* Location filled in with an integer
  2106.  * representing an index. */
  2107. {
  2108.     if (Tcl_GetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) {
  2109. return TCL_OK;
  2110.     }
  2111.     if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
  2112. /*
  2113.  * If the object is already an offset from the end of the
  2114.  * list, or can be converted to one, use it.
  2115.  */
  2116. *indexPtr = endValue + objPtr->internalRep.longValue;
  2117.     } else {
  2118. /*
  2119.  * Report a parse error.
  2120.  */
  2121. if (interp != NULL) {
  2122.     char *bytes = Tcl_GetString(objPtr);
  2123.     /*
  2124.      * The result might not be empty; this resets it which
  2125.      * should be both a cheap operation, and of little problem
  2126.      * because this is an error-generation path anyway.
  2127.      */
  2128.     Tcl_ResetResult(interp);
  2129.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  2130.    "bad index "", bytes,
  2131.    "": must be integer or end?-integer?",
  2132.    (char *) NULL);
  2133.     if (!strncmp(bytes, "end-", 3)) {
  2134. bytes += 3;
  2135.     }
  2136.     TclCheckBadOctal(interp, bytes);
  2137. }
  2138. return TCL_ERROR;
  2139.     }
  2140.     
  2141.     return TCL_OK;
  2142. }
  2143. /*
  2144.  *----------------------------------------------------------------------
  2145.  *
  2146.  * UpdateStringOfEndOffset --
  2147.  *
  2148.  * Update the string rep of a Tcl object holding an "end-offset"
  2149.  * expression.
  2150.  *
  2151.  * Results:
  2152.  * None.
  2153.  *
  2154.  * Side effects:
  2155.  * Stores a valid string in the object's string rep.
  2156.  *
  2157.  * This procedure does NOT free any earlier string rep.  If it is
  2158.  * called on an object that already has a valid string rep, it will
  2159.  * leak memory.
  2160.  *
  2161.  *----------------------------------------------------------------------
  2162.  */
  2163. static void
  2164. UpdateStringOfEndOffset(objPtr)
  2165.     register Tcl_Obj* objPtr;
  2166. {
  2167.     char buffer[TCL_INTEGER_SPACE + sizeof("end") + 1];
  2168.     register int len;
  2169.     strcpy(buffer, "end");
  2170.     len = sizeof("end") - 1;
  2171.     if (objPtr->internalRep.longValue != 0) {
  2172. buffer[len++] = '-';
  2173. len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue));
  2174.     }
  2175.     objPtr->bytes = ckalloc((unsigned) (len+1));
  2176.     strcpy(objPtr->bytes, buffer);
  2177.     objPtr->length = len;
  2178. }
  2179. /*
  2180.  *----------------------------------------------------------------------
  2181.  *
  2182.  * SetEndOffsetFromAny --
  2183.  *
  2184.  * Look for a string of the form "end-offset" and convert it
  2185.  * to an internal representation holding the offset.
  2186.  *
  2187.  * Results:
  2188.  * Returns TCL_OK if ok, TCL_ERROR if the string was badly formed.
  2189.  *
  2190.  * Side effects:
  2191.  * If interp is not NULL, stores an error message in the
  2192.  * interpreter result.
  2193.  *
  2194.  *----------------------------------------------------------------------
  2195.  */
  2196. static int
  2197. SetEndOffsetFromAny(interp, objPtr)
  2198.      Tcl_Interp* interp; /* Tcl interpreter or NULL */
  2199.      Tcl_Obj* objPtr; /* Pointer to the object to parse */
  2200. {
  2201.     int offset; /* Offset in the "end-offset" expression */
  2202.     Tcl_ObjType* oldTypePtr = objPtr->typePtr;
  2203. /* Old internal rep type of the object */
  2204.     register char* bytes; /* String rep of the object */
  2205.     int length; /* Length of the object's string rep */
  2206.     /* If it's already the right type, we're fine. */
  2207.     if (objPtr->typePtr == &tclEndOffsetType) {
  2208. return TCL_OK;
  2209.     }
  2210.     /* Check for a string rep of the right form. */
  2211.     bytes = Tcl_GetStringFromObj(objPtr, &length);
  2212.     if ((*bytes != 'e') || (strncmp(bytes, "end",
  2213.     (size_t)((length > 3) ? 3 : length)) != 0)) {
  2214. if (interp != NULL) {
  2215.     Tcl_ResetResult(interp);
  2216.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  2217.    "bad index "", bytes,
  2218.    "": must be end?-integer?",
  2219.    (char*) NULL);
  2220. }
  2221. return TCL_ERROR;
  2222.     }
  2223.     /* Convert the string rep */
  2224.     if (length <= 3) {
  2225. offset = 0;
  2226.     } else if ((length > 4) && (bytes[3] == '-')) {
  2227. /*
  2228.  * This is our limited string expression evaluator.  Pass everything
  2229.  * after "end-" to Tcl_GetInt, then reverse for offset.
  2230.  */
  2231. if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
  2232.     return TCL_ERROR;
  2233. }
  2234. offset = -offset;
  2235.     } else {
  2236. /*
  2237.  * Conversion failed.  Report the error.
  2238.  */
  2239. if (interp != NULL) {
  2240.     Tcl_ResetResult(interp);
  2241.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  2242.    "bad index "", bytes,
  2243.    "": must be integer or end?-integer?",
  2244.    (char *) NULL);
  2245. }
  2246. return TCL_ERROR;
  2247.     }
  2248.     /*
  2249.      * The conversion succeeded. Free the old internal rep and set
  2250.      * the new one.
  2251.      */
  2252.     if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
  2253. oldTypePtr->freeIntRepProc(objPtr);
  2254.     }
  2255.     
  2256.     objPtr->internalRep.longValue = offset;
  2257.     objPtr->typePtr = &tclEndOffsetType;
  2258.     return TCL_OK;
  2259. }    
  2260. /*
  2261.  *----------------------------------------------------------------------
  2262.  *
  2263.  * TclCheckBadOctal --
  2264.  *
  2265.  * This procedure checks for a bad octal value and appends a
  2266.  * meaningful error to the interp's result.
  2267.  *
  2268.  * Results:
  2269.  * 1 if the argument was a bad octal, else 0.
  2270.  *
  2271.  * Side effects:
  2272.  * The interpreter's result is modified.
  2273.  *
  2274.  *----------------------------------------------------------------------
  2275.  */
  2276. int
  2277. TclCheckBadOctal(interp, value)
  2278.     Tcl_Interp *interp; /* Interpreter to use for error reporting. 
  2279.  * If NULL, then no error message is left
  2280.  * after errors. */
  2281.     CONST char *value; /* String to check. */
  2282. {
  2283.     register CONST char *p = value;
  2284.     /*
  2285.      * A frequent mistake is invalid octal values due to an unwanted
  2286.      * leading zero. Try to generate a meaningful error message.
  2287.      */
  2288.     while (isspace(UCHAR(*p))) { /* INTL: ISO space. */
  2289. p++;
  2290.     }
  2291.     if (*p == '+' || *p == '-') {
  2292. p++;
  2293.     }
  2294.     if (*p == '0') {
  2295. while (isdigit(UCHAR(*p))) { /* INTL: digit. */
  2296.     p++;
  2297. }
  2298. while (isspace(UCHAR(*p))) { /* INTL: ISO space. */
  2299.     p++;
  2300. }
  2301. if (*p == '') {
  2302.     /* Reached end of string */
  2303.     if (interp != NULL) {
  2304. /*
  2305.  * Don't reset the result here because we want this result
  2306.  * to be added to an existing error message as extra info.
  2307.  */
  2308. Tcl_AppendResult(interp, " (looks like invalid octal number)",
  2309. (char *) NULL);
  2310.     }
  2311.     return 1;
  2312. }
  2313.     }
  2314.     return 0;
  2315. }
  2316. /*
  2317.  *----------------------------------------------------------------------
  2318.  *
  2319.  * Tcl_GetNameOfExecutable --
  2320.  *
  2321.  * This procedure simply returns a pointer to the internal full
  2322.  * path name of the executable file as computed by
  2323.  * Tcl_FindExecutable.  This procedure call is the C API
  2324.  * equivalent to the "info nameofexecutable" command.
  2325.  *
  2326.  * Results:
  2327.  * A pointer to the internal string or NULL if the internal full
  2328.  * path name has not been computed or unknown.
  2329.  *
  2330.  * Side effects:
  2331.  * The object referenced by "objPtr" might be converted to an
  2332.  * integer object.
  2333.  *
  2334.  *----------------------------------------------------------------------
  2335.  */
  2336. CONST char *
  2337. Tcl_GetNameOfExecutable()
  2338. {
  2339.     return tclExecutableName;
  2340. }
  2341. /*
  2342.  *----------------------------------------------------------------------
  2343.  *
  2344.  * TclpGetTime --
  2345.  *
  2346.  * Deprecated synonym for Tcl_GetTime.
  2347.  *
  2348.  * Results:
  2349.  * None.
  2350.  *
  2351.  * Side effects:
  2352.  * Stores current time in the buffer designated by "timePtr"
  2353.  *
  2354.  * This procedure is provided for the benefit of extensions written
  2355.  * before Tcl_GetTime was exported from the library.
  2356.  *
  2357.  *----------------------------------------------------------------------
  2358.  */
  2359. void
  2360. TclpGetTime(timePtr)
  2361.     Tcl_Time* timePtr;
  2362. {
  2363.     Tcl_GetTime(timePtr);
  2364. }