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 / tclXutil.c < prev   
Encoding:
C/C++ Source or Header  |  1993-11-19  |  17.2 KB  |  636 lines

  1. /*
  2.  * tclXutil.c
  3.  *
  4.  * Utility functions for Extended Tcl.
  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: tclXutil.c,v 3.0 1993/11/19 06:59:28 markd Rel $
  16.  *-----------------------------------------------------------------------------
  17.  */
  18.  
  19. #include "tclExtdInt.h"
  20.  
  21. #ifndef _tolower
  22. #  define _tolower tolower
  23. #  define _toupper toupper
  24. #endif
  25.  
  26. /*
  27.  * Used to return argument messages by most commands.
  28.  */
  29. char *tclXWrongArgs = "wrong # args: ";
  30.  
  31.  
  32. /*
  33.  *-----------------------------------------------------------------------------
  34.  *
  35.  * Tcl_StrToLong --
  36.  *      Convert an Ascii string to an long number of the specified base.
  37.  *
  38.  * Parameters:
  39.  *   o string (I) - String containing a number.
  40.  *   o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
  41.  *     based on the leading characters of the number.  Zero to let the number
  42.  *     determine the base.
  43.  *   o longPtr (O) - Place to return the converted number.  Will be 
  44.  *     unchanged if there is an error.
  45.  *
  46.  * Returns:
  47.  *      Returns 1 if the string was a valid number, 0 invalid.
  48.  *-----------------------------------------------------------------------------
  49.  */
  50. int
  51. Tcl_StrToLong (string, base, longPtr)
  52.     CONST char *string;
  53.     int         base;
  54.     long       *longPtr;
  55. {
  56.     char *end;
  57.     long  num;
  58.  
  59.     num = strtol(string, &end, base);
  60.     while ((*end != '\0') && ISSPACE(*end)) {
  61.         end++;
  62.     }
  63.     if ((end == string) || (*end != 0))
  64.         return FALSE;
  65.     *longPtr = num;
  66.     return TRUE;
  67.  
  68. }
  69.  
  70. /*
  71.  *-----------------------------------------------------------------------------
  72.  *
  73.  * Tcl_StrToInt --
  74.  *      Convert an Ascii string to an number of the specified base.
  75.  *
  76.  * Parameters:
  77.  *   o string (I) - String containing a number.
  78.  *   o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
  79.  *     based on the leading characters of the number.  Zero to let the number
  80.  *     determine the base.
  81.  *   o intPtr (O) - Place to return the converted number.  Will be 
  82.  *     unchanged if there is an error.
  83.  *
  84.  * Returns:
  85.  *      Returns 1 if the string was a valid number, 0 invalid.
  86.  *-----------------------------------------------------------------------------
  87.  */
  88. int
  89. Tcl_StrToInt (string, base, intPtr)
  90.     CONST char *string;
  91.     int         base;
  92.     int        *intPtr;
  93. {
  94.     char *end;
  95.     int   num;
  96.  
  97.     num = strtol(string, &end, base);
  98.     while ((*end != '\0') && ISSPACE(*end)) {
  99.         end++;
  100.     }
  101.     if ((end == string) || (*end != 0))
  102.         return FALSE;
  103.     *intPtr = num;
  104.     return TRUE;
  105.  
  106. }
  107.  
  108. /*
  109.  *-----------------------------------------------------------------------------
  110.  *
  111.  * Tcl_StrToUnsigned --
  112.  *      Convert an Ascii string to an unsigned int of the specified base.
  113.  *
  114.  * Parameters:
  115.  *   o string (I) - String containing a number.
  116.  *   o base (I) - The base to use for the number 8, 10 or 16 or zero to decide
  117.  *     based on the leading characters of the number.  Zero to let the number
  118.  *     determine the base.
  119.  *   o unsignedPtr (O) - Place to return the converted number.  Will be 
  120.  *     unchanged if there is an error.
  121.  *
  122.  * Returns:
  123.  *      Returns 1 if the string was a valid number, 0 invalid.
  124.  *-----------------------------------------------------------------------------
  125.  */
  126. int
  127. Tcl_StrToUnsigned (string, base, unsignedPtr)
  128.     CONST char *string;
  129.     int         base;
  130.     unsigned   *unsignedPtr;
  131. {
  132.     char          *end;
  133.     unsigned long  num;
  134.  
  135.     num = strtoul (string, &end, base);
  136.     while ((*end != '\0') && ISSPACE(*end)) {
  137.         end++;
  138.     }
  139.     if ((end == string) || (*end != 0))
  140.         return FALSE;
  141.     *unsignedPtr = num;
  142.     return TRUE;
  143.  
  144. }
  145.  
  146. /*
  147.  *-----------------------------------------------------------------------------
  148.  *
  149.  * Tcl_StrToDouble --
  150.  *   Convert a string to a double percision floating point number.
  151.  *
  152.  * Parameters:
  153.  *   string (I) - Buffer containing double value to convert.
  154.  *   doublePtr (O) - The convert floating point number.
  155.  * Returns:
  156.  *   TRUE if the number is ok, FALSE if it is illegal.
  157.  *-----------------------------------------------------------------------------
  158.  */
  159. int
  160. Tcl_StrToDouble (string, doublePtr)
  161.     CONST char *string;
  162.     double     *doublePtr;
  163. {
  164.     char   *end;
  165.     double  num;
  166.  
  167.     num = strtod (string, &end);
  168.     while ((*end != '\0') && ISSPACE(*end)) {
  169.         end++;
  170.     }
  171.     if ((end == string) || (*end != 0))
  172.         return FALSE;
  173.  
  174.     *doublePtr = num;
  175.     return TRUE;
  176.  
  177. }
  178.  
  179. /*
  180.  *-----------------------------------------------------------------------------
  181.  *
  182.  * Tcl_DownShift --
  183.  *     Utility procedure to down-shift a string.  It is written in such
  184.  *     a way as that the target string maybe the same as the source string.
  185.  *
  186.  * Parameters:
  187.  *   o targetStr (I) - String to store the down-shifted string in.  Must
  188.  *     have enough space allocated to store the string.  If NULL is specified,
  189.  *     then the string will be dynamicly allocated and returned as the
  190.  *     result of the function. May also be the same as the source string to
  191.  *     shift in place.
  192.  *   o sourceStr (I) - The string to down-shift.
  193.  *
  194.  * Returns:
  195.  *   A pointer to the down-shifted string
  196.  *-----------------------------------------------------------------------------
  197.  */
  198. char *
  199. Tcl_DownShift (targetStr, sourceStr)
  200.     char       *targetStr;
  201.     CONST char *sourceStr;
  202. {
  203.     register char theChar;
  204.  
  205.     if (targetStr == NULL)
  206.         targetStr = ckalloc (strlen ((char *) sourceStr) + 1);
  207.  
  208.     for (; (theChar = *sourceStr) != '\0'; sourceStr++) {
  209.         if (isupper (theChar))
  210.             theChar = _tolower (theChar);
  211.         *targetStr++ = theChar;
  212.     }
  213.     *targetStr = '\0';
  214.     return targetStr;
  215. }
  216.  
  217. /*
  218.  *-----------------------------------------------------------------------------
  219.  *
  220.  * Tcl_UpShift --
  221.  *     Utility procedure to up-shift a string.
  222.  *
  223.  * Parameters:
  224.  *   o targetStr (I) - String to store the up-shifted string in.  Must
  225.  *     have enough space allocated to store the string.  If NULL is specified,
  226.  *     then the string will be dynamicly allocated and returned as the
  227.  *     result of the function. May also be the same as the source string to
  228.  *     shift in place.
  229.  *   o sourceStr (I) - The string to up-shift.
  230.  *
  231.  * Returns:
  232.  *   A pointer to the up-shifted string
  233.  *-----------------------------------------------------------------------------
  234.  */
  235. char *
  236. Tcl_UpShift (targetStr, sourceStr)
  237.     char       *targetStr;
  238.     CONST char *sourceStr;
  239. {
  240.     register char theChar;
  241.  
  242.     if (targetStr == NULL)
  243.         targetStr = ckalloc (strlen ((char *) sourceStr) + 1);
  244.  
  245.     for (; (theChar = *sourceStr) != '\0'; sourceStr++) {
  246.         if (ISLOWER (theChar))
  247.             theChar = _toupper (theChar);
  248.         *targetStr++ = theChar;
  249.     }
  250.     *targetStr = '\0';
  251.     return targetStr;
  252. }
  253.  
  254. /*
  255.  *-----------------------------------------------------------------------------
  256.  *
  257.  * Tcl_DStringGets --
  258.  *
  259.  *    Reads a line from a file into a dynamic string.  The string will be
  260.  * expanded, if necessary and reads are done until EOL or EOF is reached.
  261.  * The line is appended to any data already in the string.
  262.  *
  263.  * Parameter
  264.  *   o filePtr (I) - File to read from.
  265.  *   o dynStrPtr (I) - String to return the data in.
  266.  * Returns:
  267.  *    o TCL_BREAK - EOF
  268.  *    o TCL_OK - If data was transfered.
  269.  *    o TCL_ERROR - An error occured.
  270.  *-----------------------------------------------------------------------------
  271.  */
  272. int
  273. Tcl_DStringGets (filePtr, dynStrPtr)
  274.     FILE         *filePtr;
  275.     Tcl_DString  *dynStrPtr;
  276. {
  277.     char           buffer [128];
  278.     register char *bufPtr, *bufEnd;
  279.     register int   readVal;
  280.     int            startLength = dynStrPtr->length;
  281.  
  282.     bufPtr = buffer;
  283.     bufEnd = buffer + sizeof (buffer) - 1;
  284.  
  285.     clearerr (filePtr);  /* Clear previous error/EOF */
  286.  
  287.     while (TRUE) {
  288.         readVal = getc (filePtr);
  289.         if (readVal == '\n')      /* Is it a new-line? */
  290.             break;
  291.         if (readVal == EOF)
  292.             break;
  293.         *bufPtr++ = readVal;
  294.         if (bufPtr > bufEnd) {
  295.             Tcl_DStringAppend (dynStrPtr, buffer, sizeof (buffer));
  296.             bufPtr = buffer;
  297.         }
  298.     }
  299.     if ((readVal == EOF) && ferror (filePtr))
  300.         return TCL_ERROR;   /* Error */
  301.  
  302.     if (bufPtr != buffer) {
  303.         Tcl_DStringAppend (dynStrPtr, buffer, bufPtr - buffer);
  304.     }
  305.  
  306.     if ((readVal == EOF) && dynStrPtr->length == startLength)
  307.         return TCL_BREAK;
  308.     else
  309.         return TCL_OK;
  310. }
  311.  
  312. /*
  313.  *-----------------------------------------------------------------------------
  314.  *
  315.  * Tcl_GetLong --
  316.  *
  317.  *      Given a string, produce the corresponding long value.
  318.  *
  319.  * Results:
  320.  *      The return value is normally TCL_OK;  in this case *longPtr
  321.  *      will be set to the integer value equivalent to string.  If
  322.  *      string is improperly formed then TCL_ERROR is returned and
  323.  *      an error message will be left in interp->result.
  324.  *
  325.  * Side effects:
  326.  *      None.
  327.  *
  328.  *-----------------------------------------------------------------------------
  329.  */
  330. int
  331. Tcl_GetLong(interp, string, longPtr)
  332.     Tcl_Interp *interp;
  333.     CONST char *string;
  334.     long       *longPtr;
  335. {
  336.     char *end;
  337.     long  i;
  338.  
  339.     i = strtol(string, &end, 0);
  340.     while ((*end != '\0') && ISSPACE(*end)) {
  341.         end++;
  342.     }
  343.     if ((end == string) || (*end != 0)) {
  344.         Tcl_AppendResult (interp, "expected integer but got \"", string,
  345.                           "\"", (char *) NULL);
  346.         return TCL_ERROR;
  347.     }
  348.     *longPtr = i;
  349.     return TCL_OK;
  350. }
  351.  
  352. /*
  353.  *-----------------------------------------------------------------------------
  354.  *
  355.  * Tcl_GetUnsigned --
  356.  *
  357.  *      Given a string, produce the corresponding unsigned integer value.
  358.  *
  359.  * Results:
  360.  *      The return value is normally TCL_OK;  in this case *unsignedPtr
  361.  *      will be set to the integer value equivalent to string.  If
  362.  *      string is improperly formed then TCL_ERROR is returned and
  363.  *      an error message will be left in interp->result.
  364.  *
  365.  * Side effects:
  366.  *      None.
  367.  *
  368.  *-----------------------------------------------------------------------------
  369.  */
  370. int
  371. Tcl_GetUnsigned(interp, string, unsignedPtr)
  372.     Tcl_Interp *interp;
  373.     CONST char *string;
  374.     unsigned   *unsignedPtr;
  375. {
  376.     char          *end;
  377.     unsigned long  i;
  378.  
  379.     /*
  380.      * Since some strtoul functions don't detect negative numbers, check
  381.      * in advance.
  382.      */
  383.     while (ISSPACE(*string))
  384.         string++;
  385.     if (string [0] == '-')
  386.         goto badUnsigned;
  387.  
  388.     i = strtoul(string, &end, 0);
  389.     while ((*end != '\0') && ISSPACE(*end))
  390.         end++;
  391.  
  392.     if ((end == string) || (*end != '\0'))
  393.         goto badUnsigned;
  394.  
  395.     *unsignedPtr = i;
  396.     return TCL_OK;
  397.  
  398.   badUnsigned:
  399.     Tcl_AppendResult (interp, "expected unsigned integer but got \"", 
  400.                       string, "\"", (char *) NULL);
  401.     return TCL_ERROR;
  402. }
  403.  
  404. /*
  405.  *-----------------------------------------------------------------------------
  406.  *
  407.  * Tcl_GetTime --
  408.  *
  409.  *      Given a string, produce the corresponding time_t value.
  410.  *
  411.  * Results:
  412.  *      The return value is normally TCL_OK;  in this case *timepPtr
  413.  *      will be set to the integer value equivalent to string.  If
  414.  *      string is improperly formed then TCL_ERROR is returned and
  415.  *      an error message will be left in interp->result.
  416.  *
  417.  * Side effects:
  418.  *      None.
  419.  *
  420.  *-----------------------------------------------------------------------------
  421.  */
  422. int
  423. Tcl_GetTime(interp, string, timePtr)
  424.     Tcl_Interp *interp;
  425.     CONST char *string;
  426.     time_t     *timePtr;
  427. {
  428.     char   *end;
  429.     long   i;
  430.     time_t time;
  431.  
  432.     i = strtol(string, &end, 0);
  433.     while ((*end != '\0') && ISSPACE(*end)) {
  434.         end++;
  435.     }
  436.     if ((end == string) || (*end != 0))
  437.         goto badTime;
  438.  
  439.     time = (time_t) i;
  440.     if (time != i)
  441.         goto badTime;
  442.  
  443.     *timePtr = time;
  444.     return TCL_OK;
  445.  
  446.   badTime:
  447.     Tcl_AppendResult (interp, "integer time \"", string, "\" to large\"",
  448.                       (char *) NULL);
  449.     return TCL_ERROR;
  450. }
  451.  
  452. /*
  453.  *-----------------------------------------------------------------------------
  454.  *
  455.  * Tcl_RelativeExpr --
  456.  *
  457.  *    Evaluate an expression that may start with the magic words "end" or
  458.  * "len".  These strings are replaced with either the end offset or the
  459.  * length that is passed in.
  460.  *
  461.  * Parameters:
  462.  *   o interp (I) - A pointer to the interpreter.
  463.  *   o cstringExpr (I) - The expression to evaludate.
  464.  *   o stringLen (I) - The length of the string.
  465.  *   o exprResultPtr (O) - The result of the expression is returned here.
  466.  * Returns:
  467.  *   TCL_OK or TCL_ERROR.
  468.  *-----------------------------------------------------------------------------
  469.  */
  470. int
  471. Tcl_RelativeExpr (interp, cstringExpr, stringLen, exprResultPtr)
  472.     Tcl_Interp  *interp;
  473.     char        *cstringExpr;
  474.     long         stringLen;
  475.     long        *exprResultPtr;
  476. {
  477.     
  478.     char *buf;
  479.     int   exprLen, result;
  480.     char  staticBuf [64];
  481.  
  482.     if (!(STRNEQU (cstringExpr, "end", 3) ||
  483.           STRNEQU (cstringExpr, "len", 3))) {
  484.         return Tcl_ExprLong (interp, cstringExpr, exprResultPtr);
  485.     }
  486.  
  487.     sprintf (staticBuf, "%ld",
  488.              stringLen - ((cstringExpr [0] == 'e') ? 1 : 0));
  489.     exprLen = strlen (staticBuf) + strlen (cstringExpr) - 2;
  490.  
  491.     buf = staticBuf;
  492.     if (exprLen > sizeof (staticBuf)) {
  493.         buf = (char *) ckalloc (exprLen);
  494.         strcpy (buf, staticBuf);
  495.     }
  496.     strcat (buf, cstringExpr + 3);
  497.  
  498.     result = Tcl_ExprLong (interp, buf, exprResultPtr);
  499.  
  500.     if (buf != staticBuf)
  501.         ckfree (buf);
  502.     return result;
  503. }
  504.  
  505. /*
  506.  *-----------------------------------------------------------------------------
  507.  *
  508.  * Tcl_GetOpenFileStruct --
  509.  *
  510.  *    Convert a file handle to a pointer to the internal Tcl file structure.
  511.  *
  512.  * Parameters:
  513.  *   o interp (I) - Current interpreter.
  514.  *   o handle (I) - The file handle to convert.
  515.  * Returns:
  516.  *   A pointer to the open file structure for the file, or NULL if an error
  517.  * occured.
  518.  *-----------------------------------------------------------------------------
  519.  */
  520. OpenFile *
  521. Tcl_GetOpenFileStruct (interp, handle)
  522.     Tcl_Interp *interp;
  523.     char       *handle;
  524. {
  525.     FILE   *filePtr;
  526.  
  527.     if (Tcl_GetOpenFile (interp, handle,
  528.                          FALSE, FALSE,  /* No checking */
  529.                          &filePtr) != TCL_OK)
  530.         return NULL;
  531.  
  532.     return tclOpenFiles [fileno (filePtr)];
  533. }
  534.  
  535. /*
  536.  *-----------------------------------------------------------------------------
  537.  *
  538.  * Tcl_SetupFileEntry --
  539.  *
  540.  * Set up an entry in the Tcl file table for a file number, including the stdio
  541.  * FILE structure.
  542.  *
  543.  * Parameters:
  544.  *   o interp (I) - Current interpreter.
  545.  *   o fileNum (I) - File number to set up the entry for.
  546.  *   o permissions (I) - Flags consisting of TCL_FILE_READABLE,
  547.  *     TCL_FILE_WRITABLE.
  548.  * Returns:
  549.  *   A pointer to the FILE structure for the file, or NULL if an error
  550.  * occured.
  551.  *-----------------------------------------------------------------------------
  552.  */
  553. FILE *
  554. Tcl_SetupFileEntry (interp, fileNum, permissions)
  555.     Tcl_Interp *interp;
  556.     int         fileNum;
  557.     int         permissions;
  558. {
  559.     Interp   *iPtr = (Interp *) interp;
  560.     char     *mode;
  561.     FILE     *filePtr;
  562.  
  563.     /*
  564.      * Set up a stdio FILE control block for the new file.
  565.      */
  566.     if (permissions & TCL_FILE_WRITABLE) {
  567.         if (permissions & TCL_FILE_READABLE)
  568.             mode = "r+";
  569.         else
  570.             mode = "w";
  571.     } else {
  572.         mode = "r";
  573.     }
  574.  
  575.     filePtr = fdopen (fileNum, mode);
  576.     if (filePtr == NULL) {
  577.         iPtr->result = Tcl_PosixError (interp);
  578.         return NULL;
  579.     }
  580.     
  581.     Tcl_EnterFile (interp, filePtr, permissions);
  582.  
  583.     return filePtr;
  584. }
  585.  
  586. /*
  587.  *-----------------------------------------------------------------------------
  588.  *
  589.  * Tcl_CloseForError --
  590.  *
  591.  *   Close a file number on error.  If the file is in the Tcl file table, clean
  592.  * it up too. The variable errno, and interp->result and the errorCode variable
  593.  * will be saved and not lost.
  594.  *
  595.  * Parameters:
  596.  *   o interp (I) - Current interpreter.
  597.  *   o fileNum (I) - File number to close.
  598.  *-----------------------------------------------------------------------------
  599.  */
  600. void
  601. Tcl_CloseForError (interp, fileNum)
  602.     Tcl_Interp *interp;
  603.     int         fileNum;
  604. {
  605.     static char *ERROR_CODE = "errorCode";
  606.     int          saveErrNo = errno;
  607.     char        *saveResult, *errorCode, *saveErrorCode, *argv [2], buf [32];
  608.  
  609.     saveResult = ckstrdup (interp->result);
  610.  
  611.     errorCode = Tcl_GetVar (interp, ERROR_CODE, TCL_GLOBAL_ONLY);
  612.     if (errorCode != NULL)
  613.         saveErrorCode = ckstrdup (errorCode);
  614.     else
  615.         saveErrorCode = NULL;
  616.  
  617.     sprintf (buf, "file%d", fileNum);
  618.  
  619.     argv [0] = "close";
  620.     argv [1] = buf;
  621.     Tcl_CloseCmd (NULL, interp, 2, argv);
  622.     Tcl_ResetResult (interp);
  623.  
  624.     if (saveErrorCode != NULL) {
  625.         Tcl_SetVar (interp, ERROR_CODE, saveErrorCode, TCL_GLOBAL_ONLY);
  626.         free (saveErrorCode);
  627.     }
  628.     Tcl_SetResult (interp, saveResult, TCL_VOLATILE);
  629.     free (saveResult);
  630.  
  631.     close (fileNum);  /* In case Tcl didn't have it open */
  632.     
  633.     errno = saveErrNo;
  634. }
  635.      
  636.