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

  1. Newsgroups: comp.sources.misc
  2. From: karl@sugar.neosoft.com (Karl Lehenbauer)
  3. Subject:  v25i085:  tcl - tool command language, version 6.1, Part17/33
  4. Message-ID: <1991Nov15.224745.20787@sparky.imd.sterling.com>
  5. X-Md4-Signature: 5a7a26146b9c714a0ce71c4429843743
  6. Date: Fri, 15 Nov 1991 22:47:45 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
  10. Posting-number: Volume 25, Issue 85
  11. Archive-name: tcl/part17
  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 17 (of 33)."
  21. # Contents:  tcl6.1/tclBasic.c
  22. # Wrapped by karl@one on Tue Nov 12 19:44:26 1991
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'tcl6.1/tclBasic.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'tcl6.1/tclBasic.c'\"
  26. else
  27. echo shar: Extracting \"'tcl6.1/tclBasic.c'\" \(27576 characters\)
  28. sed "s/^X//" >'tcl6.1/tclBasic.c' <<'END_OF_FILE'
  29. X/* 
  30. X * tclBasic.c --
  31. X *
  32. X *    Contains the basic facilities for TCL command interpretation,
  33. X *    including interpreter creation and deletion, command creation
  34. X *    and deletion, and command parsing and execution.
  35. X *
  36. X * Copyright 1987-1991 Regents of the University of California
  37. X * Permission to use, copy, modify, and distribute this
  38. X * software and its documentation for any purpose and without
  39. X * fee is hereby granted, provided that the above copyright
  40. X * notice appear in all copies.  The University of California
  41. X * makes no representations about the suitability of this
  42. X * software for any purpose.  It is provided "as is" without
  43. X * express or implied warranty.
  44. X */
  45. X
  46. X#ifndef lint
  47. Xstatic char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclBasic.c,v 1.128 91/10/31 16:41:13 ouster Exp $ SPRITE (Berkeley)";
  48. X#endif
  49. X
  50. X#include "tclInt.h"
  51. X
  52. X/*
  53. X * The following structure defines all of the commands in the Tcl core,
  54. X * and the C procedures that execute them.
  55. X */
  56. X
  57. Xtypedef struct {
  58. X    char *name;            /* Name of command. */
  59. X    Tcl_CmdProc *proc;        /* Procedure that executes command. */
  60. X} CmdInfo;
  61. X
  62. X/*
  63. X * Built-in commands, and the procedures associated with them:
  64. X */
  65. X
  66. Xstatic CmdInfo builtInCmds[] = {
  67. X    /*
  68. X     * Commands in the generic core:
  69. X     */
  70. X
  71. X    {"append",        Tcl_AppendCmd},
  72. X    {"array",        Tcl_ArrayCmd},
  73. X    {"break",        Tcl_BreakCmd},
  74. X    {"case",        Tcl_CaseCmd},
  75. X    {"catch",        Tcl_CatchCmd},
  76. X    {"concat",        Tcl_ConcatCmd},
  77. X    {"continue",    Tcl_ContinueCmd},
  78. X    {"error",        Tcl_ErrorCmd},
  79. X    {"eval",        Tcl_EvalCmd},
  80. X    {"expr",        Tcl_ExprCmd},
  81. X    {"for",        Tcl_ForCmd},
  82. X    {"foreach",        Tcl_ForeachCmd},
  83. X    {"format",        Tcl_FormatCmd},
  84. X    {"global",        Tcl_GlobalCmd},
  85. X    {"if",        Tcl_IfCmd},
  86. X    {"incr",        Tcl_IncrCmd},
  87. X    {"info",        Tcl_InfoCmd},
  88. X    {"join",        Tcl_JoinCmd},
  89. X    {"lappend",        Tcl_LappendCmd},
  90. X    {"lindex",        Tcl_LindexCmd},
  91. X    {"linsert",        Tcl_LinsertCmd},
  92. X    {"list",        Tcl_ListCmd},
  93. X    {"llength",        Tcl_LlengthCmd},
  94. X    {"lrange",        Tcl_LrangeCmd},
  95. X    {"lreplace",    Tcl_LreplaceCmd},
  96. X    {"lsearch",        Tcl_LsearchCmd},
  97. X    {"lsort",        Tcl_LsortCmd},
  98. X    {"proc",        Tcl_ProcCmd},
  99. X    {"regexp",        Tcl_RegexpCmd},
  100. X    {"regsub",        Tcl_RegsubCmd},
  101. X    {"rename",        Tcl_RenameCmd},
  102. X    {"return",        Tcl_ReturnCmd},
  103. X    {"scan",        Tcl_ScanCmd},
  104. X    {"set",        Tcl_SetCmd},
  105. X    {"split",        Tcl_SplitCmd},
  106. X    {"string",        Tcl_StringCmd},
  107. X    {"trace",        Tcl_TraceCmd},
  108. X    {"unset",        Tcl_UnsetCmd},
  109. X    {"uplevel",        Tcl_UplevelCmd},
  110. X    {"upvar",        Tcl_UpvarCmd},
  111. X    {"while",        Tcl_WhileCmd},
  112. X
  113. X    /*
  114. X     * Commands in the UNIX core:
  115. X     */
  116. X
  117. X#ifndef TCL_GENERIC_ONLY
  118. X    {"cd",        Tcl_CdCmd},
  119. X    {"close",        Tcl_CloseCmd},
  120. X    {"eof",        Tcl_EofCmd},
  121. X    {"exec",        Tcl_ExecCmd},
  122. X    {"exit",        Tcl_ExitCmd},
  123. X    {"file",        Tcl_FileCmd},
  124. X    {"flush",        Tcl_FlushCmd},
  125. X    {"gets",        Tcl_GetsCmd},
  126. X    {"glob",        Tcl_GlobCmd},
  127. X    {"open",        Tcl_OpenCmd},
  128. X    {"puts",        Tcl_PutsCmd},
  129. X    {"pwd",        Tcl_PwdCmd},
  130. X    {"read",        Tcl_ReadCmd},
  131. X    {"seek",        Tcl_SeekCmd},
  132. X    {"source",        Tcl_SourceCmd},
  133. X    {"tell",        Tcl_TellCmd},
  134. X    {"time",        Tcl_TimeCmd},
  135. X#endif /* TCL_GENERIC_ONLY */
  136. X    {NULL,        (Tcl_CmdProc *) NULL}
  137. X};
  138. X
  139. X/*
  140. X *----------------------------------------------------------------------
  141. X *
  142. X * Tcl_CreateInterp --
  143. X *
  144. X *    Create a new TCL command interpreter.
  145. X *
  146. X * Results:
  147. X *    The return value is a token for the interpreter, which may be
  148. X *    used in calls to procedures like Tcl_CreateCmd, Tcl_Eval, or
  149. X *    Tcl_DeleteInterp.
  150. X *
  151. X * Side effects:
  152. X *    The command interpreter is initialized with an empty variable
  153. X *    table and the built-in commands.
  154. X *
  155. X *----------------------------------------------------------------------
  156. X */
  157. X
  158. XTcl_Interp *
  159. XTcl_CreateInterp()
  160. X{
  161. X    register Interp *iPtr;
  162. X    register Command *cmdPtr;
  163. X    register CmdInfo *cmdInfoPtr;
  164. X    int i;
  165. X
  166. X    iPtr = (Interp *) ckalloc(sizeof(Interp));
  167. X    iPtr->result = iPtr->resultSpace;
  168. X    iPtr->freeProc = 0;
  169. X    iPtr->errorLine = 0;
  170. X    Tcl_InitHashTable(&iPtr->commandTable, TCL_STRING_KEYS);
  171. X    Tcl_InitHashTable(&iPtr->globalTable, TCL_STRING_KEYS);
  172. X    iPtr->numLevels = 0;
  173. X    iPtr->framePtr = NULL;
  174. X    iPtr->varFramePtr = NULL;
  175. X    iPtr->activeTracePtr = NULL;
  176. X    iPtr->numEvents = 0;
  177. X    iPtr->events = NULL;
  178. X    iPtr->curEvent = 0;
  179. X    iPtr->curEventNum = 0;
  180. X    iPtr->revPtr = NULL;
  181. X    iPtr->historyFirst = NULL;
  182. X    iPtr->revDisables = 1;
  183. X    iPtr->evalFirst = iPtr->evalLast = NULL;
  184. X    iPtr->appendResult = NULL;
  185. X    iPtr->appendAvl = 0;
  186. X    iPtr->appendUsed = 0;
  187. X    iPtr->numFiles = 0;
  188. X    iPtr->filePtrArray = NULL;
  189. X    for (i = 0; i < NUM_REGEXPS; i++) {
  190. X    iPtr->patterns[i] = NULL;
  191. X    iPtr->regexps[i] = NULL;
  192. X    }
  193. X    iPtr->cmdCount = 0;
  194. X    iPtr->noEval = 0;
  195. X    iPtr->scriptFile = NULL;
  196. X    iPtr->flags = 0;
  197. X    iPtr->tracePtr = NULL;
  198. X    iPtr->resultSpace[0] = 0;
  199. X
  200. X    /*
  201. X     * Create the built-in commands.  Do it here, rather than calling
  202. X     * Tcl_CreateCommand, because it's faster (there's no need to
  203. X     * check for a pre-existing command by the same name).
  204. X     */
  205. X
  206. X    for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
  207. X    int new;
  208. X    Tcl_HashEntry *hPtr;
  209. X
  210. X    hPtr = Tcl_CreateHashEntry(&iPtr->commandTable,
  211. X        cmdInfoPtr->name, &new);
  212. X    if (new) {
  213. X        cmdPtr = (Command *) ckalloc(sizeof(Command));
  214. X        cmdPtr->proc = cmdInfoPtr->proc;
  215. X        cmdPtr->clientData = (ClientData) NULL;
  216. X        cmdPtr->deleteProc = NULL;
  217. X        Tcl_SetHashValue(hPtr, cmdPtr);
  218. X    }
  219. X    }
  220. X
  221. X#ifndef TCL_GENERIC_ONLY
  222. X    TclSetupEnv((Tcl_Interp *) iPtr);
  223. X#endif
  224. X
  225. X    return (Tcl_Interp *) iPtr;
  226. X}
  227. X
  228. X/*
  229. X *----------------------------------------------------------------------
  230. X *
  231. X * Tcl_DeleteInterp --
  232. X *
  233. X *    Delete an interpreter and free up all of the resources associated
  234. X *    with it.
  235. X *
  236. X * Results:
  237. X *    None.
  238. X *
  239. X * Side effects:
  240. X *    The interpreter is destroyed.  The caller should never again
  241. X *    use the interp token.
  242. X *
  243. X *----------------------------------------------------------------------
  244. X */
  245. X
  246. Xvoid
  247. XTcl_DeleteInterp(interp)
  248. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  249. X                 * by a previous call to Tcl_CreateInterp). */
  250. X{
  251. X    Interp *iPtr = (Interp *) interp;
  252. X    Tcl_HashEntry *hPtr;
  253. X    Tcl_HashSearch search;
  254. X    register Command *cmdPtr;
  255. X    int i;
  256. X
  257. X    /*
  258. X     * If the interpreter is in use, delay the deletion until later.
  259. X     */
  260. X
  261. X    iPtr->flags |= DELETED;
  262. X    if (iPtr->numLevels != 0) {
  263. X    return;
  264. X    }
  265. X
  266. X    /*
  267. X     * Free up any remaining resources associated with the
  268. X     * interpreter.
  269. X     */
  270. X
  271. X    for (hPtr = Tcl_FirstHashEntry(&iPtr->commandTable, &search);
  272. X        hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) {
  273. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  274. X    if (cmdPtr->deleteProc != NULL) { 
  275. X        (*cmdPtr->deleteProc)(cmdPtr->clientData);
  276. X    }
  277. X    ckfree((char *) cmdPtr);
  278. X    }
  279. X    Tcl_DeleteHashTable(&iPtr->commandTable);
  280. X    TclDeleteVars(iPtr, &iPtr->globalTable);
  281. X    if (iPtr->events != NULL) {
  282. X    int i;
  283. X
  284. X    for (i = 0; i < iPtr->numEvents; i++) {
  285. X        ckfree(iPtr->events[i].command);
  286. X    }
  287. X    ckfree((char *) iPtr->events);
  288. X    }
  289. X    while (iPtr->revPtr != NULL) {
  290. X    HistoryRev *nextPtr = iPtr->revPtr->nextPtr;
  291. X
  292. X    ckfree((char *) iPtr->revPtr);
  293. X    iPtr->revPtr = nextPtr;
  294. X    }
  295. X    if (iPtr->appendResult != NULL) {
  296. X    ckfree(iPtr->appendResult);
  297. X    }
  298. X#ifndef TCL_GENERIC_ONLY
  299. X    if (iPtr->numFiles > 0) {
  300. X    for (i = 0; i < iPtr->numFiles; i++) {
  301. X        OpenFile *filePtr;
  302. X    
  303. X        filePtr = iPtr->filePtrArray[i];
  304. X        if (filePtr == NULL) {
  305. X        continue;
  306. X        }
  307. X        if (i >= 3) {
  308. X        fclose(filePtr->f);
  309. X        if (filePtr->f2 != NULL) {
  310. X            fclose(filePtr->f2);
  311. X        }
  312. X        if (filePtr->numPids > 0) {
  313. X            Tcl_DetachPids(filePtr->numPids, filePtr->pidPtr);
  314. X            ckfree((char *) filePtr->pidPtr);
  315. X        }
  316. X        }
  317. X        ckfree((char *) filePtr);
  318. X    }
  319. X    ckfree((char *) iPtr->filePtrArray);
  320. X    }
  321. X#endif
  322. X    for (i = 0; i < NUM_REGEXPS; i++) {
  323. X    if (iPtr->patterns[i] == NULL) {
  324. X        break;
  325. X    }
  326. X    ckfree(iPtr->patterns[i]);
  327. X    ckfree((char *) iPtr->regexps[i]);
  328. X    }
  329. X    while (iPtr->tracePtr != NULL) {
  330. X    Trace *nextPtr = iPtr->tracePtr->nextPtr;
  331. X
  332. X    ckfree((char *) iPtr->tracePtr);
  333. X    iPtr->tracePtr = nextPtr;
  334. X    }
  335. X    ckfree((char *) iPtr);
  336. X}
  337. X
  338. X/*
  339. X *----------------------------------------------------------------------
  340. X *
  341. X * Tcl_CreateCommand --
  342. X *
  343. X *    Define a new command in a command table.
  344. X *
  345. X * Results:
  346. X *    None.
  347. X *
  348. X * Side effects:
  349. X *    If a command named cmdName already exists for interp, it is
  350. X *    deleted.  In the future, when cmdName is seen as the name of
  351. X *    a command by Tcl_Eval, proc will be called.  When the command
  352. X *    is deleted from the table, deleteProc will be called.  See the
  353. X *    manual entry for details on the calling sequence.
  354. X *
  355. X *----------------------------------------------------------------------
  356. X */
  357. X
  358. Xvoid
  359. XTcl_CreateCommand(interp, cmdName, proc, clientData, deleteProc)
  360. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  361. X                 * by a previous call to Tcl_CreateInterp). */
  362. X    char *cmdName;        /* Name of command. */
  363. X    Tcl_CmdProc *proc;        /* Command procedure to associate with
  364. X                 * cmdName. */
  365. X    ClientData clientData;    /* Arbitrary one-word value to pass to proc. */
  366. X    Tcl_CmdDeleteProc *deleteProc;
  367. X                /* If not NULL, gives a procedure to call when
  368. X                 * this command is deleted. */
  369. X{
  370. X    Interp *iPtr = (Interp *) interp;
  371. X    register Command *cmdPtr;
  372. X    Tcl_HashEntry *hPtr;
  373. X    int new;
  374. X
  375. X    hPtr = Tcl_CreateHashEntry(&iPtr->commandTable, cmdName, &new);
  376. X    if (!new) {
  377. X    /*
  378. X     * Command already exists:  delete the old one.
  379. X     */
  380. X
  381. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  382. X    if (cmdPtr->deleteProc != NULL) {
  383. X        (*cmdPtr->deleteProc)(cmdPtr->clientData);
  384. X    }
  385. X    } else {
  386. X    cmdPtr = (Command *) ckalloc(sizeof(Command));
  387. X    Tcl_SetHashValue(hPtr, cmdPtr);
  388. X    }
  389. X    cmdPtr->proc = proc;
  390. X    cmdPtr->clientData = clientData;
  391. X    cmdPtr->deleteProc = deleteProc;
  392. X}
  393. X
  394. X/*
  395. X *----------------------------------------------------------------------
  396. X *
  397. X * Tcl_DeleteCommand --
  398. X *
  399. X *    Remove the given command from the given interpreter.
  400. X *
  401. X * Results:
  402. X *    0 is returned if the command was deleted successfully.
  403. X *    -1 is returned if there didn't exist a command by that
  404. X *    name.
  405. X *
  406. X * Side effects:
  407. X *    CmdName will no longer be recognized as a valid command for
  408. X *    interp.
  409. X *
  410. X *----------------------------------------------------------------------
  411. X */
  412. X
  413. Xint
  414. XTcl_DeleteCommand(interp, cmdName)
  415. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  416. X                 * by a previous call to Tcl_CreateInterp). */
  417. X    char *cmdName;        /* Name of command to remove. */
  418. X{
  419. X    Interp *iPtr = (Interp *) interp;
  420. X    Tcl_HashEntry *hPtr;
  421. X    Command *cmdPtr;
  422. X
  423. X    hPtr = Tcl_FindHashEntry(&iPtr->commandTable, cmdName);
  424. X    if (hPtr == NULL) {
  425. X    return -1;
  426. X    }
  427. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  428. X    if (cmdPtr->deleteProc != NULL) {
  429. X    (*cmdPtr->deleteProc)(cmdPtr->clientData);
  430. X    }
  431. X    ckfree((char *) cmdPtr);
  432. X    Tcl_DeleteHashEntry(hPtr);
  433. X    return 0;
  434. X}
  435. X
  436. X/*
  437. X *-----------------------------------------------------------------
  438. X *
  439. X * Tcl_Eval --
  440. X *
  441. X *    Parse and execute a command in the Tcl language.
  442. X *
  443. X * Results:
  444. X *    The return value is one of the return codes defined in tcl.hd
  445. X *    (such as TCL_OK), and interp->result contains a string value
  446. X *    to supplement the return code.  The value of interp->result
  447. X *    will persist only until the next call to Tcl_Eval:  copy it or
  448. X *    lose it! *TermPtr is filled in with the character just after
  449. X *    the last one that was part of the command (usually a NULL
  450. X *    character or a closing bracket).
  451. X *
  452. X * Side effects:
  453. X *    Almost certainly;  depends on the command.
  454. X *
  455. X *-----------------------------------------------------------------
  456. X */
  457. X
  458. Xint
  459. XTcl_Eval(interp, cmd, flags, termPtr)
  460. X    Tcl_Interp *interp;        /* Token for command interpreter (returned
  461. X                 * by a previous call to Tcl_CreateInterp). */
  462. X    char *cmd;            /* Pointer to TCL command to interpret. */
  463. X    int flags;            /* OR-ed combination of flags like
  464. X                 * TCL_BRACKET_TERM and TCL_RECORD_BOUNDS. */
  465. X    char **termPtr;        /* If non-NULL, fill in the address it points
  466. X                 * to with the address of the char. just after
  467. X                 * the last one that was part of cmd.  See
  468. X                 * the man page for details on this. */
  469. X{
  470. X    /*
  471. X     * The storage immediately below is used to generate a copy
  472. X     * of the command, after all argument substitutions.  Pv will
  473. X     * contain the argv values passed to the command procedure.
  474. X     */
  475. X
  476. X#   define NUM_CHARS 200
  477. X    char copyStorage[NUM_CHARS];
  478. X    ParseValue pv;
  479. X    char *oldBuffer;
  480. X
  481. X    /*
  482. X     * This procedure generates an (argv, argc) array for the command,
  483. X     * It starts out with stack-allocated space but uses dynamically-
  484. X     * allocated storage to increase it if needed.
  485. X     */
  486. X
  487. X#   define NUM_ARGS 10
  488. X    char *(argStorage[NUM_ARGS]);
  489. X    char **argv = argStorage;
  490. X    int argc;
  491. X    int argSize = NUM_ARGS;
  492. X
  493. X    register char *src;            /* Points to current character
  494. X                     * in cmd. */
  495. X    char termChar;            /* Return when this character is found
  496. X                     * (either ']' or '\0').  Zero means
  497. X                     * that newlines terminate commands. */
  498. X    int result;                /* Return value. */
  499. X    register Interp *iPtr = (Interp *) interp;
  500. X    Tcl_HashEntry *hPtr;
  501. X    Command *cmdPtr;
  502. X    char *dummy;            /* Make termPtr point here if it was
  503. X                     * originally NULL. */
  504. X    char *cmdStart;            /* Points to first non-blank char. in
  505. X                     * command (used in calling trace
  506. X                     * procedures). */
  507. X    char *ellipsis = "";        /* Used in setting errorInfo variable;
  508. X                     * set to "..." to indicate that not
  509. X                     * all of offending command is included
  510. X                     * in errorInfo.  "" means that the
  511. X                     * command is all there. */
  512. X    register Trace *tracePtr;
  513. X
  514. X    /*
  515. X     * Initialize the result to an empty string and clear out any
  516. X     * error information.  This makes sure that we return an empty
  517. X     * result if there are no commands in the command string.
  518. X     */
  519. X
  520. X    Tcl_FreeResult((Tcl_Interp *) iPtr);
  521. X    iPtr->result = iPtr->resultSpace;
  522. X    iPtr->resultSpace[0] = 0;
  523. X    result = TCL_OK;
  524. X
  525. X    /*
  526. X     * Check depth of nested calls to Tcl_Eval:  if this gets too large,
  527. X     * it's probably because of an infinite loop somewhere.
  528. X     */
  529. X
  530. X    iPtr->numLevels++;
  531. X    if (iPtr->numLevels > MAX_NESTING_DEPTH) {
  532. X    iPtr->result =  "too many nested calls to Tcl_Eval (infinite loop?)";
  533. X    return TCL_ERROR;
  534. X    }
  535. X
  536. X    /*
  537. X     * Initialize the area in which command copies will be assembled.
  538. X     */
  539. X
  540. X    pv.buffer = copyStorage;
  541. X    pv.end = copyStorage + NUM_CHARS - 1;
  542. X    pv.expandProc = TclExpandParseValue;
  543. X    pv.clientData = (ClientData) NULL;
  544. X
  545. X    src = cmd;
  546. X    if (flags & TCL_BRACKET_TERM) {
  547. X    termChar = ']';
  548. X    } else {
  549. X    termChar = 0;
  550. X    }
  551. X    if (termPtr == NULL) {
  552. X    termPtr = &dummy;
  553. X    }
  554. X    *termPtr = src;
  555. X    cmdStart = src;
  556. X
  557. X    /*
  558. X     * There can be many sub-commands (separated by semi-colons or
  559. X     * newlines) in one command string.  This outer loop iterates over
  560. X     * individual commands.
  561. X     */
  562. X
  563. X    while (*src != termChar) {
  564. X    iPtr->flags &= ~(ERR_IN_PROGRESS | ERROR_CODE_SET);
  565. X
  566. X    /*
  567. X     * Skim off leading white space and semi-colons, and skip
  568. X     * comments.
  569. X     */
  570. X
  571. X    while (1) {
  572. X        register char c = *src;
  573. X
  574. X        if ((CHAR_TYPE(c) != TCL_SPACE) && (c != ';') && (c != '\n')) {
  575. X        break;
  576. X        }
  577. X        src += 1;
  578. X    }
  579. X    if (*src == '#') {
  580. X        for (src++; *src != 0; src++) {
  581. X        if (*src == '\n') {
  582. X            src++;
  583. X            break;
  584. X        }
  585. X        }
  586. X        continue;
  587. X    }
  588. X    cmdStart = src;
  589. X
  590. X    /*
  591. X     * Parse the words of the command, generating the argc and
  592. X     * argv for the command procedure.  May have to call
  593. X     * TclParseWords several times, expanding the argv array
  594. X     * between calls.
  595. X     */
  596. X
  597. X    pv.next = oldBuffer = pv.buffer;
  598. X    argc = 0;
  599. X    while (1) {
  600. X        int newArgs, maxArgs;
  601. X        char **newArgv;
  602. X        int i;
  603. X
  604. X        /*
  605. X         * Note:  the "- 2" below guarantees that we won't use the
  606. X         * last two argv slots here.  One is for a NULL pointer to
  607. X         * mark the end of the list, and the other is to leave room
  608. X         * for inserting the command name "unknown" as the first
  609. X         * argument (see below).
  610. X         */
  611. X
  612. X        maxArgs = argSize - argc - 2;
  613. X        result = TclParseWords((Tcl_Interp *) iPtr, src, flags,
  614. X            maxArgs, termPtr, &newArgs, &argv[argc], &pv);
  615. X        src = *termPtr;
  616. X        if (result != TCL_OK) {
  617. X        ellipsis = "...";
  618. X        goto done;
  619. X        }
  620. X
  621. X        /*
  622. X         * Careful!  Buffer space may have gotten reallocated while
  623. X         * parsing words.  If this happened, be sure to update all
  624. X         * of the older argv pointers to refer to the new space.
  625. X         */
  626. X
  627. X        if (oldBuffer != pv.buffer) {
  628. X        int i;
  629. X
  630. X        for (i = 0; i < argc; i++) {
  631. X            argv[i] = pv.buffer + (argv[i] - oldBuffer);
  632. X        }
  633. X        oldBuffer = pv.buffer;
  634. X        }
  635. X        argc += newArgs;
  636. X        if (newArgs < maxArgs) {
  637. X        argv[argc] = (char *) NULL;
  638. X        break;
  639. X        }
  640. X
  641. X        /*
  642. X         * Args didn't all fit in the current array.  Make it bigger.
  643. X         */
  644. X
  645. X        argSize *= 2;
  646. X        newArgv = (char **)
  647. X            ckalloc((unsigned) argSize * sizeof(char *));
  648. X        for (i = 0; i < argc; i++) {
  649. X        newArgv[i] = argv[i];
  650. X        }
  651. X        if (argv != argStorage) {
  652. X        ckfree((char *) argv);
  653. X        }
  654. X        argv = newArgv;
  655. X    }
  656. X
  657. X    /*
  658. X     * If this is an empty command (or if we're just parsing
  659. X     * commands without evaluating them), then just skip to the
  660. X     * next command.
  661. X     */
  662. X
  663. X    if ((argc == 0) || iPtr->noEval) {
  664. X        continue;
  665. X    }
  666. X    argv[argc] = NULL;
  667. X
  668. X    /*
  669. X     * Save information for the history module, if needed.
  670. X     */
  671. X
  672. X    if (flags & TCL_RECORD_BOUNDS) {
  673. X        iPtr->evalFirst = cmdStart;
  674. X        iPtr->evalLast = src-1;
  675. X    }
  676. X
  677. X    /*
  678. X     * Find the procedure to execute this command.  If there isn't
  679. X     * one, then see if there is a command "unknown".  If so,
  680. X     * invoke it instead, passing it the words of the original
  681. X     * command as arguments.
  682. X     */
  683. X
  684. X    hPtr = Tcl_FindHashEntry(&iPtr->commandTable, argv[0]);
  685. X    if (hPtr == NULL) {
  686. X        int i;
  687. X
  688. X        hPtr = Tcl_FindHashEntry(&iPtr->commandTable, "unknown");
  689. X        if (hPtr == NULL) {
  690. X        Tcl_ResetResult(interp);
  691. X        Tcl_AppendResult(interp, "invalid command name: \"",
  692. X            argv[0], "\"", (char *) NULL);
  693. X        result = TCL_ERROR;
  694. X        goto done;
  695. X        }
  696. X        for (i = argc; i >= 0; i--) {
  697. X        argv[i+1] = argv[i];
  698. X        }
  699. X        argv[0] = "unknown";
  700. X        argc++;
  701. X    }
  702. X    cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
  703. X
  704. X    /*
  705. X     * Call trace procedures, if any.
  706. X     */
  707. X
  708. X    for (tracePtr = iPtr->tracePtr; tracePtr != NULL;
  709. X        tracePtr = tracePtr->nextPtr) {
  710. X        char saved;
  711. X
  712. X        if (tracePtr->level < iPtr->numLevels) {
  713. X        continue;
  714. X        }
  715. X        saved = *src;
  716. X        *src = 0;
  717. X        (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
  718. X            cmdStart, cmdPtr->proc, cmdPtr->clientData, argc, argv);
  719. X        *src = saved;
  720. X    }
  721. X
  722. X    /*
  723. X     * At long last, invoke the command procedure.  Reset the
  724. X     * result to its default empty value first (it could have
  725. X     * gotten changed by earlier commands in the same command
  726. X     * string).
  727. X     */
  728. X
  729. X    iPtr->cmdCount++;
  730. X    Tcl_FreeResult(iPtr);
  731. X    iPtr->result = iPtr->resultSpace;
  732. X    iPtr->resultSpace[0] = 0;
  733. X    result = (*cmdPtr->proc)(cmdPtr->clientData, interp, argc, argv);
  734. X    if (result != TCL_OK) {
  735. X        break;
  736. X    }
  737. X    }
  738. X
  739. X    /*
  740. X     * Free up any extra resources that were allocated.
  741. X     */
  742. X
  743. X    done:
  744. X    if (pv.buffer != copyStorage) {
  745. X    ckfree((char *) pv.buffer);
  746. X    }
  747. X    if (argv != argStorage) {
  748. X    ckfree((char *) argv);
  749. X    }
  750. X    iPtr->numLevels--;
  751. X    if (iPtr->numLevels == 0) {
  752. X    if (result == TCL_RETURN) {
  753. X        result = TCL_OK;
  754. X    }
  755. X    if ((result != TCL_OK) && (result != TCL_ERROR)) {
  756. X        Tcl_ResetResult(interp);
  757. X        if (result == TCL_BREAK) {
  758. X        iPtr->result = "invoked \"break\" outside of a loop";
  759. X        } else if (result == TCL_CONTINUE) {
  760. X        iPtr->result = "invoked \"continue\" outside of a loop";
  761. X        } else {
  762. X        iPtr->result = iPtr->resultSpace;
  763. X        sprintf(iPtr->resultSpace, "command returned bad code: %d",
  764. X            result);
  765. X        }
  766. X        result = TCL_ERROR;
  767. X    }
  768. X    if (iPtr->flags & DELETED) {
  769. X        Tcl_DeleteInterp(interp);
  770. X    }
  771. X    }
  772. X
  773. X    /*
  774. X     * If an error occurred, record information about what was being
  775. X     * executed when the error occurred.
  776. X     */
  777. X
  778. X    if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
  779. X    int numChars;
  780. X    register char *p;
  781. X
  782. X    /*
  783. X     * Compute the line number where the error occurred.
  784. X     */
  785. X
  786. X    iPtr->errorLine = 1;
  787. X    for (p = cmd; p != cmdStart; p++) {
  788. X        if (*p == '\n') {
  789. X        iPtr->errorLine++;
  790. X        }
  791. X    }
  792. X    for ( ; isspace(*p) || (*p == ';'); p++) {
  793. X        if (*p == '\n') {
  794. X        iPtr->errorLine++;
  795. X        }
  796. X    }
  797. X
  798. X    /*
  799. X     * Figure out how much of the command to print in the error
  800. X     * message (up to a certain number of characters, or up to
  801. X     * the first new-line).
  802. X     */
  803. X
  804. X    numChars = src - cmdStart;
  805. X    if (numChars > (NUM_CHARS-50)) {
  806. X        numChars = NUM_CHARS-50;
  807. X        ellipsis = " ...";
  808. X    }
  809. X
  810. X    if (!(iPtr->flags & ERR_IN_PROGRESS)) {
  811. X        sprintf(copyStorage, "\n    while executing\n\"%.*s%s\"",
  812. X            numChars, cmdStart, ellipsis);
  813. X    } else {
  814. X        sprintf(copyStorage, "\n    invoked from within\n\"%.*s%s\"",
  815. X            numChars, cmdStart, ellipsis);
  816. X    }
  817. X    Tcl_AddErrorInfo(interp, copyStorage);
  818. X    iPtr->flags &= ~ERR_ALREADY_LOGGED;
  819. X    } else {
  820. X    iPtr->flags &= ~ERR_ALREADY_LOGGED;
  821. X    }
  822. X    return result;
  823. X}
  824. X
  825. X/*
  826. X *----------------------------------------------------------------------
  827. X *
  828. X * Tcl_CreateTrace --
  829. X *
  830. X *    Arrange for a procedure to be called to trace command execution.
  831. X *
  832. X * Results:
  833. X *    The return value is a token for the trace, which may be passed
  834. X *    to Tcl_DeleteTrace to eliminate the trace.
  835. X *
  836. X * Side effects:
  837. X *    From now on, proc will be called just before a command procedure
  838. X *    is called to execute a Tcl command.  Calls to proc will have the
  839. X *    following form:
  840. X *
  841. X *    void
  842. X *    proc(clientData, interp, level, command, cmdProc, cmdClientData,
  843. X *        argc, argv)
  844. X *        ClientData clientData;
  845. X *        Tcl_Interp *interp;
  846. X *        int level;
  847. X *        char *command;
  848. X *        int (*cmdProc)();
  849. X *        ClientData cmdClientData;
  850. X *        int argc;
  851. X *        char **argv;
  852. X *    {
  853. X *    }
  854. X *
  855. X *    The clientData and interp arguments to proc will be the same
  856. X *    as the corresponding arguments to this procedure.  Level gives
  857. X *    the nesting level of command interpretation for this interpreter
  858. X *    (0 corresponds to top level).  Command gives the ASCII text of
  859. X *    the raw command, cmdProc and cmdClientData give the procedure that
  860. X *    will be called to process the command and the ClientData value it
  861. X *    will receive, and argc and argv give the arguments to the
  862. X *    command, after any argument parsing and substitution.  Proc
  863. X *    does not return a value.
  864. X *
  865. X *----------------------------------------------------------------------
  866. X */
  867. X
  868. XTcl_Trace
  869. XTcl_CreateTrace(interp, level, proc, clientData)
  870. X    Tcl_Interp *interp;        /* Interpreter in which to create the trace. */
  871. X    int level;            /* Only call proc for commands at nesting level
  872. X                 * <= level (1 => top level). */
  873. X    Tcl_CmdTraceProc *proc;    /* Procedure to call before executing each
  874. X                 * command. */
  875. X    ClientData clientData;    /* Arbitrary one-word value to pass to proc. */
  876. X{
  877. X    register Trace *tracePtr;
  878. X    register Interp *iPtr = (Interp *) interp;
  879. X
  880. X    tracePtr = (Trace *) ckalloc(sizeof(Trace));
  881. X    tracePtr->level = level;
  882. X    tracePtr->proc = proc;
  883. X    tracePtr->clientData = clientData;
  884. X    tracePtr->nextPtr = iPtr->tracePtr;
  885. X    iPtr->tracePtr = tracePtr;
  886. X
  887. X    return (Tcl_Trace) tracePtr;
  888. X}
  889. X
  890. X/*
  891. X *----------------------------------------------------------------------
  892. X *
  893. X * Tcl_DeleteTrace --
  894. X *
  895. X *    Remove a trace.
  896. X *
  897. X * Results:
  898. X *    None.
  899. X *
  900. X * Side effects:
  901. X *    From now on there will be no more calls to the procedure given
  902. X *    in trace.
  903. X *
  904. X *----------------------------------------------------------------------
  905. X */
  906. X
  907. Xvoid
  908. XTcl_DeleteTrace(interp, trace)
  909. X    Tcl_Interp *interp;        /* Interpreter that contains trace. */
  910. X    Tcl_Trace trace;        /* Token for trace (returned previously by
  911. X                 * Tcl_CreateTrace). */
  912. X{
  913. X    register Interp *iPtr = (Interp *) interp;
  914. X    register Trace *tracePtr = (Trace *) trace;
  915. X    register Trace *tracePtr2;
  916. X
  917. X    if (iPtr->tracePtr == tracePtr) {
  918. X    iPtr->tracePtr = tracePtr->nextPtr;
  919. X    ckfree((char *) tracePtr);
  920. X    } else {
  921. X    for (tracePtr2 = iPtr->tracePtr; tracePtr2 != NULL;
  922. X        tracePtr2 = tracePtr2->nextPtr) {
  923. X        if (tracePtr2->nextPtr == tracePtr) {
  924. X        tracePtr2->nextPtr = tracePtr->nextPtr;
  925. X        ckfree((char *) tracePtr);
  926. X        return;
  927. X        }
  928. X    }
  929. X    }
  930. X}
  931. X
  932. X/*
  933. X *----------------------------------------------------------------------
  934. X *
  935. X * Tcl_AddErrorInfo --
  936. X *
  937. X *    Add information to a message being accumulated that describes
  938. X *    the current error.
  939. X *
  940. X * Results:
  941. X *    None.
  942. X *
  943. X * Side effects:
  944. X *    The contents of message are added to the "errorInfo" variable.
  945. X *    If Tcl_Eval has been called since the current value of errorInfo
  946. X *    was set, errorInfo is cleared before adding the new message.
  947. X *
  948. X *----------------------------------------------------------------------
  949. X */
  950. X
  951. Xvoid
  952. XTcl_AddErrorInfo(interp, message)
  953. X    Tcl_Interp *interp;        /* Interpreter to which error information
  954. X                 * pertains. */
  955. X    char *message;        /* Message to record. */
  956. X{
  957. X    register Interp *iPtr = (Interp *) interp;
  958. X
  959. X    /*
  960. X     * If an error is already being logged, then the new errorInfo
  961. X     * is the concatenation of the old info and the new message.
  962. X     * If this is the first piece of info for the error, then the
  963. X     * new errorInfo is the concatenation of the message in
  964. X     * interp->result and the new message.
  965. X     */
  966. X
  967. X    if (!(iPtr->flags & ERR_IN_PROGRESS)) {
  968. X    Tcl_SetVar2(interp, "errorInfo", (char *) NULL, interp->result,
  969. X        TCL_GLOBAL_ONLY);
  970. X    iPtr->flags |= ERR_IN_PROGRESS;
  971. X
  972. X    /*
  973. X     * If the errorCode variable wasn't set by the code that generated
  974. X     * the error, set it to "NONE".
  975. X     */
  976. X
  977. X    if (!(iPtr->flags & ERROR_CODE_SET)) {
  978. X        (void) Tcl_SetVar2(interp, "errorCode", (char *) NULL, "NONE",
  979. X            TCL_GLOBAL_ONLY);
  980. X    }
  981. X    }
  982. X    Tcl_SetVar2(interp, "errorInfo", (char *) NULL, message,
  983. X        TCL_GLOBAL_ONLY|TCL_APPEND_VALUE);
  984. X}
  985. X
  986. X/*
  987. X *----------------------------------------------------------------------
  988. X *
  989. X * Tcl_VarEval --
  990. X *
  991. X *    Given a variable number of string arguments, concatenate them
  992. X *    all together and execute the result as a Tcl command.
  993. X *
  994. X * Results:
  995. X *    A standard Tcl return result.  An error message or other
  996. X *    result may be left in interp->result.
  997. X *
  998. X * Side effects:
  999. X *    Depends on what was done by the command.
  1000. X *
  1001. X *----------------------------------------------------------------------
  1002. X */
  1003. X    /* VARARGS2 */ /* ARGSUSED */
  1004. Xint
  1005. X#ifndef lint
  1006. XTcl_VarEval(va_alist)
  1007. X#else
  1008. XTcl_VarEval(interp, p, va_alist)
  1009. X    Tcl_Interp *interp;        /* Interpreter in which to execute command. */
  1010. X    char *p;            /* One or more strings to concatenate,
  1011. X                 * terminated with a NULL string. */
  1012. X#endif
  1013. X    va_dcl
  1014. X{
  1015. X    va_list argList;
  1016. X#define FIXED_SIZE 200
  1017. X    char fixedSpace[FIXED_SIZE+1];
  1018. X    int spaceAvl, spaceUsed, length;
  1019. X    char *string, *cmd;
  1020. X    Tcl_Interp *interp;
  1021. X    int result;
  1022. X
  1023. X    /*
  1024. X     * Copy the strings one after the other into a single larger
  1025. X     * string.  Use stack-allocated space for small commands, but if
  1026. X     * the commands gets too large than call ckalloc to create the
  1027. X     * space.
  1028. X     */
  1029. X
  1030. X    va_start(argList);
  1031. X    interp = va_arg(argList, Tcl_Interp *);
  1032. X    spaceAvl = FIXED_SIZE;
  1033. X    spaceUsed = 0;
  1034. X    cmd = fixedSpace;
  1035. X    while (1) {
  1036. X    string = va_arg(argList, char *);
  1037. X    if (string == NULL) {
  1038. X        break;
  1039. X    }
  1040. X    length = strlen(string);
  1041. X    if ((spaceUsed + length) > spaceAvl) {
  1042. X        char *new;
  1043. X
  1044. X        spaceAvl = spaceUsed + length;
  1045. X        spaceAvl += spaceAvl/2;
  1046. X        new = ckalloc((unsigned) spaceAvl);
  1047. X        memcpy((VOID *) new, (VOID *) cmd, spaceUsed);
  1048. X        if (cmd != fixedSpace) {
  1049. X        ckfree(cmd);
  1050. X        }
  1051. X        cmd = new;
  1052. X    }
  1053. X    strcpy(cmd + spaceUsed, string);
  1054. X    spaceUsed += length;
  1055. X    }
  1056. X    va_end(argList);
  1057. X    cmd[spaceUsed] = '\0';
  1058. X
  1059. X    result = Tcl_Eval(interp, cmd, 0, (char **) NULL);
  1060. X    if (cmd != fixedSpace) {
  1061. X    ckfree(cmd);
  1062. X    }
  1063. X    return result;
  1064. X}
  1065. END_OF_FILE
  1066. if test 27576 -ne `wc -c <'tcl6.1/tclBasic.c'`; then
  1067.     echo shar: \"'tcl6.1/tclBasic.c'\" unpacked with wrong size!
  1068. fi
  1069. # end of 'tcl6.1/tclBasic.c'
  1070. fi
  1071. echo shar: End of archive 17 \(of 33\).
  1072. cp /dev/null ark17isdone
  1073. MISSING=""
  1074. 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
  1075.     if test ! -f ark${I}isdone ; then
  1076.     MISSING="${MISSING} ${I}"
  1077.     fi
  1078. done
  1079. if test "${MISSING}" = "" ; then
  1080.     echo You have unpacked all 33 archives.
  1081.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1082. else
  1083.     echo You still need to unpack the following archives:
  1084.     echo "        " ${MISSING}
  1085. fi
  1086. ##  End of shell archive.
  1087. exit 0
  1088.  
  1089. exit 0 # Just in case...
  1090. -- 
  1091. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1092. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1093. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1094. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1095.