home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume25 / tcl / part29 < prev    next >
Encoding:
Text File  |  1991-11-15  |  39.1 KB  |  1,483 lines

  1. Newsgroups: comp.sources.misc
  2. From: karl@sugar.neosoft.com (Karl Lehenbauer)
  3. Subject:  v25i097:  tcl - tool command language, version 6.1, Part29/33
  4. Message-ID: <1991Nov15.225911.21999@sparky.imd.sterling.com>
  5. X-Md4-Signature: 68b025872ee4e8c0dc5ec1b697e8a88e
  6. Date: Fri, 15 Nov 1991 22:59:11 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
  10. Posting-number: Volume 25, Issue 97
  11. Archive-name: tcl/part29
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 29 (of 33)."
  21. # Contents:  tcl6.1/tclUtil.c
  22. # Wrapped by karl@one on Tue Nov 12 19:44:31 1991
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'tcl6.1/tclUtil.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'tcl6.1/tclUtil.c'\"
  26. else
  27. echo shar: Extracting \"'tcl6.1/tclUtil.c'\" \(36390 characters\)
  28. sed "s/^X//" >'tcl6.1/tclUtil.c' <<'END_OF_FILE'
  29. X/* 
  30. X * tclUtil.c --
  31. X *
  32. X *    This file contains utility procedures that are used by many Tcl
  33. X *    commands.
  34. X *
  35. X * Copyright 1987-1991 Regents of the University of California
  36. X * Permission to use, copy, modify, and distribute this
  37. X * software and its documentation for any purpose and without
  38. X * fee is hereby granted, provided that the above copyright
  39. X * notice appear in all copies.  The University of California
  40. X * makes no representations about the suitability of this
  41. X * software for any purpose.  It is provided "as is" without
  42. X * express or implied warranty.
  43. X */
  44. X
  45. X#ifndef lint
  46. Xstatic char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclUtil.c,v 1.60 91/10/17 15:49:56 ouster Exp $ SPRITE (Berkeley)";
  47. X#endif
  48. X
  49. X#include "tclInt.h"
  50. X
  51. X/*
  52. X * The following values are used in the flags returned by Tcl_ScanElement
  53. X * and used by Tcl_ConvertElement.
  54. X */
  55. X
  56. X#define USE_BRACES        1
  57. X#define CANT_USE_BRACES        2
  58. X
  59. X/*
  60. X * The variable below is set to NULL before invoking regexp functions
  61. X * and checked after those functions.  If an error occurred then regerror
  62. X * will set the variable to point to a (static) error message.  This
  63. X * mechanism unfortunately does not support multi-threading, but then
  64. X * neither does the rest of the regexp facilities.
  65. X */
  66. X
  67. Xchar *tclRegexpError = NULL;
  68. X
  69. X/*
  70. X * Function prototypes for local procedures in this file:
  71. X */
  72. X
  73. Xstatic void        SetupAppendBuffer _ANSI_ARGS_((Interp *iPtr,
  74. X                int newSpace));
  75. X
  76. X/*
  77. X *----------------------------------------------------------------------
  78. X *
  79. X * TclFindElement --
  80. X *
  81. X *    Given a pointer into a Tcl list, locate the first (or next)
  82. X *    element in the list.
  83. X *
  84. X * Results:
  85. X *    The return value is normally TCL_OK, which means that the
  86. X *    element was successfully located.  If TCL_ERROR is returned
  87. X *    it means that list didn't have proper list structure;
  88. X *    interp->result contains a more detailed error message.
  89. X *
  90. X *    If TCL_OK is returned, then *elementPtr will be set to point
  91. X *    to the first element of list, and *nextPtr will be set to point
  92. X *    to the character just after any white space following the last
  93. X *    character that's part of the element.  If this is the last argument
  94. X *    in the list, then *nextPtr will point to the NULL character at the
  95. X *    end of list.  If sizePtr is non-NULL, *sizePtr is filled in with
  96. X *    the number of characters in the element.  If the element is in
  97. X *    braces, then *elementPtr will point to the character after the
  98. X *    opening brace and *sizePtr will not include either of the braces.
  99. X *    If there isn't an element in the list, *sizePtr will be zero, and
  100. X *    both *elementPtr and *termPtr will refer to the null character at
  101. X *    the end of list.  Note:  this procedure does NOT collapse backslash
  102. X *    sequences.
  103. X *
  104. X * Side effects:
  105. X *    None.
  106. X *
  107. X *----------------------------------------------------------------------
  108. X */
  109. X
  110. Xint
  111. XTclFindElement(interp, list, elementPtr, nextPtr, sizePtr, bracePtr)
  112. X    Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  113. X    register char *list;    /* String containing Tcl list with zero
  114. X                 * or more elements (possibly in braces). */
  115. X    char **elementPtr;        /* Fill in with location of first significant
  116. X                 * character in first element of list. */
  117. X    char **nextPtr;        /* Fill in with location of character just
  118. X                 * after all white space following end of
  119. X                 * argument (i.e. next argument or end of
  120. X                 * list). */
  121. X    int *sizePtr;        /* If non-zero, fill in with size of
  122. X                 * element. */
  123. X    int *bracePtr;        /* If non-zero fill in with non-zero/zero
  124. X                 * to indicate that arg was/wasn't
  125. X                 * in braces. */
  126. X{
  127. X    register char *p;
  128. X    int openBraces = 0;
  129. X    int inQuotes = 0;
  130. X    int size;
  131. X
  132. X    /*
  133. X     * Skim off leading white space and check for an opening brace or
  134. X     * quote.   Note:  use of "isascii" below and elsewhere in this
  135. X     * procedure is a temporary hack (7/27/90) because Mx uses characters
  136. X     * with the high-order bit set for some things.  This should probably
  137. X     * be changed back eventually, or all of Tcl should call isascii.
  138. X     */
  139. X
  140. X    while (isascii(*list) && isspace(*list)) {
  141. X    list++;
  142. X    }
  143. X    if (*list == '{') {
  144. X    openBraces = 1;
  145. X    list++;
  146. X    } else if (*list == '"') {
  147. X    inQuotes = 1;
  148. X    list++;
  149. X    }
  150. X    if (bracePtr != 0) {
  151. X    *bracePtr = openBraces;
  152. X    }
  153. X    p = list;
  154. X
  155. X    /*
  156. X     * Find the end of the element (either a space or a close brace or
  157. X     * the end of the string).
  158. X     */
  159. X
  160. X    while (1) {
  161. X    switch (*p) {
  162. X
  163. X        /*
  164. X         * Open brace: don't treat specially unless the element is
  165. X         * in braces.  In this case, keep a nesting count.
  166. X         */
  167. X
  168. X        case '{':
  169. X        if (openBraces != 0) {
  170. X            openBraces++;
  171. X        }
  172. X        break;
  173. X
  174. X        /*
  175. X         * Close brace: if element is in braces, keep nesting
  176. X         * count and quit when the last close brace is seen.
  177. X         */
  178. X
  179. X        case '}':
  180. X        if (openBraces == 1) {
  181. X            char *p2;
  182. X
  183. X            size = p - list;
  184. X            p++;
  185. X            if ((isascii(*p) && isspace(*p)) || (*p == 0)) {
  186. X            goto done;
  187. X            }
  188. X            for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
  189. X                p2++) {
  190. X            /* null body */
  191. X            }
  192. X            Tcl_ResetResult(interp);
  193. X            sprintf(interp->result,
  194. X                "list element in braces followed by \"%.*s\" instead of space",
  195. X                p2-p, p);
  196. X            return TCL_ERROR;
  197. X        } else if (openBraces != 0) {
  198. X            openBraces--;
  199. X        }
  200. X        break;
  201. X
  202. X        /*
  203. X         * Backslash:  skip over everything up to the end of the
  204. X         * backslash sequence.
  205. X         */
  206. X
  207. X        case '\\': {
  208. X        int size;
  209. X
  210. X        (void) Tcl_Backslash(p, &size);
  211. X        p += size - 1;
  212. X        break;
  213. X        }
  214. X
  215. X        /*
  216. X         * Space: ignore if element is in braces or quotes;  otherwise
  217. X         * terminate element.
  218. X         */
  219. X
  220. X        case ' ':
  221. X        case '\f':
  222. X        case '\n':
  223. X        case '\r':
  224. X        case '\t':
  225. X        case '\v':
  226. X        if ((openBraces == 0) && !inQuotes) {
  227. X            size = p - list;
  228. X            goto done;
  229. X        }
  230. X        break;
  231. X
  232. X        /*
  233. X         * Double-quote:  if element is in quotes then terminate it.
  234. X         */
  235. X
  236. X        case '"':
  237. X        if (inQuotes) {
  238. X            char *p2;
  239. X
  240. X            size = p-list;
  241. X            p++;
  242. X            if ((isascii(*p) && isspace(*p)) || (*p == 0)) {
  243. X            goto done;
  244. X            }
  245. X            for (p2 = p; (*p2 != 0) && (!isspace(*p2)) && (p2 < p+20);
  246. X                p2++) {
  247. X            /* null body */
  248. X            }
  249. X            Tcl_ResetResult(interp);
  250. X            sprintf(interp->result,
  251. X                "list element in quotes followed by \"%.*s\" %s",
  252. X                p2-p, p, "instead of space");
  253. X            return TCL_ERROR;
  254. X        }
  255. X        break;
  256. X
  257. X        /*
  258. X         * End of list:  terminate element.
  259. X         */
  260. X
  261. X        case 0:
  262. X        if (openBraces != 0) {
  263. X            Tcl_SetResult(interp, "unmatched open brace in list",
  264. X                TCL_STATIC);
  265. X            return TCL_ERROR;
  266. X        } else if (inQuotes) {
  267. X            Tcl_SetResult(interp, "unmatched open quote in list",
  268. X                TCL_STATIC);
  269. X            return TCL_ERROR;
  270. X        }
  271. X        size = p - list;
  272. X        goto done;
  273. X
  274. X    }
  275. X    p++;
  276. X    }
  277. X
  278. X    done:
  279. X    while (isascii(*p) && isspace(*p)) {
  280. X    p++;
  281. X    }
  282. X    *elementPtr = list;
  283. X    *nextPtr = p;
  284. X    if (sizePtr != 0) {
  285. X    *sizePtr = size;
  286. X    }
  287. X    return TCL_OK;
  288. X}
  289. X
  290. X/*
  291. X *----------------------------------------------------------------------
  292. X *
  293. X * TclCopyAndCollapse --
  294. X *
  295. X *    Copy a string and eliminate any backslashes that aren't in braces.
  296. X *
  297. X * Results:
  298. X *    There is no return value.  Count chars. get copied from src
  299. X *    to dst.  Along the way, if backslash sequences are found outside
  300. X *    braces, the backslashes are eliminated in the copy.
  301. X *    After scanning count chars. from source, a null character is
  302. X *    placed at the end of dst.
  303. X *
  304. X * Side effects:
  305. X *    None.
  306. X *
  307. X *----------------------------------------------------------------------
  308. X */
  309. X
  310. Xvoid
  311. XTclCopyAndCollapse(count, src, dst)
  312. X    int count;            /* Total number of characters to copy
  313. X                 * from src. */
  314. X    register char *src;        /* Copy from here... */
  315. X    register char *dst;        /* ... to here. */
  316. X{
  317. X    register char c;
  318. X    int numRead;
  319. X
  320. X    for (c = *src; count > 0; src++, c = *src, count--) {
  321. X    if (c == '\\') {
  322. X        *dst = Tcl_Backslash(src, &numRead);
  323. X        if (*dst != 0) {
  324. X        dst++;
  325. X        }
  326. X        src += numRead-1;
  327. X        count -= numRead-1;
  328. X    } else {
  329. X        *dst = c;
  330. X        dst++;
  331. X    }
  332. X    }
  333. X    *dst = 0;
  334. X}
  335. X
  336. X/*
  337. X *----------------------------------------------------------------------
  338. X *
  339. X * Tcl_SplitList --
  340. X *
  341. X *    Splits a list up into its constituent fields.
  342. X *
  343. X * Results
  344. X *    The return value is normally TCL_OK, which means that
  345. X *    the list was successfully split up.  If TCL_ERROR is
  346. X *    returned, it means that "list" didn't have proper list
  347. X *    structure;  interp->result will contain a more detailed
  348. X *    error message.
  349. X *
  350. X *    *argvPtr will be filled in with the address of an array
  351. X *    whose elements point to the elements of list, in order.
  352. X *    *argcPtr will get filled in with the number of valid elements
  353. X *    in the array.  A single block of memory is dynamically allocated
  354. X *    to hold both the argv array and a copy of the list (with
  355. X *    backslashes and braces removed in the standard way).
  356. X *    The caller must eventually free this memory by calling free()
  357. X *    on *argvPtr.  Note:  *argvPtr and *argcPtr are only modified
  358. X *    if the procedure returns normally.
  359. X *
  360. X * Side effects:
  361. X *    Memory is allocated.
  362. X *
  363. X *----------------------------------------------------------------------
  364. X */
  365. X
  366. Xint
  367. XTcl_SplitList(interp, list, argcPtr, argvPtr)
  368. X    Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  369. X    char *list;            /* Pointer to string with list structure. */
  370. X    int *argcPtr;        /* Pointer to location to fill in with
  371. X                 * the number of elements in the list. */
  372. X    char ***argvPtr;        /* Pointer to place to store pointer to array
  373. X                 * of pointers to list elements. */
  374. X{
  375. X    char **argv;
  376. X    register char *p;
  377. X    int size, i, result, elSize, brace;
  378. X    char *element;
  379. X
  380. X    /*
  381. X     * Figure out how much space to allocate.  There must be enough
  382. X     * space for both the array of pointers and also for a copy of
  383. X     * the list.  To estimate the number of pointers needed, count
  384. X     * the number of space characters in the list.
  385. X     */
  386. X
  387. X    for (size = 1, p = list; *p != 0; p++) {
  388. X    if (isspace(*p)) {
  389. X        size++;
  390. X    }
  391. X    }
  392. X    size++;            /* Leave space for final NULL pointer. */
  393. X    argv = (char **) ckalloc((unsigned)
  394. X        ((size * sizeof(char *)) + (p - list) + 1));
  395. X    for (i = 0, p = ((char *) argv) + size*sizeof(char *);
  396. X        *list != 0; i++) {
  397. X    result = TclFindElement(interp, list, &element, &list, &elSize, &brace);
  398. X    if (result != TCL_OK) {
  399. X        ckfree((char *) argv);
  400. X        return result;
  401. X    }
  402. X    if (*element == 0) {
  403. X        break;
  404. X    }
  405. X    if (i >= size) {
  406. X        ckfree((char *) argv);
  407. X        Tcl_SetResult(interp, "internal error in Tcl_SplitList",
  408. X            TCL_STATIC);
  409. X        return TCL_ERROR;
  410. X    }
  411. X    argv[i] = p;
  412. X    if (brace) {
  413. X        strncpy(p, element, elSize);
  414. X        p += elSize;
  415. X        *p = 0;
  416. X        p++;
  417. X    } else {
  418. X        TclCopyAndCollapse(elSize, element, p);
  419. X        p += elSize+1;
  420. X    }
  421. X    }
  422. X
  423. X    argv[i] = NULL;
  424. X    *argvPtr = argv;
  425. X    *argcPtr = i;
  426. X    return TCL_OK;
  427. X}
  428. X
  429. X/*
  430. X *----------------------------------------------------------------------
  431. X *
  432. X * Tcl_ScanElement --
  433. X *
  434. X *    This procedure is a companion procedure to Tcl_ConvertElement.
  435. X *    It scans a string to see what needs to be done to it (e.g.
  436. X *    add backslashes or enclosing braces) to make the string into
  437. X *    a valid Tcl list element.
  438. X *
  439. X * Results:
  440. X *    The return value is an overestimate of the number of characters
  441. X *    that will be needed by Tcl_ConvertElement to produce a valid
  442. X *    list element from string.  The word at *flagPtr is filled in
  443. X *    with a value needed by Tcl_ConvertElement when doing the actual
  444. X *    conversion.
  445. X *
  446. X * Side effects:
  447. X *    None.
  448. X *
  449. X *----------------------------------------------------------------------
  450. X */
  451. X
  452. Xint
  453. XTcl_ScanElement(string, flagPtr)
  454. X    char *string;        /* String to convert to Tcl list element. */
  455. X    int *flagPtr;        /* Where to store information to guide
  456. X                 * Tcl_ConvertElement. */
  457. X{
  458. X    int flags, nestingLevel;
  459. X    register char *p;
  460. X
  461. X    /*
  462. X     * This procedure and Tcl_ConvertElement together do two things:
  463. X     *
  464. X     * 1. They produces a proper list, one that will yield back the
  465. X     * argument strings when evaluated or when disassembled with
  466. X     * Tcl_SplitList.  This is the most important thing.
  467. X     * 
  468. X     * 2. They try to produce legible output, which means minimizing the
  469. X     * use of backslashes (using braces instead).  However, there are
  470. X     * some situations where backslashes must be used (e.g. an element
  471. X     * like "{abc": the leading brace will have to be backslashed.  For
  472. X     * each element, one of three things must be done:
  473. X     *
  474. X     * (a) Use the element as-is (it doesn't contain anything special
  475. X     * characters).  This is the most desirable option.
  476. X     *
  477. X     * (b) Enclose the element in braces, but leave the contents alone.
  478. X     * This happens if the element contains embedded space, or if it
  479. X     * contains characters with special interpretation ($, [, ;, or \),
  480. X     * or if it starts with a brace or double-quote, or if there are
  481. X     * no characters in the element.
  482. X     *
  483. X     * (c) Don't enclose the element in braces, but add backslashes to
  484. X     * prevent special interpretation of special characters.  This is a
  485. X     * last resort used when the argument would normally fall under case
  486. X     * (b) but contains unmatched braces.  It also occurs if the last
  487. X     * character of the argument is a backslash.
  488. X     *
  489. X     * The procedure figures out how many bytes will be needed to store
  490. X     * the result (actually, it overestimates).  It also collects information
  491. X     * about the element in the form of a flags word.
  492. X     */
  493. X
  494. X    nestingLevel = 0;
  495. X    flags = 0;
  496. X    p = string;
  497. X    if ((*p == '{') || (*p == '"') || (*p == 0)) {
  498. X    flags |= USE_BRACES;
  499. X    }
  500. X    for ( ; *p != 0; p++) {
  501. X    switch (*p) {
  502. X        case '{':
  503. X        nestingLevel++;
  504. X        break;
  505. X        case '}':
  506. X        nestingLevel--;
  507. X        if (nestingLevel < 0) {
  508. X            flags |= CANT_USE_BRACES;
  509. X        }
  510. X        break;
  511. X        case '[':
  512. X        case '$':
  513. X        case ';':
  514. X        case ' ':
  515. X        case '\f':
  516. X        case '\n':
  517. X        case '\r':
  518. X        case '\t':
  519. X        case '\v':
  520. X        flags |= USE_BRACES;
  521. X        break;
  522. X        case '\\':
  523. X        if (p[1] == 0) {
  524. X            flags = CANT_USE_BRACES;
  525. X        } else {
  526. X            int size;
  527. X
  528. X            (void) Tcl_Backslash(p, &size);
  529. X            p += size-1;
  530. X            flags |= USE_BRACES;
  531. X        }
  532. X        break;
  533. X    }
  534. X    }
  535. X    if ((nestingLevel != 0) || (flags & CANT_USE_BRACES)) {
  536. X    flags = CANT_USE_BRACES;
  537. X    }
  538. X    *flagPtr = flags;
  539. X
  540. X    /*
  541. X     * Allow enough space to backslash every character plus leave
  542. X     * two spaces for braces.
  543. X     */
  544. X
  545. X    return 2*(p-string) + 2;
  546. X}
  547. X
  548. X/*
  549. X *----------------------------------------------------------------------
  550. X *
  551. X * Tcl_ConvertElement --
  552. X *
  553. X *    This is a companion procedure to Tcl_ScanElement.  Given the
  554. X *    information produced by Tcl_ScanElement, this procedure converts
  555. X *    a string to a list element equal to that string.
  556. X *
  557. X * Results:
  558. X *    Information is copied to *dst in the form of a list element
  559. X *    identical to src (i.e. if Tcl_SplitList is applied to dst it
  560. X *    will produce a string identical to src).  The return value is
  561. X *    a count of the number of characters copied (not including the
  562. X *    terminating NULL character).
  563. X *
  564. X * Side effects:
  565. X *    None.
  566. X *
  567. X *----------------------------------------------------------------------
  568. X */
  569. X
  570. Xint
  571. XTcl_ConvertElement(src, dst, flags)
  572. X    register char *src;        /* Source information for list element. */
  573. X    char *dst;            /* Place to put list-ified element. */
  574. X    int flags;            /* Flags produced by Tcl_ScanElement. */
  575. X{
  576. X    register char *p = dst;
  577. X
  578. X    /*
  579. X     * See the comment block at the beginning of the Tcl_ScanElement
  580. X     * code for details of how this works.
  581. X     */
  582. X
  583. X    if (flags & USE_BRACES) {
  584. X    *p = '{';
  585. X    p++;
  586. X    for ( ; *src != 0; src++, p++) {
  587. X        *p = *src;
  588. X    }
  589. X    *p = '}';
  590. X    p++;
  591. X    } else {
  592. X    /*
  593. X     * Must backslash a leading open brace, but after that don't
  594. X     * need to worry about either open or close braces.
  595. X     */
  596. X
  597. X    if (*src == '{') {
  598. X        *p = '\\';
  599. X        p++;
  600. X    }
  601. X    for (; *src != 0 ; src++) {
  602. X        switch (*src) {
  603. X        case ']':
  604. X        case '[':
  605. X        case '$':
  606. X        case ';':
  607. X        case ' ':
  608. X        case '\\':
  609. X            *p = '\\';
  610. X            p++;
  611. X            break;
  612. X        case '\f':
  613. X            *p = '\\';
  614. X            p++;
  615. X            *p = 'f';
  616. X            p++;
  617. X            continue;
  618. X        case '\n':
  619. X            *p = '\\';
  620. X            p++;
  621. X            *p = 'n';
  622. X            p++;
  623. X            continue;
  624. X        case '\r':
  625. X            *p = '\\';
  626. X            p++;
  627. X            *p = 'r';
  628. X            p++;
  629. X            continue;
  630. X        case '\t':
  631. X            *p = '\\';
  632. X            p++;
  633. X            *p = 't';
  634. X            p++;
  635. X            continue;
  636. X        case '\v':
  637. X            *p = '\\';
  638. X            p++;
  639. X            *p = 'v';
  640. X            p++;
  641. X            continue;
  642. X        }
  643. X        *p = *src;
  644. X        p++;
  645. X    }
  646. X    }
  647. X    *p = '\0';
  648. X    return p-dst;
  649. X}
  650. X
  651. X/*
  652. X *----------------------------------------------------------------------
  653. X *
  654. X * Tcl_Merge --
  655. X *
  656. X *    Given a collection of strings, merge them together into a
  657. X *    single string that has proper Tcl list structured (i.e.
  658. X *    Tcl_SplitList may be used to retrieve strings equal to the
  659. X *    original elements, and Tcl_Eval will parse the string back
  660. X *    into its original elements).
  661. X *
  662. X * Results:
  663. X *    The return value is the address of a dynamically-allocated
  664. X *    string containing the merged list.
  665. X *
  666. X * Side effects:
  667. X *    None.
  668. X *
  669. X *----------------------------------------------------------------------
  670. X */
  671. X
  672. Xchar *
  673. XTcl_Merge(argc, argv)
  674. X    int argc;            /* How many strings to merge. */
  675. X    char **argv;        /* Array of string values. */
  676. X{
  677. X#   define LOCAL_SIZE 20
  678. X    int localFlags[LOCAL_SIZE], *flagPtr;
  679. X    int numChars;
  680. X    char *result;
  681. X    register char *dst;
  682. X    int i;
  683. X
  684. X    /*
  685. X     * Pass 1: estimate space, gather flags.
  686. X     */
  687. X
  688. X    if (argc <= LOCAL_SIZE) {
  689. X    flagPtr = localFlags;
  690. X    } else {
  691. X    flagPtr = (int *) ckalloc((unsigned) argc*sizeof(int));
  692. X    }
  693. X    numChars = 1;
  694. X    for (i = 0; i < argc; i++) {
  695. X    numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;
  696. X    }
  697. X
  698. X    /*
  699. X     * Pass two: copy into the result area.
  700. X     */
  701. X
  702. X    result = (char *) ckalloc((unsigned) numChars);
  703. X    dst = result;
  704. X    for (i = 0; i < argc; i++) {
  705. X    numChars = Tcl_ConvertElement(argv[i], dst, flagPtr[i]);
  706. X    dst += numChars;
  707. X    *dst = ' ';
  708. X    dst++;
  709. X    }
  710. X    if (dst == result) {
  711. X    *dst = 0;
  712. X    } else {
  713. X    dst[-1] = 0;
  714. X    }
  715. X
  716. X    if (flagPtr != localFlags) {
  717. X    ckfree((char *) flagPtr);
  718. X    }
  719. X    return result;
  720. X}
  721. X
  722. X/*
  723. X *----------------------------------------------------------------------
  724. X *
  725. X * Tcl_Concat --
  726. X *
  727. X *    Concatenate a set of strings into a single large string.
  728. X *
  729. X * Results:
  730. X *    The return value is dynamically-allocated string containing
  731. X *    a concatenation of all the strings in argv, with spaces between
  732. X *    the original argv elements.
  733. X *
  734. X * Side effects:
  735. X *    Memory is allocated for the result;  the caller is responsible
  736. X *    for freeing the memory.
  737. X *
  738. X *----------------------------------------------------------------------
  739. X */
  740. X
  741. Xchar *
  742. XTcl_Concat(argc, argv)
  743. X    int argc;            /* Number of strings to concatenate. */
  744. X    char **argv;        /* Array of strings to concatenate. */
  745. X{
  746. X    int totalSize, i;
  747. X    register char *p;
  748. X    char *result;
  749. X
  750. X    for (totalSize = 1, i = 0; i < argc; i++) {
  751. X    totalSize += strlen(argv[i]) + 1;
  752. X    }
  753. X    result = (char *) ckalloc((unsigned) totalSize);
  754. X    if (argc == 0) {
  755. X    *result = '\0';
  756. X    return result;
  757. X    }
  758. X    for (p = result, i = 0; i < argc; i++) {
  759. X    char *element;
  760. X    int length;
  761. X
  762. X    /*
  763. X     * Clip white space off the front and back of the string
  764. X     * to generate a neater result, and ignore any empty
  765. X     * elements.
  766. X     */
  767. X
  768. X    element = argv[i];
  769. X    while (isspace(*element)) {
  770. X        element++;
  771. X    }
  772. X    for (length = strlen(element);
  773. X        (length > 0) && (isspace(element[length-1]));
  774. X        length--) {
  775. X        /* Null loop body. */
  776. X    }
  777. X    if (length == 0) {
  778. X        continue;
  779. X    }
  780. X    (void) strncpy(p, element, length);
  781. X    p += length;
  782. X    *p = ' ';
  783. X    p++;
  784. X    }
  785. X    if (p != result) {
  786. X    p[-1] = 0;
  787. X    } else {
  788. X    *p = 0;
  789. X    }
  790. X    return result;
  791. X}
  792. X
  793. X/*
  794. X *----------------------------------------------------------------------
  795. X *
  796. X * Tcl_StringMatch --
  797. X *
  798. X *    See if a particular string matches a particular pattern.
  799. X *
  800. X * Results:
  801. X *    The return value is 1 if string matches pattern, and
  802. X *    0 otherwise.  The matching operation permits the following
  803. X *    special characters in the pattern: *?\[] (see the manual
  804. X *    entry for details on what these mean).
  805. X *
  806. X * Side effects:
  807. X *    None.
  808. X *
  809. X *----------------------------------------------------------------------
  810. X */
  811. X
  812. Xint
  813. XTcl_StringMatch(string, pattern)
  814. X    register char *string;    /* String. */
  815. X    register char *pattern;    /* Pattern, which may contain
  816. X                 * special characters. */
  817. X{
  818. X    char c2;
  819. X
  820. X    while (1) {
  821. X    /* See if we're at the end of both the pattern and the string.
  822. X     * If so, we succeeded.  If we're at the end of the pattern
  823. X     * but not at the end of the string, we failed.
  824. X     */
  825. X    
  826. X    if (*pattern == 0) {
  827. X        if (*string == 0) {
  828. X        return 1;
  829. X        } else {
  830. X        return 0;
  831. X        }
  832. X    }
  833. X    if ((*string == 0) && (*pattern != '*')) {
  834. X        return 0;
  835. X    }
  836. X
  837. X    /* Check for a "*" as the next pattern character.  It matches
  838. X     * any substring.  We handle this by calling ourselves
  839. X     * recursively for each postfix of string, until either we
  840. X     * match or we reach the end of the string.
  841. X     */
  842. X    
  843. X    if (*pattern == '*') {
  844. X        pattern += 1;
  845. X        if (*pattern == 0) {
  846. X        return 1;
  847. X        }
  848. X        while (*string != 0) {
  849. X        if (Tcl_StringMatch(string, pattern)) {
  850. X            return 1;
  851. X        }
  852. X        string += 1;
  853. X        }
  854. X        return 0;
  855. X    }
  856. X    
  857. X    /* Check for a "?" as the next pattern character.  It matches
  858. X     * any single character.
  859. X     */
  860. X
  861. X    if (*pattern == '?') {
  862. X        goto thisCharOK;
  863. X    }
  864. X
  865. X    /* Check for a "[" as the next pattern character.  It is followed
  866. X     * by a list of characters that are acceptable, or by a range
  867. X     * (two characters separated by "-").
  868. X     */
  869. X    
  870. X    if (*pattern == '[') {
  871. X        pattern += 1;
  872. X        while (1) {
  873. X        if ((*pattern == ']') || (*pattern == 0)) {
  874. X            return 0;
  875. X        }
  876. X        if (*pattern == *string) {
  877. X            break;
  878. X        }
  879. X        if (pattern[1] == '-') {
  880. X            c2 = pattern[2];
  881. X            if (c2 == 0) {
  882. X            return 0;
  883. X            }
  884. X            if ((*pattern <= *string) && (c2 >= *string)) {
  885. X            break;
  886. X            }
  887. X            if ((*pattern >= *string) && (c2 <= *string)) {
  888. X            break;
  889. X            }
  890. X            pattern += 2;
  891. X        }
  892. X        pattern += 1;
  893. X        }
  894. X        while ((*pattern != ']') && (*pattern != 0)) {
  895. X        pattern += 1;
  896. X        }
  897. X        goto thisCharOK;
  898. X    }
  899. X    
  900. X    /* If the next pattern character is '/', just strip off the '/'
  901. X     * so we do exact matching on the character that follows.
  902. X     */
  903. X    
  904. X    if (*pattern == '\\') {
  905. X        pattern += 1;
  906. X        if (*pattern == 0) {
  907. X        return 0;
  908. X        }
  909. X    }
  910. X
  911. X    /* There's no special character.  Just make sure that the next
  912. X     * characters of each string match.
  913. X     */
  914. X    
  915. X    if (*pattern != *string) {
  916. X        return 0;
  917. X    }
  918. X
  919. X    thisCharOK: pattern += 1;
  920. X    string += 1;
  921. X    }
  922. X}
  923. X
  924. X/*
  925. X *----------------------------------------------------------------------
  926. X *
  927. X * Tcl_SetResult --
  928. X *
  929. X *    Arrange for "string" to be the Tcl return value.
  930. X *
  931. X * Results:
  932. X *    None.
  933. X *
  934. X * Side effects:
  935. X *    interp->result is left pointing either to "string" (if "copy" is 0)
  936. X *    or to a copy of string.
  937. X *
  938. X *----------------------------------------------------------------------
  939. X */
  940. X
  941. Xvoid
  942. XTcl_SetResult(interp, string, freeProc)
  943. X    Tcl_Interp *interp;        /* Interpreter with which to associate the
  944. X                 * return value. */
  945. X    char *string;        /* Value to be returned.  If NULL,
  946. X                 * the result is set to an empty string. */
  947. X    Tcl_FreeProc *freeProc;    /* Gives information about the string:
  948. X                 * TCL_STATIC, TCL_VOLATILE, or the address
  949. X                 * of a Tcl_FreeProc such as free. */
  950. X{
  951. X    register Interp *iPtr = (Interp *) interp;
  952. X    int length;
  953. X    Tcl_FreeProc *oldFreeProc = iPtr->freeProc;
  954. X    char *oldResult = iPtr->result;
  955. X
  956. X    iPtr->freeProc = freeProc;
  957. X    if (string == NULL) {
  958. X    iPtr->resultSpace[0] = 0;
  959. X    iPtr->result = iPtr->resultSpace;
  960. X    iPtr->freeProc = 0;
  961. X    } else if (freeProc == TCL_VOLATILE) {
  962. X    length = strlen(string);
  963. X    if (length > TCL_RESULT_SIZE) {
  964. X        iPtr->result = (char *) ckalloc((unsigned) length+1);
  965. X        iPtr->freeProc = (Tcl_FreeProc *) free;
  966. X    } else {
  967. X        iPtr->result = iPtr->resultSpace;
  968. X        iPtr->freeProc = 0;
  969. X    }
  970. X    strcpy(iPtr->result, string);
  971. X    } else {
  972. X    iPtr->result = string;
  973. X    }
  974. X
  975. X    /*
  976. X     * If the old result was dynamically-allocated, free it up.  Do it
  977. X     * here, rather than at the beginning, in case the new result value
  978. X     * was part of the old result value.
  979. X     */
  980. X
  981. X    if (oldFreeProc != 0) {
  982. X    (*oldFreeProc)(oldResult);
  983. X    }
  984. X}
  985. X
  986. X/*
  987. X *----------------------------------------------------------------------
  988. X *
  989. X * Tcl_AppendResult --
  990. X *
  991. X *    Append a variable number of strings onto the result already
  992. X *    present for an interpreter.
  993. X *
  994. X * Results:
  995. X *    None.
  996. X *
  997. X * Side effects:
  998. X *    The result in the interpreter given by the first argument
  999. X *    is extended by the strings given by the second and following
  1000. X *    arguments (up to a terminating NULL argument).
  1001. X *
  1002. X *----------------------------------------------------------------------
  1003. X */
  1004. X
  1005. X    /* VARARGS2 */
  1006. X#ifndef lint
  1007. Xvoid
  1008. XTcl_AppendResult(va_alist)
  1009. X#else
  1010. Xvoid
  1011. X    /* VARARGS2 */ /* ARGSUSED */
  1012. XTcl_AppendResult(interp, p, va_alist)
  1013. X    Tcl_Interp *interp;        /* Interpreter whose result is to be
  1014. X                 * extended. */
  1015. X    char *p;            /* One or more strings to add to the
  1016. X                 * result, terminated with NULL. */
  1017. X#endif
  1018. X    va_dcl
  1019. X{
  1020. X    va_list argList;
  1021. X    register Interp *iPtr;
  1022. X    char *string;
  1023. X    int newSpace;
  1024. X
  1025. X    /*
  1026. X     * First, scan through all the arguments to see how much space is
  1027. X     * needed.
  1028. X     */
  1029. X
  1030. X    va_start(argList);
  1031. X    iPtr = va_arg(argList, Interp *);
  1032. X    newSpace = 0;
  1033. X    while (1) {
  1034. X    string = va_arg(argList, char *);
  1035. X    if (string == NULL) {
  1036. X        break;
  1037. X    }
  1038. X    newSpace += strlen(string);
  1039. X    }
  1040. X    va_end(argList);
  1041. X
  1042. X    /*
  1043. X     * If the append buffer isn't already setup and large enough
  1044. X     * to hold the new data, set it up.
  1045. X     */
  1046. X
  1047. X    if ((iPtr->result != iPtr->appendResult)
  1048. X       || ((newSpace + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1049. X       SetupAppendBuffer(iPtr, newSpace);
  1050. X    }
  1051. X
  1052. X    /*
  1053. X     * Final step:  go through all the argument strings again, copying
  1054. X     * them into the buffer.
  1055. X     */
  1056. X
  1057. X    va_start(argList);
  1058. X    (void) va_arg(argList, Tcl_Interp *);
  1059. X    while (1) {
  1060. X    string = va_arg(argList, char *);
  1061. X    if (string == NULL) {
  1062. X        break;
  1063. X    }
  1064. X    strcpy(iPtr->appendResult + iPtr->appendUsed, string);
  1065. X    iPtr->appendUsed += strlen(string);
  1066. X    }
  1067. X    va_end(argList);
  1068. X}
  1069. X
  1070. X/*
  1071. X *----------------------------------------------------------------------
  1072. X *
  1073. X * Tcl_AppendElement --
  1074. X *
  1075. X *    Convert a string to a valid Tcl list element and append it
  1076. X *    to the current result (which is ostensibly a list).
  1077. X *
  1078. X * Results:
  1079. X *    None.
  1080. X *
  1081. X * Side effects:
  1082. X *    The result in the interpreter given by the first argument
  1083. X *    is extended with a list element converted from string.  If
  1084. X *    the original result wasn't empty, then a blank is added before
  1085. X *    the converted list element.
  1086. X *
  1087. X *----------------------------------------------------------------------
  1088. X */
  1089. X
  1090. Xvoid
  1091. XTcl_AppendElement(interp, string, noSep)
  1092. X    Tcl_Interp *interp;        /* Interpreter whose result is to be
  1093. X                 * extended. */
  1094. X    char *string;        /* String to convert to list element and
  1095. X                 * add to result. */
  1096. X    int noSep;            /* If non-zero, then don't output a
  1097. X                 * space character before this element,
  1098. X                 * even if the element isn't the first
  1099. X                 * thing in the output buffer. */
  1100. X{
  1101. X    register Interp *iPtr = (Interp *) interp;
  1102. X    int size, flags;
  1103. X    char *dst;
  1104. X
  1105. X    /*
  1106. X     * See how much space is needed, and grow the append buffer if
  1107. X     * needed to accommodate the list element.
  1108. X     */
  1109. X
  1110. X    size = Tcl_ScanElement(string, &flags) + 1;
  1111. X    if ((iPtr->result != iPtr->appendResult)
  1112. X       || ((size + iPtr->appendUsed) >= iPtr->appendAvl)) {
  1113. X       SetupAppendBuffer(iPtr, size+iPtr->appendUsed);
  1114. X    }
  1115. X
  1116. X    /*
  1117. X     * Convert the string into a list element and copy it to the
  1118. X     * buffer that's forming.
  1119. X     */
  1120. X
  1121. X    dst = iPtr->appendResult + iPtr->appendUsed;
  1122. X    if (!noSep && (iPtr->appendUsed != 0)) {
  1123. X    iPtr->appendUsed++;
  1124. X    *dst = ' ';
  1125. X    dst++;
  1126. X    }
  1127. X    iPtr->appendUsed += Tcl_ConvertElement(string, dst, flags);
  1128. X}
  1129. X
  1130. X/*
  1131. X *----------------------------------------------------------------------
  1132. X *
  1133. X * SetupAppendBuffer --
  1134. X *
  1135. X *    This procedure makes sure that there is an append buffer
  1136. X *    properly initialized for interp, and that it has at least
  1137. X *    enough room to accommodate newSpace new bytes of information.
  1138. X *
  1139. X * Results:
  1140. X *    None.
  1141. X *
  1142. X * Side effects:
  1143. X *    None.
  1144. X *
  1145. X *----------------------------------------------------------------------
  1146. X */
  1147. X
  1148. Xstatic void
  1149. XSetupAppendBuffer(iPtr, newSpace)
  1150. X    register Interp *iPtr;    /* Interpreter whose result is being set up. */
  1151. X    int newSpace;        /* Make sure that at least this many bytes
  1152. X                 * of new information may be added. */
  1153. X{
  1154. X    int totalSpace;
  1155. X
  1156. X    /*
  1157. X     * Make the append buffer larger, if that's necessary, then
  1158. X     * copy the current result into the append buffer and make the
  1159. X     * append buffer the official Tcl result.
  1160. X     */
  1161. X
  1162. X    if (iPtr->result != iPtr->appendResult) {
  1163. X    /*
  1164. X     * If an oversized buffer was used recently, then free it up
  1165. X     * so we go back to a smaller buffer.  This avoids tying up
  1166. X     * memory forever after a large operation.
  1167. X     */
  1168. X
  1169. X    if (iPtr->appendAvl > 500) {
  1170. X        ckfree(iPtr->appendResult);
  1171. X        iPtr->appendResult = NULL;
  1172. X        iPtr->appendAvl = 0;
  1173. X    }
  1174. X    iPtr->appendUsed = strlen(iPtr->result);
  1175. X    }
  1176. X    totalSpace = newSpace + iPtr->appendUsed;
  1177. X    if (totalSpace >= iPtr->appendAvl) {
  1178. X    char *new;
  1179. X
  1180. X    if (totalSpace < 100) {
  1181. X        totalSpace = 200;
  1182. X    } else {
  1183. X        totalSpace *= 2;
  1184. X    }
  1185. X    new = (char *) ckalloc((unsigned) totalSpace);
  1186. X    strcpy(new, iPtr->result);
  1187. X    if (iPtr->appendResult != NULL) {
  1188. X        ckfree(iPtr->appendResult);
  1189. X    }
  1190. X    iPtr->appendResult = new;
  1191. X    iPtr->appendAvl = totalSpace;
  1192. X    } else if (iPtr->result != iPtr->appendResult) {
  1193. X    strcpy(iPtr->appendResult, iPtr->result);
  1194. X    }
  1195. X    Tcl_FreeResult(iPtr);
  1196. X    iPtr->result = iPtr->appendResult;
  1197. X}
  1198. X
  1199. X/*
  1200. X *----------------------------------------------------------------------
  1201. X *
  1202. X * Tcl_ResetResult --
  1203. X *
  1204. X *    This procedure restores the result area for an interpreter
  1205. X *    to its default initialized state, freeing up any memory that
  1206. X *    may have been allocated for the result and clearing any
  1207. X *    error information for the interpreter.
  1208. X *
  1209. X * Results:
  1210. X *    None.
  1211. X *
  1212. X * Side effects:
  1213. X *    None.
  1214. X *
  1215. X *----------------------------------------------------------------------
  1216. X */
  1217. X
  1218. Xvoid
  1219. XTcl_ResetResult(interp)
  1220. X    Tcl_Interp *interp;        /* Interpreter for which to clear result. */
  1221. X{
  1222. X    register Interp *iPtr = (Interp *) interp;
  1223. X
  1224. X    Tcl_FreeResult(iPtr);
  1225. X    iPtr->result = iPtr->resultSpace;
  1226. X    iPtr->resultSpace[0] = 0;
  1227. X    iPtr->flags &=
  1228. X        ~(ERR_ALREADY_LOGGED | ERR_IN_PROGRESS | ERROR_CODE_SET);
  1229. X}
  1230. X
  1231. X/*
  1232. X *----------------------------------------------------------------------
  1233. X *
  1234. X * Tcl_SetErrorCode --
  1235. X *
  1236. X *    This procedure is called to record machine-readable information
  1237. X *    about an error that is about to be returned.
  1238. X *
  1239. X * Results:
  1240. X *    None.
  1241. X *
  1242. X * Side effects:
  1243. X *    The errorCode global variable is modified to hold all of the
  1244. X *    arguments to this procedure, in a list form with each argument
  1245. X *    becoming one element of the list.  A flag is set internally
  1246. X *    to remember that errorCode has been set, so the variable doesn't
  1247. X *    get set automatically when the error is returned.
  1248. X *
  1249. X *----------------------------------------------------------------------
  1250. X */
  1251. X    /* VARARGS2 */
  1252. X#ifndef lint
  1253. Xvoid
  1254. XTcl_SetErrorCode(va_alist)
  1255. X#else
  1256. Xvoid
  1257. X    /* VARARGS2 */ /* ARGSUSED */
  1258. XTcl_SetErrorCode(interp, p, va_alist)
  1259. X    Tcl_Interp *interp;        /* Interpreter whose errorCode variable is
  1260. X                 * to be set. */
  1261. X    char *p;            /* One or more elements to add to errorCode,
  1262. X                 * terminated with NULL. */
  1263. X#endif
  1264. X    va_dcl
  1265. X{
  1266. X    va_list argList;
  1267. X    char *string;
  1268. X    int flags;
  1269. X    Interp *iPtr;
  1270. X
  1271. X    /*
  1272. X     * Scan through the arguments one at a time, appending them to
  1273. X     * $errorCode as list elements.
  1274. X     */
  1275. X
  1276. X    va_start(argList);
  1277. X    iPtr = va_arg(argList, Interp *);
  1278. X    flags = TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT;
  1279. X    while (1) {
  1280. X    string = va_arg(argList, char *);
  1281. X    if (string == NULL) {
  1282. X        break;
  1283. X    }
  1284. X    (void) Tcl_SetVar2((Tcl_Interp *) iPtr, "errorCode",
  1285. X        (char *) NULL, string, flags);
  1286. X    flags |= TCL_APPEND_VALUE;
  1287. X    }
  1288. X    va_end(argList);
  1289. X    iPtr->flags |= ERROR_CODE_SET;
  1290. X}
  1291. X
  1292. X/*
  1293. X *----------------------------------------------------------------------
  1294. X *
  1295. X * TclGetListIndex --
  1296. X *
  1297. X *    Parse a list index, which may be either an integer or the
  1298. X *    value "end".
  1299. X *
  1300. X * Results:
  1301. X *    The return value is either TCL_OK or TCL_ERROR.  If it is
  1302. X *    TCL_OK, then the index corresponding to string is left in
  1303. X *    *indexPtr.  If the return value is TCL_ERROR, then string
  1304. X *    was bogus;  an error message is returned in interp->result.
  1305. X *    If a negative index is specified, it is rounded up to 0.
  1306. X *    The index value may be larger than the size of the list
  1307. X *    (this happens when "end" is specified).
  1308. X *
  1309. X * Side effects:
  1310. X *    None.
  1311. X *
  1312. X *----------------------------------------------------------------------
  1313. X */
  1314. X
  1315. Xint
  1316. XTclGetListIndex(interp, string, indexPtr)
  1317. X    Tcl_Interp *interp;            /* Interpreter for error reporting. */
  1318. X    char *string;            /* String containing list index. */
  1319. X    int *indexPtr;            /* Where to store index. */
  1320. X{
  1321. X    if (isdigit(*string) || (*string == '-')) {
  1322. X    if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
  1323. X        return TCL_ERROR;
  1324. X    }
  1325. X    if (*indexPtr < 0) {
  1326. X        *indexPtr = 0;
  1327. X    }
  1328. X    } else if (strncmp(string, "end", strlen(string)) == 0) {
  1329. X    *indexPtr = 1<<30;
  1330. X    } else {
  1331. X    Tcl_AppendResult(interp, "bad index \"", string,
  1332. X        "\": must be integer or \"end\"", (char *) NULL);
  1333. X    return TCL_ERROR;
  1334. X    }
  1335. X    return TCL_OK;
  1336. X}
  1337. X
  1338. X/*
  1339. X *----------------------------------------------------------------------
  1340. X *
  1341. X * TclCompileRegexp --
  1342. X *
  1343. X *    Compile a regular expression into a form suitable for fast
  1344. X *    matching.  This procedure retains a small cache of pre-compiled
  1345. X *    regular expressions in the interpreter, in order to avoid
  1346. X *    compilation costs as much as possible.
  1347. X *
  1348. X * Results:
  1349. X *    The return value is a pointer to the compiled form of string,
  1350. X *    suitable for passing to regexec.  If an error occurred while
  1351. X *    compiling the pattern, then NULL is returned and an error
  1352. X *    message is left in interp->result.
  1353. X *
  1354. X * Side effects:
  1355. X *    The cache of compiled regexp's in interp will be modified to
  1356. X *    hold information for string, if such information isn't already
  1357. X *    present in the cache.
  1358. X *
  1359. X *----------------------------------------------------------------------
  1360. X */
  1361. X
  1362. Xregexp *
  1363. XTclCompileRegexp(interp, string)
  1364. X    Tcl_Interp *interp;            /* For use in error reporting. */
  1365. X    char *string;            /* String for which to produce
  1366. X                     * compiled regular expression. */
  1367. X{
  1368. X    register Interp *iPtr = (Interp *) interp;
  1369. X    int i, length;
  1370. X    regexp *result;
  1371. X
  1372. X    length = strlen(string);
  1373. X    for (i = 0; i < NUM_REGEXPS; i++) {
  1374. X    if ((length == iPtr->patLengths[i])
  1375. X        && (strcmp(string, iPtr->patterns[i]) == 0)) {
  1376. X        /*
  1377. X         * Move the matched pattern to the first slot in the
  1378. X         * cache and shift the other patterns down one position.
  1379. X         */
  1380. X
  1381. X        if (i != 0) {
  1382. X        int j;
  1383. X        char *cachedString;
  1384. X
  1385. X        cachedString = iPtr->patterns[i];
  1386. X        result = iPtr->regexps[i];
  1387. X        for (j = i-1; j >= 0; j--) {
  1388. X            iPtr->patterns[j+1] = iPtr->patterns[j];
  1389. X            iPtr->patLengths[j+1] = iPtr->patLengths[j];
  1390. X            iPtr->regexps[j+1] = iPtr->regexps[j];
  1391. X        }
  1392. X        iPtr->patterns[0] = cachedString;
  1393. X        iPtr->patLengths[0] = length;
  1394. X        iPtr->regexps[0] = result;
  1395. X        }
  1396. X        return iPtr->regexps[0];
  1397. X    }
  1398. X    }
  1399. X
  1400. X    /*
  1401. X     * No match in the cache.  Compile the string and add it to the
  1402. X     * cache.
  1403. X     */
  1404. X
  1405. X    tclRegexpError = NULL;
  1406. X    result = regcomp(string);
  1407. X    if (tclRegexpError != NULL) {
  1408. X    Tcl_AppendResult(interp,
  1409. X        "couldn't compile regular expression pattern: ",
  1410. X        tclRegexpError, (char *) NULL);
  1411. X    return NULL;
  1412. X    }
  1413. X    if (iPtr->patterns[NUM_REGEXPS-1] != NULL) {
  1414. X    ckfree(iPtr->patterns[NUM_REGEXPS-1]);
  1415. X    ckfree((char *) iPtr->regexps[NUM_REGEXPS-1]);
  1416. X    }
  1417. X    for (i = NUM_REGEXPS - 2; i >= 0; i--) {
  1418. X    iPtr->patterns[i+1] = iPtr->patterns[i];
  1419. X    iPtr->patLengths[i+1] = iPtr->patLengths[i];
  1420. X    iPtr->regexps[i+1] = iPtr->regexps[i];
  1421. X    }
  1422. X    iPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
  1423. X    strcpy(iPtr->patterns[0], string);
  1424. X    iPtr->patLengths[0] = length;
  1425. X    iPtr->regexps[0] = result;
  1426. X    return result;
  1427. X}
  1428. X
  1429. X/*
  1430. X *----------------------------------------------------------------------
  1431. X *
  1432. X * regerror --
  1433. X *
  1434. X *    This procedure is invoked by the Henry Spencer's regexp code
  1435. X *    when an error occurs.  It saves the error message so it can
  1436. X *    be seen by the code that called Spencer's code.
  1437. X *
  1438. X * Results:
  1439. X *    None.
  1440. X *
  1441. X * Side effects:
  1442. X *    The value of "string" is saved in "tclRegexpError".
  1443. X *
  1444. X *----------------------------------------------------------------------
  1445. X */
  1446. X
  1447. Xvoid
  1448. Xregerror(string)
  1449. X    char *string;            /* Error message. */
  1450. X{
  1451. X    tclRegexpError = string;
  1452. X}
  1453. END_OF_FILE
  1454. if test 36390 -ne `wc -c <'tcl6.1/tclUtil.c'`; then
  1455.     echo shar: \"'tcl6.1/tclUtil.c'\" unpacked with wrong size!
  1456. fi
  1457. # end of 'tcl6.1/tclUtil.c'
  1458. fi
  1459. echo shar: End of archive 29 \(of 33\).
  1460. cp /dev/null ark29isdone
  1461. MISSING=""
  1462. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ; do
  1463.     if test ! -f ark${I}isdone ; then
  1464.     MISSING="${MISSING} ${I}"
  1465.     fi
  1466. done
  1467. if test "${MISSING}" = "" ; then
  1468.     echo You have unpacked all 33 archives.
  1469.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1470. else
  1471.     echo You still need to unpack the following archives:
  1472.     echo "        " ${MISSING}
  1473. fi
  1474. ##  End of shell archive.
  1475. exit 0
  1476.  
  1477. exit 0 # Just in case...
  1478. -- 
  1479. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1480. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1481. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1482. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1483.