home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / devel / tcl / tclx7_31.z / tclx7_31 / tcldev / tclX7.3a-p1 / src / tclXsignal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-19  |  39.7 KB  |  1,415 lines

  1. /*
  2.  * tclXsignal.c --
  3.  *
  4.  * Tcl Unix signal support routines and the signal and commands.
  5.  *-----------------------------------------------------------------------------
  6.  * Copyright 1991-1993 Karl Lehenbauer and Mark Diekhans.
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  11.  * Mark Diekhans make no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without express or
  13.  * implied warranty.
  14.  *-----------------------------------------------------------------------------
  15.  * $Id: tclXsignal.c,v 3.0 1993/11/19 06:59:16 markd Rel $
  16.  *-----------------------------------------------------------------------------
  17.  */
  18.  
  19. #include "tclExtdInt.h"
  20.  
  21.  
  22. #ifndef SIGCLD
  23. #   define SIGCLD SIGCHLD
  24. #endif
  25. #ifndef SIGCHLD
  26. #   define SIGCHLD SIGCLD
  27. #endif
  28.  
  29. #ifndef MAXSIG
  30. #  ifdef NSIG
  31. #    define MAXSIG NSIG
  32. #  else
  33. #    define MAXSIG 32
  34. #  endif
  35. #endif
  36.  
  37. /*
  38.  * Signal name table maps name to number.
  39.  */
  40.  
  41. #define SIG_NAME_MAX 9  /* Maximum length of any signal name */
  42.  
  43. static struct {char *name;
  44.         short num;
  45.        } sigNameTable [] = {
  46. #ifdef SIGABRT
  47.     "ABRT",    SIGABRT,
  48. #endif
  49. #ifdef SIGALRM
  50.     "ALRM",    SIGALRM,
  51. #endif
  52. #ifdef SIGBUS
  53.     "BUS",     SIGBUS,
  54. #endif
  55. #ifdef SIGCHLD
  56.     "CHLD",    SIGCHLD,
  57. #endif
  58. #ifdef SIGCLD
  59.     "CLD",     SIGCLD,
  60. #endif
  61. #ifdef SIGCONT
  62.     "CONT",    SIGCONT,
  63. #endif
  64. #ifdef SIGEMT
  65.     "EMT",     SIGEMT,
  66. #endif
  67. #ifdef SIGFPE
  68.     "FPE",     SIGFPE,
  69. #endif
  70. #ifdef SIGHUP
  71.     "HUP",     SIGHUP,
  72. #endif
  73. #ifdef SIGILL
  74.     "ILL",     SIGILL,
  75. #endif
  76. #ifdef SIGINT
  77.     "INT",     SIGINT,
  78. #endif
  79. #ifdef SIGIO
  80.     "IO",      SIGIO,
  81. #endif
  82. #ifdef SIGIOT
  83.     "IOT",     SIGIOT,
  84. #endif
  85. #ifdef SIGKILL
  86.     "KILL",    SIGKILL,
  87. #endif
  88. #ifdef SIGLOST
  89.     "LOST",    SIGLOST,
  90. #endif
  91. #ifdef SIGPIPE
  92.     "PIPE",    SIGPIPE,
  93. #endif
  94. #ifdef SIGPOLL
  95.     "POLL",    SIGPOLL,
  96. #endif
  97. #ifdef SIGPROF
  98.     "PROF",    SIGPROF,
  99. #endif
  100. #ifdef SIGPWR
  101.     "PWR",     SIGPWR,
  102. #endif
  103. #ifdef SIGQUIT
  104.     "QUIT",    SIGQUIT,
  105. #endif
  106. #ifdef SIGSEGV
  107.     "SEGV",    SIGSEGV,
  108. #endif
  109. #ifdef SIGSTOP
  110.     "STOP",    SIGSTOP,
  111. #endif
  112. #ifdef SIGSYS
  113.     "SYS",     SIGSYS,
  114. #endif
  115. #ifdef SIGTERM
  116.     "TERM",    SIGTERM,
  117. #endif
  118. #ifdef SIGTRAP
  119.     "TRAP",    SIGTRAP,
  120. #endif
  121. #ifdef SIGTSTP
  122.     "TSTP",    SIGTSTP,
  123. #endif
  124. #ifdef SIGTTIN
  125.     "TTIN",    SIGTTIN,
  126. #endif
  127. #ifdef SIGTTOU
  128.     "TTOU",    SIGTTOU,
  129. #endif
  130. #ifdef SIGURG
  131.     "URG",     SIGURG,
  132. #endif
  133. #ifdef SIGUSR1
  134.     "USR1",    SIGUSR1,
  135. #endif
  136. #ifdef SIGUSR2
  137.     "USR2",    SIGUSR2,
  138. #endif
  139. #ifdef SIGVTALRM
  140.     "VTALRM",  SIGVTALRM,
  141. #endif
  142. #ifdef SIGWINCH
  143.     "WINCH",   SIGWINCH,
  144. #endif
  145. #ifdef SIGXCPU
  146.     "XCPU",    SIGXCPU,
  147. #endif
  148. #ifdef SIGXFSZ
  149.     "XFSZ",    SIGXFSZ,
  150. #endif
  151.     NULL,         -1};
  152.  
  153. #ifndef RETSIGTYPE
  154. #   define RETSIGTYPE void
  155. #endif
  156.  
  157. typedef RETSIGTYPE (*signalProcPtr_t) _ANSI_ARGS_((int));
  158.  
  159. /*
  160.  * Class of actions that can be set by the signal command.
  161.  */
  162. #define SIGACT_SET     1   /* Set the signal     */
  163. #define SIGACT_GET     2   /* Get the signal     */
  164. #define SIGACT_BLOCK   3   /* Block the signal   */
  165. #define SIGACT_UNBLOCK 4   /* Unblock the signal */
  166.  
  167. /*
  168.  * Defines if this is not Posix.
  169.  */
  170. #ifndef SIG_BLOCK
  171. #   define SIG_BLOCK       1
  172. #   define SIG_UNBLOCK     2
  173. #endif
  174.  
  175. /*
  176.  * Structure used to save error state of the interpreter.
  177.  */
  178. typedef struct {
  179.     char  *result;
  180.     char  *errorInfo;
  181.     char  *errorCode;
  182. } errState_t;
  183.  
  184. /*
  185.  * Table containing a interpreters and there Async handler cookie.
  186.  */
  187. typedef struct {
  188.     Tcl_Interp       *interp;
  189.     Tcl_AsyncHandler  handler;
  190. } interpHandler_t;
  191.  
  192. static interpHandler_t *interpTable = NULL;
  193. static int              interpTableSize  = 0;
  194. static int              numInterps  = 0;
  195.  
  196. /*
  197.  * A flag indicating that an "error" signal has occured.  This is used to
  198.  * flush interactive input in commands and is only cleared there.  Also an
  199.  * application-supplied function to call if a error signal occurs.  This
  200.  * normally flushes command input.
  201.  */
  202. int tclGotErrorSignal = FALSE;
  203. void (*tclErrorSignalProc) _ANSI_ARGS_((int signalNum)) = NULL;
  204.  
  205. /*
  206.  * Counters of signals that have occured but have not been processed.
  207.  */
  208. static unsigned signalsReceived [MAXSIG];
  209.  
  210. /*
  211.  * Table of commands to evaluate when a signal occurs.  If the command is
  212.  * NULL and the signal is received, an error is returned.
  213.  */
  214. static char *signalTrapCmds [MAXSIG];
  215.  
  216. /*
  217.  * Pointer to background error handler (normally NULL or Tk_BackgroundError).
  218.  */
  219. void (*tclSignalBackgroundError) _ANSI_ARGS_((Tcl_Interp *interp)) = NULL;
  220.  
  221. /*
  222.  * Prototypes of internal functions.
  223.  */
  224. static int
  225. SigNameToNum _ANSI_ARGS_((char *sigName));
  226.  
  227. static int
  228. GetSignalState _ANSI_ARGS_((int              signalNum,
  229.                             signalProcPtr_t *sigProcPtr));
  230.  
  231. static int
  232. SetSignalAction _ANSI_ARGS_((int             signalNum,
  233.                              signalProcPtr_t sigFunc));
  234.  
  235. static RETSIGTYPE
  236. TclSignalTrap _ANSI_ARGS_((int signalNum));
  237.  
  238. static int
  239. FormatTrapCode  _ANSI_ARGS_((Tcl_Interp  *interp,
  240.                              int          signalNum,
  241.                              Tcl_DString *command));
  242.  
  243. static errState_t *
  244. SaveErrorState _ANSI_ARGS_((Tcl_Interp *interp));
  245.  
  246. static void
  247. RestoreErrorState _ANSI_ARGS_((Tcl_Interp *interp,
  248.                                errState_t *errStatePtr));
  249.  
  250. static int
  251. EvalTrapCode _ANSI_ARGS_((Tcl_Interp *interp,
  252.                           int         signalNum));
  253.  
  254. static int
  255. ProcessASignal _ANSI_ARGS_((Tcl_Interp *interp,
  256.                             int         signalNum));
  257.  
  258. static int
  259. ParseSignalList _ANSI_ARGS_((Tcl_Interp *interp,
  260.                              char       *signalListStr,
  261.                              int         signalList []));
  262.  
  263. static char *
  264. SignalBlocked _ANSI_ARGS_((Tcl_Interp  *interp,
  265.                            int          signalNum));
  266.  
  267. static int
  268. GetSignalStates  _ANSI_ARGS_((Tcl_Interp *interp,
  269.                               int         signalListSize,
  270.                               int         signalList [MAXSIG]));
  271.  
  272. static int
  273. SetSignalStates  _ANSI_ARGS_((Tcl_Interp      *interp,
  274.                               int              signalListSize,
  275.                               int              signalList [MAXSIG],
  276.                               signalProcPtr_t  actionFunc,
  277.                               char            *command));
  278.  
  279. static int
  280. BlockSignals _ANSI_ARGS_((Tcl_Interp  *interp,
  281.                           int          action,
  282.                           int          signalListSize,
  283.                           int          signalList [MAXSIG]));
  284.  
  285. static void
  286. SignalCmdCleanUp _ANSI_ARGS_((ClientData  clientData,
  287.                               Tcl_Interp *interp));
  288.  
  289.  
  290. /*
  291.  *-----------------------------------------------------------------------------
  292.  *
  293.  * SigNameToNum --
  294.  *     Converts a UNIX signal name to its number, returns -1 if not found.
  295.  *     the name may be upper or lower case and may optionally have the 
  296.  *     leading "SIG" omitted.
  297.  *
  298.  *-----------------------------------------------------------------------------
  299.  */
  300. static int
  301. SigNameToNum (sigName)
  302.     char *sigName;
  303. {
  304.     char  sigNameUp [SIG_NAME_MAX+1];  /* Upshifted signal name */
  305.     char *sigNamePtr; 
  306.     int   idx;
  307.  
  308.     /*
  309.      * Copy and upshift requested name.
  310.      */
  311.  
  312.     if (strlen (sigName) > SIG_NAME_MAX)
  313.         return -1;   /* Name too long */
  314.  
  315.     Tcl_UpShift (sigNameUp, sigName);
  316.  
  317.     if (STRNEQU (sigNameUp, "SIG", 3))
  318.         sigNamePtr = &sigNameUp [3];
  319.     else
  320.         sigNamePtr = sigNameUp;
  321.  
  322.     for (idx = 0; sigNameTable [idx].num != -1; idx++)
  323.         if (STREQU (sigNamePtr, sigNameTable [idx].name))
  324.             break;
  325.  
  326.     return sigNameTable [idx].num;
  327. }
  328.  
  329. /*
  330.  *-----------------------------------------------------------------------------
  331.  *
  332.  * Tcl_KillCmd --
  333.  *     Implements the TCL kill command:
  334.  *        kill ?-pgroup? ?signal? idlist
  335.  *
  336.  * Results:
  337.  *  Standard TCL results, may return the UNIX system error message.
  338.  *-----------------------------------------------------------------------------
  339.  */
  340. int
  341. Tcl_KillCmd (clientData, interp, argc, argv)
  342.     ClientData  clientData;
  343.     Tcl_Interp *interp;
  344.     int     argc;
  345.     char      **argv;
  346. {
  347.     int    signalNum, nextArg, idx, procId, procArgc;
  348.     int    pgroup = FALSE;
  349.     char **procArgv;
  350.  
  351.     if (argc < 2)
  352.         goto usage;
  353.  
  354.     nextArg = 1;
  355.     if (STREQU (argv [nextArg], "-pgroup")) {
  356.         pgroup = TRUE;
  357.         nextArg++;
  358.     }
  359.         
  360.     if (((argc - nextArg) < 1) || ((argc - nextArg) > 2))
  361.         goto usage;
  362.  
  363.     if ((argc - nextArg) == 1) {
  364.         signalNum = SIGTERM;
  365.     } else {
  366.         if (!Tcl_StrToInt (argv[nextArg], 0, &signalNum)) {
  367.             signalNum = SigNameToNum (argv[nextArg]);
  368.         }
  369.         if ((signalNum < 0) || (signalNum > MAXSIG)) {
  370.             Tcl_AppendResult (interp, "invalid signal", (char *) NULL);
  371.             return TCL_ERROR;
  372.         }
  373.         nextArg++;
  374.     }
  375.  
  376.     if (Tcl_SplitList (interp, argv [nextArg], &procArgc, 
  377.                        &procArgv) != TCL_OK)
  378.         return TCL_ERROR;
  379.  
  380.     for (idx = 0; idx < procArgc; idx++) {
  381.         if (Tcl_GetInt (interp, procArgv [idx], &procId) != TCL_OK)
  382.             goto errorExit;
  383.         
  384.         if (pgroup)
  385.             procId = -procId;
  386.  
  387.         if (kill ((pid_t) procId, signalNum) < 0) {
  388.             Tcl_AppendResult (interp, "pid ", procArgv [idx],
  389.                               ": ", Tcl_PosixError (interp), (char *) NULL);
  390.             goto errorExit;
  391.         }
  392.      }
  393.  
  394.     ckfree ((char *) procArgv);
  395.     return TCL_OK;
  396.         
  397.   errorExit:
  398.     ckfree ((char *) procArgv);
  399.     return TCL_ERROR;;
  400.  
  401.   usage:
  402.     Tcl_AppendResult (interp, tclXWrongArgs, argv [0], 
  403.                       " ?-pgroup? ?signal? idlist", (char *) NULL);
  404.     return TCL_ERROR;
  405. }
  406.  
  407. /*
  408.  *-----------------------------------------------------------------------------
  409.  *
  410.  * GetSignalState --
  411.  *     Get the current state of the specified signal.
  412.  * Parameters:
  413.  *   o signalNum (I) - Signal number to query.
  414.  *   o sigProcPtr (O) - The signal function is returned here.
  415.  * Results
  416.  *   TCL_OK or TCL_ERROR (check errno).
  417.  *-----------------------------------------------------------------------------
  418.  */
  419. static int
  420. GetSignalState (signalNum, sigProcPtr)
  421.     int              signalNum;
  422.     signalProcPtr_t *sigProcPtr;
  423. {
  424. #ifdef HAVE_SIGACTION
  425.     struct sigaction currentState;
  426.  
  427.     if (sigaction (signalNum, NULL, ¤tState) < 0)
  428.         return TCL_ERROR;
  429.     *sigProcPtr = currentState.sa_handler;
  430.     return TCL_OK;
  431. #else
  432.     signalProcPtr_t  actionFunc;
  433.  
  434.     if (signalNum == SIGKILL)
  435.          actionFunc = SIG_DFL;
  436.     else
  437.         actionFunc = signal (signalNum, SIG_DFL);
  438.     if (actionFunc == SIG_ERR)
  439.         return TCL_ERROR;
  440.     if (actionFunc != SIG_DFL)
  441.         signal (signalNum, actionFunc);  /* reset */
  442.     *sigProcPtr = actionFunc;
  443.     return TCL_OK;
  444. #endif
  445. }
  446.  
  447. /*
  448.  *-----------------------------------------------------------------------------
  449.  *
  450.  * SetSignalAction --
  451.  *     Set the action to occur when a signal is received.
  452.  * Parameters:
  453.  *   o signalNum (I) - Signal number to query.
  454.  *   o sigFunc (O) - The signal function or SIG_DFL or SIG_IGN.
  455.  * Results
  456.  *   TCL_OK or TCL_ERROR (check errno).
  457.  *-----------------------------------------------------------------------------
  458.  */
  459. static int
  460. SetSignalAction (signalNum, sigFunc)
  461.     int             signalNum;
  462.     signalProcPtr_t sigFunc;
  463. {
  464. #ifdef HAVE_SIGACTION
  465.     struct sigaction newState;
  466.     
  467.     newState.sa_handler = sigFunc;
  468.     sigfillset (&newState.sa_mask);
  469.     newState.sa_flags = 0;
  470.  
  471.     if (sigaction (signalNum, &newState, NULL) < 0)
  472.         return TCL_ERROR;
  473.  
  474.     return TCL_OK;
  475. #else
  476.     if (signal (signalNum, sigFunc) == SIG_ERR)
  477.         return TCL_ERROR;
  478.     else
  479.         return TCL_OK;
  480. #endif
  481. }
  482.  
  483. /*
  484.  *-----------------------------------------------------------------------------
  485.  *
  486.  * TclSignalTrap --
  487.  *
  488.  *   Trap handler for UNIX signals.  Sets tells all registered interpreters
  489.  * that a trap has occured and saves the trap info.  The first interpreter to
  490.  * call it's async signal handler will process all pending signals.
  491.  *-----------------------------------------------------------------------------
  492.  */
  493. static RETSIGTYPE
  494. TclSignalTrap (signalNum)
  495.     int signalNum;
  496. {
  497.     int idx;
  498.  
  499.     /*
  500.      * Record the count of the number of this type of signal that has occured
  501.      * and tell all the interpreters to call the async handler when safe.
  502.      */
  503.     signalsReceived [signalNum]++;
  504.  
  505.     for (idx = 0; idx < numInterps; idx++)
  506.         Tcl_AsyncMark (interpTable [idx].handler);
  507.  
  508.     /*
  509.      * Flag used by command input functions to flush input.
  510.      */
  511.     if (signalTrapCmds [signalNum] == NULL) {
  512.         tclGotErrorSignal = TRUE;
  513.         if (tclErrorSignalProc != NULL)
  514.             (*tclErrorSignalProc) (signalNum);
  515.     }
  516. #ifndef HAVE_SIGACTION
  517.     /*
  518.      * For old-style Unix signals, the signal must be explictly re-enabled.
  519.      * Not done for SIGCHLD, as we would continue to the signal until the
  520.      * wait is done.  This is fixed by Posix signals and is not necessary under
  521.      * BSD, but it done this way for consistency.
  522.      */
  523.     if (signalNum != SIGCHLD) {
  524.         if (SetSignalAction (signalNum, TclSignalTrap) == TCL_ERROR)
  525.             panic ("TclSignalTrap bug");
  526.     }
  527. #endif
  528. }
  529.  
  530. /*
  531.  *-----------------------------------------------------------------------------
  532.  *
  533.  * SaveErrorState --
  534.  *  
  535.  *   Save the error state of the interpreter (result, errorInfo and errorCode).
  536.  *
  537.  * Parameters:
  538.  *   o interp (I) - The interpreter to save. Result will be reset.
  539.  * Returns:
  540.  *   A dynamically allocated structure containing all three strings,  Its
  541.  * allocated as a single malloc block.
  542.  *-----------------------------------------------------------------------------
  543.  */
  544. static errState_t *
  545. SaveErrorState (interp)
  546.     Tcl_Interp *interp;
  547. {
  548.     errState_t *errStatePtr;
  549.     char       *errorInfo, *errorCode, *nextPtr;
  550.     int         len;
  551.  
  552.     errorInfo = Tcl_GetVar (interp, "errorInfo", TCL_GLOBAL_ONLY);
  553.     errorCode = Tcl_GetVar (interp, "errorCode", TCL_GLOBAL_ONLY);
  554.  
  555.     len = sizeof (errState_t) + strlen (interp->result) + 1;
  556.     if (errorInfo != NULL)
  557.         len += strlen (errorInfo) + 1;
  558.     if (errorCode != NULL)
  559.         len += strlen (errorCode) + 1;
  560.  
  561.  
  562.     errStatePtr = (errState_t *) ckalloc (len);
  563.     nextPtr = ((char *) errStatePtr) + sizeof (errState_t);
  564.  
  565.     errStatePtr->result = nextPtr;
  566.     strcpy (errStatePtr->result, interp->result);
  567.     nextPtr += strlen (interp->result) + 1;
  568.  
  569.     errStatePtr->errorInfo = NULL;
  570.     if (errorInfo != NULL) {
  571.         errStatePtr->errorInfo = nextPtr;
  572.         strcpy (errStatePtr->errorInfo, errorInfo);
  573.         nextPtr += strlen (errorInfo) + 1;
  574.     }
  575.  
  576.     errStatePtr->errorCode = NULL;
  577.     if (errorCode != NULL) {
  578.         errStatePtr->errorCode = nextPtr;
  579.         strcpy (errStatePtr->errorCode, errorCode);
  580.         nextPtr += strlen (errorCode) + 1;
  581.     }
  582.  
  583.     Tcl_ResetResult (interp);
  584.     return errStatePtr;
  585. }
  586.  
  587. /*
  588.  *-----------------------------------------------------------------------------
  589.  *
  590.  * RestoreErrorState --
  591.  *  
  592.  *   Restore the error state of the interpreter that was saved by
  593.  * SaveErrorState.
  594.  *
  595.  * Parameters:
  596.  *   o interp (I) - The interpreter to save.
  597.  *   o errStatePtr (I) - Error state from SaveErrorState.  This structure will
  598.  *     be freed. 
  599.  * Returns:
  600.  *   A dynamically allocated structure containing all three strings,  Its
  601.  * allocated as a single malloc block.
  602.  *-----------------------------------------------------------------------------
  603.  */
  604. static void
  605. RestoreErrorState (interp, errStatePtr)
  606.     Tcl_Interp *interp;
  607.     errState_t *errStatePtr;
  608. {
  609.     Tcl_SetResult (interp, errStatePtr->result, TCL_VOLATILE);
  610.     if (errStatePtr->errorInfo != NULL)
  611.         Tcl_SetVar (interp, "errorInfo", errStatePtr->errorInfo,
  612.                     TCL_GLOBAL_ONLY);
  613.     if (errStatePtr->errorCode != NULL)
  614.         Tcl_SetVar (interp, "errorCode", errStatePtr->errorCode,
  615.                     TCL_GLOBAL_ONLY);
  616.  
  617.     ckfree (errStatePtr);
  618. }
  619.  
  620. /*
  621.  *-----------------------------------------------------------------------------
  622.  *
  623.  * FormatTrapCode --
  624.  *     Format the signal name into the signal trap command.  Replacing %S with
  625.  * the signal name.
  626.  *
  627.  * Parameters:
  628.  *   o interp (I/O) - The interpreter to return errors in.
  629.  *   o signalNum (I) - The signal number of the signal that occured.
  630.  *   o command (O) - The resulting command adter the formatting.
  631.  *-----------------------------------------------------------------------------
  632.  */
  633. static int
  634. FormatTrapCode (interp, signalNum, command)
  635.     Tcl_Interp  *interp;
  636.     int          signalNum;
  637.     Tcl_DString *command;
  638. {
  639.     char  *signalName, *copyPtr, *scanPtr, prevChar;
  640.  
  641.     /*
  642.      * Force name to always be SIGCHLD, even if system defines only SIGCLD.
  643.      */
  644.     if (signalNum == SIGCHLD)
  645.         signalName = "SIGCHLD";
  646.     else
  647.         signalName = Tcl_SignalId (signalNum);
  648.  
  649.     Tcl_DStringInit (command);
  650.  
  651.     copyPtr = scanPtr = signalTrapCmds [signalNum];
  652.  
  653.     while (*scanPtr != '\0') {
  654.         if (*scanPtr != '%') {
  655.             scanPtr++;
  656.             continue;
  657.         }
  658.         if (scanPtr [1] == '%') {
  659.             scanPtr += 2;
  660.             continue;
  661.         }
  662.         Tcl_DStringAppend (command, copyPtr, (scanPtr - copyPtr));
  663.  
  664.         switch (scanPtr [1]) {
  665.           case 'S': {
  666.               Tcl_DStringAppend (command, signalName, -1);
  667.               break;
  668.           }
  669.           default:
  670.             goto badSpec;
  671.         }
  672.         scanPtr += 2;
  673.         copyPtr = scanPtr;
  674.     }
  675.     Tcl_DStringAppend (command, copyPtr, copyPtr - scanPtr);
  676.  
  677.     return TCL_OK;
  678.  
  679.     /*
  680.      * Handle bad % specification currently pointed to by scanPtr.
  681.      */
  682.   badSpec:
  683.     {
  684.         char badSpec [2];
  685.         
  686.         badSpec [0] = scanPtr [1];
  687.         badSpec [1] = '\0';
  688.         Tcl_AppendResult (interp, "bad signal trap command formatting ",
  689.                           "specification \"%", badSpec,
  690.                           "\", expected one of \"%%\" or \"%S\"",
  691.                           (char *) NULL);
  692.         return TCL_ERROR;
  693.     }
  694. }
  695.  
  696. /*
  697.  *-----------------------------------------------------------------------------
  698.  *
  699.  * EvalTrapCode --
  700.  *     Run code as the result of a signal.  The symbolic signal name is
  701.  * formatted into the command replacing %S with the symbolic signal name.
  702.  *
  703.  * Parameters:
  704.  *   o interp (I) - The interpreter to run the signal in. If an error
  705.  *     occures, then the result will be left in the interp.
  706.  *   o signalNum (I) - The signal number of the signal that occured.
  707.  * Return:
  708.  *   TCL_OK or TCL_ERROR.
  709.  *-----------------------------------------------------------------------------
  710.  */
  711. static int
  712. EvalTrapCode (interp, signalNum)
  713.     Tcl_Interp *interp;
  714.     int         signalNum;
  715. {
  716.     int          result;
  717.     Tcl_DString  command;
  718.  
  719.     Tcl_ResetResult (interp);
  720.  
  721.     /*
  722.      * Format the signal name into the command.  This also allows the signal
  723.      * to be reset in the command.
  724.      */
  725.  
  726.     result = FormatTrapCode (interp,
  727.                              signalNum,
  728.                              &command);
  729.     if (result == TCL_OK)
  730.         result = Tcl_GlobalEval (interp, 
  731.                                  command.string);
  732.  
  733.     Tcl_DStringFree (&command);
  734.  
  735.     if (result == TCL_ERROR) {
  736.         char errorInfo [64];
  737.  
  738.         sprintf (errorInfo, "\n    while executing signal trap code for %s%s",
  739.                  Tcl_SignalId (signalNum), " signal");
  740.         Tcl_AddErrorInfo (interp, errorInfo);
  741.  
  742.         return TCL_ERROR;
  743.     }
  744.     
  745.     Tcl_ResetResult (interp);
  746.     return TCL_OK;
  747. }
  748.  
  749. /*
  750.  *-----------------------------------------------------------------------------
  751.  *
  752.  * ProcessASignal --
  753.  *  
  754.  *   Do processing on the specified signal.
  755.  *
  756.  * Parameters:
  757.  *   o interp (O) - Result will contain the result of the signal handling
  758.  *     code that was evaled.
  759.  *   o signalNum - The signal to process.
  760.  * Returns:
  761.  *   TCL_OK or TCL_ERROR.
  762.  *-----------------------------------------------------------------------------
  763.  */
  764. static int
  765. ProcessASignal (interp, signalNum)
  766.     Tcl_Interp *interp;
  767.     int         signalNum;
  768. {
  769.     char *signalName;
  770.     int   result = TCL_OK;
  771.  
  772.     /*
  773.      * Either return an error or evaluate code associated with this signal.
  774.      * If evaluating code, call it for each time the signal occured.
  775.      */
  776.     if (signalTrapCmds [signalNum] == NULL) {
  777.         signalsReceived [signalNum] = 0;
  778.  
  779.         /*
  780.          * Force name to always be SIGCHLD, even if system defines only SIGCLD.
  781.          */
  782.         if (signalNum == SIGCHLD)
  783.             signalName = "SIGCHLD";
  784.         else
  785.             signalName = Tcl_SignalId (signalNum);
  786.  
  787.         Tcl_SetErrorCode (interp, "POSIX", "SIG", signalName, (char*) NULL);
  788.         Tcl_AppendResult (interp, signalName, " signal received", 
  789.                           (char *)NULL);
  790.         Tcl_SetVar (interp, "errorInfo", "", TCL_GLOBAL_ONLY);
  791.         result = TCL_ERROR;
  792.     } else {
  793.         while (signalsReceived [signalNum] > 0) {
  794.             (signalsReceived [signalNum])--;
  795.             result = EvalTrapCode (interp, signalNum);
  796.             if (result == TCL_ERROR)
  797.                 break;
  798.         }
  799.     }
  800.     return result;
  801. }
  802.  
  803. /*
  804.  *-----------------------------------------------------------------------------
  805.  *
  806.  * Tcl_ProcessSignals --
  807.  *  
  808.  *   Called by Tcl_Eval, etc to process pending signals in a safe state
  809.  * interpreter state.  This is often called just after a command completes.
  810.  * The results of the command are passed to this procedure and may be altered
  811.  * by it.  If trap code is specified for the signal that was received, then
  812.  * the trap will be executed, otherwise an error result will be returned
  813.  * indicating that the signal occured.  If an error is returned, clear the
  814.  * errorInfo variable.  This makes sure it exists and that it is empty,
  815.  * otherwise bogus or non-existant information will be returned if this
  816.  * routine was called somewhere besides Tcl_Eval.  If a signal was received
  817.  * multiple times and a trap is set on it, then that trap will be executed for
  818.  * each time the signal was received.
  819.  * 
  820.  * Parameters:
  821.  *   o clientData (I) - Not used.
  822.  *   o interp (I/O) - interp->result should contain the result for
  823.  *     the command that just executed.  This will either be restored or
  824.  *     replaced with a new result.  If this is NULL, the no interpreter
  825.  *     is directly available (i.e. Tk event loop).  In this case, the first
  826.  *     interpreter in internal interpreter table is used.  If an error occurs,
  827.  *     it is handled via the error handler registerd in the global variable
  828.  *     "tclSignalBackgroundError"
  829.  *   o cmdResultCode (I) - The integer result returned by the command that
  830.  *     Tcl_Eval just completed.  Should be TCL_OK if not called from
  831.  *     Tcl_Eval.
  832.  * Returns:
  833.  *   Either the original result code, an error result if one of the
  834.  *   trap commands returned an error, or an error indicating the
  835.  *   a signal occured.
  836.  *-----------------------------------------------------------------------------
  837.  */
  838. int
  839. Tcl_ProcessSignals (clientData, interp, cmdResultCode)
  840.     ClientData  clientData;
  841.     Tcl_Interp *interp;
  842.     int         cmdResultCode;
  843. {
  844.     Tcl_Interp *sigInterp;
  845.     errState_t *errStatePtr;
  846.     int         signalNum, result, idx;
  847.  
  848.     /*
  849.      * Get the interpreter is it wasn't supplied, if none is available,
  850.      * bail out.
  851.      */
  852.     if (interp == NULL) {
  853.         if (numInterps == 0)
  854.             return cmdResultCode;
  855.         sigInterp = interpTable [0].interp;
  856.     } else {
  857.         sigInterp = interp;
  858.     }
  859.  
  860.     errStatePtr = SaveErrorState (sigInterp);
  861.  
  862.     /*
  863.      * Process all signals.  Don't process any more if one returns an error.
  864.      */
  865.     result = TCL_OK;
  866.  
  867.     for (signalNum = 1; signalNum < MAXSIG; signalNum++) {
  868.         if (signalsReceived [signalNum] == 0)
  869.             continue;
  870.         result = ProcessASignal (sigInterp, signalNum);
  871.         if (result == TCL_ERROR)
  872.             break;
  873.     }
  874.  
  875.     /*
  876.      * Restore result and error state if we didn't get an error in signal
  877.      * handling.
  878.      */
  879.     if (result != TCL_ERROR) {
  880.         RestoreErrorState (sigInterp, errStatePtr);
  881.     } else {
  882.         ckfree (errStatePtr);
  883.         cmdResultCode = TCL_ERROR;
  884.     }
  885.  
  886.     /*
  887.      * Reset the signal received flag in case more signals are pending.
  888.      */
  889.     for (signalNum = 1; signalNum < MAXSIG; signalNum++) {
  890.         if (signalsReceived [signalNum] != 0)
  891.             break;
  892.     }
  893.     if (signalNum < MAXSIG) {
  894.         for (idx = 0; idx < numInterps; idx++)
  895.             Tcl_AsyncMark (interpTable [idx].handler);
  896.     }
  897.  
  898.     /*
  899.      * If we got an error and an interpreter was not supplied, call the
  900.      * background error handler (if available).  Otherwise, lose the error.
  901.      */
  902.     if ((result == TCL_ERROR) && (interp == NULL) &&
  903.         (tclSignalBackgroundError != NULL))
  904.         (*tclSignalBackgroundError) (sigInterp);
  905.  
  906.     return cmdResultCode;
  907. }
  908.  
  909. /*
  910.  *-----------------------------------------------------------------------------
  911.  *
  912.  * ParseSignalList --
  913.  *  
  914.  *   Parse a list of signal names or numbers.
  915.  * 
  916.  * Parameters:
  917.  *   o interp (O) - Interpreter for returning errors.
  918.  *   o signalListStr (I) - The Tcl list of signals to convert.
  919.  *   o signalList (O) - The list of converted signal numbers, must be
  920.  *     big enough to hold MAXSIG signals.
  921.  *     Tcl_Eval just completed.
  922.  * Returns:
  923.  *   The number of signals converted, or -1 if an error occures.
  924.  *-----------------------------------------------------------------------------
  925.  */
  926. static int
  927. ParseSignalList (interp, signalListStr, signalList)
  928.     Tcl_Interp *interp;
  929.     char       *signalListStr;
  930.     int         signalList [];
  931. {
  932.     char         **signalListArgv;
  933.     int            signalListSize, signalNum, idx;
  934.     char          *signalName;
  935.  
  936.     if (Tcl_SplitList (interp, signalListStr, &signalListSize, 
  937.                        &signalListArgv) != TCL_OK)
  938.         return -1;
  939.  
  940.     if (signalListSize > MAXSIG) {
  941.         Tcl_AppendResult (interp, "too many signals supplied in list",
  942.                           (char *) NULL);
  943.         goto errorExit;
  944.     }
  945.  
  946.     if (signalListSize == 0) {
  947.         Tcl_AppendResult (interp, "signal list may not be empty",
  948.                           (char *) NULL);
  949.         goto errorExit;
  950.     }
  951.  
  952.     for (idx = 0; idx < signalListSize; idx++) {
  953.         signalName = signalListArgv [idx];
  954.  
  955.         if (Tcl_StrToInt (signalName, 0, &signalNum))
  956.             signalName = Tcl_SignalId (signalNum);
  957.         else
  958.             signalNum = SigNameToNum (signalName);
  959.  
  960.         if (signalName == NULL) {
  961.             char numBuf [20];
  962.  
  963.             sprintf (numBuf, "%d", signalNum);
  964.             Tcl_AppendResult (interp, "invalid signal number: ",
  965.                               numBuf, (char *) NULL);
  966.             goto errorExit;
  967.         }
  968.  
  969.         if ((signalNum < 1) || (signalNum > MAXSIG)) {
  970.             Tcl_AppendResult (interp, "invalid signal name: ",
  971.                               signalName, (char *) NULL);
  972.             goto errorExit;
  973.         }
  974.         signalList [idx] = signalNum;
  975.     }
  976.  
  977.     ckfree ((char *) signalListArgv);
  978.     return signalListSize;
  979.  
  980.   errorExit:
  981.     ckfree ((char *) signalListArgv);
  982.     return -1;
  983.  
  984. }
  985.  
  986. /*
  987.  *-----------------------------------------------------------------------------
  988.  *
  989.  * SignalBlocked --
  990.  *     
  991.  *    Determine if a signal is blocked.  On non-Posix systems, always returns
  992.  * "0".
  993.  *
  994.  * Parameters::
  995.  *   o interp (O) - Error messages are returned in result.
  996.  *   o signalNum (I) - The signal to determine the state for.
  997.  * Returns:
  998.  *   NULL if an error occured, or a pointer to a static string of "1" if the
  999.  * signal is block, and a static string of "0" if it is not blocked.
  1000.  *-----------------------------------------------------------------------------
  1001.  */
  1002. static char *
  1003. SignalBlocked (interp, signalNum)
  1004.     Tcl_Interp  *interp;
  1005.     int          signalNum;
  1006. {
  1007. #ifdef HAVE_SIGACTION
  1008.     int      idx;
  1009.     sigset_t sigBlockSet;
  1010.  
  1011.     if (sigprocmask (SIG_BLOCK, NULL, &sigBlockSet)) {
  1012.         interp->result = Tcl_PosixError (interp);
  1013.         return NULL;
  1014.     }
  1015.     return sigismember (&sigBlockSet, signalNum) ? "1" : "0";
  1016. #else
  1017.     return "0";
  1018. #endif
  1019. }
  1020.  
  1021. /*
  1022.  *-----------------------------------------------------------------------------
  1023.  *
  1024.  * GetSignalStates --
  1025.  *     
  1026.  *    Return a keyed list containing the signal states for the specified
  1027.  * signals.
  1028.  *
  1029.  * Parameters::
  1030.  *   o interp (O) - The list is returned in the result.
  1031.  *   o signalListSize (I) - Number of signals in the signal list.
  1032.  *   o signalList (I) - List of signals of requested signals.
  1033.  * Returns:
  1034.  *   TCL_OK or TCL_ERROR, with error message in interp.
  1035.  *-----------------------------------------------------------------------------
  1036.  */
  1037. static int
  1038. GetSignalStates (interp, signalListSize, signalList)
  1039.     Tcl_Interp *interp;
  1040.     int         signalListSize;
  1041.     int         signalList [MAXSIG];
  1042. {
  1043.     int              idx, signalNum, actuallyDone = -1;
  1044.     char            *stateKeyedList [MAXSIG];
  1045.     char            *sigState [3], *sigEntry [2];
  1046.     signalProcPtr_t  actionFunc;
  1047.  
  1048.     for (idx = 0; idx < signalListSize; idx ++) {
  1049.         signalNum = signalList [idx];
  1050.  
  1051.         if (GetSignalState (signalNum, &actionFunc) == TCL_ERROR)
  1052.             goto unixSigError;
  1053.         
  1054.         sigState [2] = NULL;
  1055.         if (actionFunc == SIG_DFL)
  1056.             sigState [0]  = "default";
  1057.         else if (actionFunc == SIG_IGN)
  1058.             sigState [0] = "ignore";
  1059.         else if (actionFunc == TclSignalTrap) {
  1060.             if (signalTrapCmds [signalNum] == NULL)
  1061.                 sigState [0] = "error";
  1062.             else {
  1063.                 sigState [0] = "trap";
  1064.                 sigState [2] = signalTrapCmds [signalNum];
  1065.             }
  1066.         } else {
  1067.             sigState [0] = "unknown";
  1068.         }
  1069.  
  1070.         sigState [1] = SignalBlocked (interp, signalNum);
  1071.         if (sigState [1] == NULL)
  1072.             goto unixSigError;
  1073.  
  1074.         sigEntry [0] = Tcl_SignalId (signalNum);
  1075.         sigEntry [1] = Tcl_Merge ((sigState [2] == NULL) ? 2 : 3,
  1076.                                   sigState);
  1077.  
  1078.         stateKeyedList [idx] = Tcl_Merge (2, sigEntry);
  1079.         ckfree (sigEntry [1]);
  1080.  
  1081.         actuallyDone = idx;
  1082.  
  1083.     }
  1084.     Tcl_SetResult (interp, Tcl_Merge (signalListSize, stateKeyedList),
  1085.                    TCL_DYNAMIC);
  1086.  
  1087.     for (idx = 0; idx <= actuallyDone; idx++)
  1088.         ckfree (stateKeyedList [idx]);
  1089.  
  1090.     return TCL_OK;
  1091.  
  1092.   unixSigError:
  1093.     for (idx = 0; idx <= actuallyDone; idx++)
  1094.         ckfree (stateKeyedList [idx]);
  1095.  
  1096.     interp->result = Tcl_PosixError (interp);
  1097.     return TCL_ERROR;
  1098. }
  1099.  
  1100. /*
  1101.  *-----------------------------------------------------------------------------
  1102.  *
  1103.  * SetSignalStates --
  1104.  *     
  1105.  *    Set the signal state for the specified signals.  
  1106.  *
  1107.  * Parameters::
  1108.  *   o interp (O) - The list is returned in the result.
  1109.  *   o signalListSize (I) - Number of signals in the signal list.
  1110.  *   o signalList (I) - List of signals of requested signals.
  1111.  *   o actionFunc (I) - The function to run when the signal is received.
  1112.  *   o command (I) - If the function is the "trap" function, this is the
  1113.  *     Tcl command to run when the trap occurs.  Otherwise, NULL.
  1114.  * Returns:
  1115.  *   TCL_OK or TCL_ERROR, with error message in interp.
  1116.  *-----------------------------------------------------------------------------
  1117.  */
  1118. static int
  1119. SetSignalStates (interp, signalListSize, signalList, actionFunc, command)
  1120.     Tcl_Interp      *interp;
  1121.     int              signalListSize;
  1122.     int              signalList [MAXSIG];
  1123.     signalProcPtr_t  actionFunc;
  1124.     char            *command;
  1125.  
  1126. {
  1127.     int idx, signalNum;
  1128.  
  1129.     for (idx = 0; idx < signalListSize; idx ++) {
  1130.         signalNum = signalList [idx];
  1131.  
  1132.         if (signalTrapCmds [signalNum] != NULL) {
  1133.             ckfree (signalTrapCmds [signalNum]);
  1134.             signalTrapCmds [signalNum] = NULL;
  1135.         }
  1136.         if (SetSignalAction (signalNum, actionFunc) == TCL_ERROR)
  1137.             goto unixSigError;
  1138.  
  1139.         if (command != NULL)
  1140.             signalTrapCmds [signalNum] = ckstrdup (command);
  1141.     }
  1142.  
  1143.     return TCL_OK;
  1144.  
  1145.   unixSigError:
  1146.     interp->result = Tcl_PosixError (interp);
  1147.     return TCL_ERROR;
  1148. }
  1149.  
  1150. /*
  1151.  *-----------------------------------------------------------------------------
  1152.  *
  1153.  * BlockSignals --
  1154.  *     
  1155.  *    Block or unblock the specified signals.  Returns an error if not a Posix
  1156.  * system.
  1157.  *
  1158.  * Parameters::
  1159.  *   o interp (O) - Error messages are returned in result.
  1160.  *   o action (I) - SIG_BLOCK or SIG_UNBLOCK.
  1161.  *   o signalListSize (I) - Number of signals in the signal list.
  1162.  *   o signalList (I) - List of signals of requested signals.
  1163.  * Returns:
  1164.  *   TCL_OK or TCL_ERROR, with error message in interp.
  1165.  *-----------------------------------------------------------------------------
  1166.  */
  1167. static int
  1168. BlockSignals (interp, action, signalListSize, signalList)
  1169.     Tcl_Interp  *interp;
  1170.     int          action;
  1171.     int          signalListSize;
  1172.     int          signalList [MAXSIG];
  1173. {
  1174. #ifdef HAVE_SIGACTION
  1175.     int      idx;
  1176.     sigset_t sigBlockSet;
  1177.  
  1178.     sigemptyset (&sigBlockSet);
  1179.  
  1180.     for (idx = 0; idx < signalListSize; idx ++)
  1181.         sigaddset (&sigBlockSet, signalList [idx]);
  1182.  
  1183.     if (sigprocmask (action, &sigBlockSet, NULL)) {
  1184.         interp->result = Tcl_PosixError (interp);
  1185.         return TCL_ERROR;
  1186.     }
  1187.  
  1188.     return TCL_OK;
  1189. #else
  1190.     interp->result = "Posix signals are not available on this system";
  1191.     return TCL_ERROR;
  1192. #endif
  1193. }
  1194.  
  1195. /*
  1196.  *-----------------------------------------------------------------------------
  1197.  *
  1198.  * Tcl_SignalCmd --
  1199.  *     Implements the TCL signal command:
  1200.  *         signal action siglist ?command?
  1201.  *
  1202.  * Results:
  1203.  *      Standard TCL results, may return the UNIX system error message.
  1204.  *
  1205.  * Side effects:
  1206.  *    Signal handling states may be changed.
  1207.  *-----------------------------------------------------------------------------
  1208.  */
  1209. static int
  1210. Tcl_SignalCmd (clientData, interp, argc, argv)
  1211.     char       *clientData;
  1212.     Tcl_Interp *interp;
  1213.     int         argc;
  1214.     char      **argv;
  1215. {
  1216.     int                  signalListSize, signalNum, idx;
  1217.     int                  signalList [MAXSIG], actionClass;
  1218.     char                *signalName;
  1219.     signalProcPtr_t      actionFunc;
  1220.     char                *command = NULL;
  1221.  
  1222.     if ((argc < 3) || (argc > 4)) {
  1223.         Tcl_AppendResult (interp, tclXWrongArgs, argv [0], 
  1224.                           " action signalList ?command?", (char *) NULL);
  1225.         return TCL_ERROR;
  1226.     }
  1227.  
  1228.     signalListSize = ParseSignalList (interp, argv [2], signalList);
  1229.     if (signalListSize < 0)    
  1230.         return TCL_ERROR;
  1231.  
  1232.     /*
  1233.      * Determine the action to take on all of the signals.
  1234.      */
  1235.     if (STREQU (argv [1], "trap")) {
  1236.         actionFunc = TclSignalTrap;
  1237.         actionClass = SIGACT_SET;
  1238.         if (argc != 4) {
  1239.             Tcl_AppendResult (interp, "command required for ",
  1240.                              "trapping signals", (char *) NULL);
  1241.             return TCL_ERROR;
  1242.         }
  1243.         command = argv [3];
  1244.     } else {
  1245.         if (STREQU (argv [1], "default")) {
  1246.             actionFunc  = SIG_DFL;
  1247.             actionClass = SIGACT_SET;
  1248.         } else if (STREQU (argv [1], "ignore")) {
  1249.             actionFunc = SIG_IGN;
  1250.             actionClass = SIGACT_SET;
  1251.         } else if (STREQU (argv [1], "error")) {
  1252.             actionFunc = TclSignalTrap;
  1253.             actionClass = SIGACT_SET;
  1254.         } else if (STREQU (argv [1], "get")) {
  1255.             actionClass = SIGACT_GET;
  1256.         } else if (STREQU (argv [1], "block")) {
  1257.             actionClass = SIGACT_BLOCK;
  1258.         } else if (STREQU (argv [1], "unblock")) {
  1259.             actionClass = SIGACT_UNBLOCK;
  1260.         } else {
  1261.             Tcl_AppendResult (interp, "invalid signal action specified: ", 
  1262.                               argv [1], ": expected one of \"default\", ",
  1263.                               "\"ignore\", \"error\", \"trap\", or \"get\", ",
  1264.                               "\"block\", \"unblock\"", (char *) NULL);
  1265.             return TCL_ERROR;
  1266.         }
  1267.         if (argc != 3) {
  1268.             Tcl_AppendResult (interp, "command may not be ",
  1269.                               "specified for \"", argv [1], "\" action",
  1270.                               (char *) NULL);
  1271.             return TCL_ERROR;
  1272.         }
  1273.     }
  1274.  
  1275.     /*
  1276.      * Process the specified action class.
  1277.      */
  1278.     switch (actionClass) {
  1279.       case SIGACT_SET:
  1280.         return SetSignalStates (interp, signalListSize, signalList,
  1281.                                 actionFunc, command);
  1282.       case SIGACT_GET:
  1283.         return GetSignalStates (interp, signalListSize, signalList);
  1284.       case SIGACT_BLOCK:
  1285.         return BlockSignals (interp, SIG_BLOCK, signalListSize, signalList);
  1286.       case SIGACT_UNBLOCK:
  1287.         return BlockSignals (interp, SIG_UNBLOCK, signalListSize, signalList);
  1288.     }
  1289.  
  1290. }
  1291.  
  1292. /*
  1293.  *-----------------------------------------------------------------------------
  1294.  *
  1295.  *  SignalCmdCleanUp --
  1296.  *
  1297.  *   Clean up the signal data structure when an interpreter is deleted. If
  1298.  * this is the last interpreter, clean up all tables.
  1299.  *
  1300.  * Parameters:
  1301.  *   o clientData (I) - Not used.
  1302.  *   o interp (I) - Interp that is being deleted.
  1303.  *-----------------------------------------------------------------------------
  1304.  */
  1305. static void
  1306. SignalCmdCleanUp (clientData, interp)
  1307.     ClientData  clientData;
  1308.     Tcl_Interp *interp;
  1309. {
  1310.     int  idx;
  1311.  
  1312.     for (idx = 0; idx < numInterps; idx++) {
  1313.         if (interpTable [idx].interp == interp)
  1314.             break;
  1315.     }
  1316.     if (idx == numInterps)
  1317.         panic ("signal interp lost");
  1318.  
  1319.     interpTable [idx] = interpTable [--numInterps];
  1320.  
  1321.     /*
  1322.      * If there are no more interpreters, clean everything up.
  1323.      */
  1324.     if (numInterps == 0) {
  1325.         ckfree (interpTable);
  1326.         interpTable = NULL;
  1327.         interpTableSize = 0;
  1328.  
  1329.         for (idx = 0; idx < MAXSIG; idx++) {
  1330.             if (signalTrapCmds [idx] != NULL) {
  1331.                 ckfree (signalTrapCmds [idx]);
  1332.                 signalTrapCmds [idx] = NULL;
  1333.             }
  1334.         }
  1335.     }
  1336. }
  1337.  
  1338. /*
  1339.  *-----------------------------------------------------------------------------
  1340.  *
  1341.  * Tcl_SetupSigInt --
  1342.  *    Set up SIGINT to the "error" state if the current state is default.
  1343.  * This is done because shells set SIGINT to ignore for background processes
  1344.  * so that they don't die on signals generated by the user at the keyboard.
  1345.  * Tcl only enables SIGINT catching if it is an interactive session.
  1346.  *-----------------------------------------------------------------------------
  1347.  */
  1348. void
  1349. Tcl_SetupSigInt ()
  1350. {
  1351.     signalProcPtr_t  actionFunc;
  1352.  
  1353.     if ((GetSignalState (SIGINT, &actionFunc) == TCL_OK) &&
  1354.         (actionFunc == SIG_DFL))
  1355.         SetSignalAction (SIGINT, TclSignalTrap);
  1356. }
  1357.  
  1358. /*
  1359.  *-----------------------------------------------------------------------------
  1360.  *
  1361.  * Tcl_InitSignalHandling --
  1362.  *      Initializes singal handling for a interpreter.
  1363.  *-----------------------------------------------------------------------------
  1364.  */
  1365. void
  1366. Tcl_InitSignalHandling (interp)
  1367.     Tcl_Interp *interp;
  1368. {
  1369.     int              idx;
  1370.     interpHandler_t *newTable;
  1371.  
  1372.     /*
  1373.      * If this is the first interpreter, set everything up.
  1374.      */
  1375.     if (numInterps == 0) {
  1376.         interpTableSize = 4;
  1377.         interpTable = (interpHandler_t *)
  1378.             ckalloc (sizeof (interpHandler_t) * interpTableSize);
  1379.  
  1380.         for (idx = 0; idx < MAXSIG; idx++) {
  1381.             signalsReceived [idx] = 0;
  1382.             signalTrapCmds [idx] = NULL;
  1383.         }
  1384.     }
  1385.  
  1386.     /*
  1387.      * If there is not room in this table for another interp, expand it.
  1388.      */
  1389.     if (numInterps == interpTableSize) {
  1390.         newTable = (interpHandler_t *)
  1391.             ckalloc (sizeof (interpHandler_t) * interpTableSize * 2);
  1392.         memcpy (newTable, interpTable,
  1393.                 sizeof (interpHandler_t) * interpTableSize);
  1394.         ckfree (interpTable);
  1395.         interpTable = newTable;
  1396.         interpTableSize *= 2;
  1397.     }
  1398.  
  1399.     /*
  1400.      * Add this interpreter to the list and set up a async handler.
  1401.      * Arange for clean up on the interpreter being deleted.
  1402.      */
  1403.     interpTable [numInterps].interp = interp;
  1404.     interpTable [numInterps].handler =
  1405.         Tcl_AsyncCreate (Tcl_ProcessSignals, (ClientData) NULL);
  1406.     numInterps++;
  1407.  
  1408.     Tcl_CallWhenDeleted (interp, SignalCmdCleanUp, (ClientData) NULL);
  1409.  
  1410.     Tcl_CreateCommand (interp, "kill", Tcl_KillCmd,
  1411.                        (ClientData) NULL, (void (*)()) NULL);
  1412.     Tcl_CreateCommand (interp, "signal", Tcl_SignalCmd,
  1413.                        (ClientData) NULL, (void (*)()) NULL);
  1414. }
  1415.