home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tcl / os2 / tclClock.c < prev    next >
C/C++ Source or Header  |  1998-08-07  |  9KB  |  354 lines

  1. /* 
  2.  * tclClock.c --
  3.  *
  4.  *    Contains the time and date related commands.  This code
  5.  *    is derived from the time and date facilities of TclX,
  6.  *    by Mark Diekhans and Karl Lehenbauer.
  7.  *
  8.  * Copyright 1991-1995 Karl Lehenbauer and Mark Diekhans.
  9.  * Copyright (c) 1995 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tclClock.c 1.19 96/03/13 11:28:45
  15.  */
  16.  
  17. #include "tcl.h"
  18. #include "tclInt.h"
  19. #include "tclPort.h"
  20.  
  21. /*
  22.  * Function prototypes for local procedures in this file:
  23.  */
  24.  
  25. static int        FormatClock _ANSI_ARGS_((Tcl_Interp *interp,
  26.                 unsigned long clockVal, int useGMT,
  27.                 char *format));
  28. static int        ParseTime _ANSI_ARGS_((Tcl_Interp *interp,
  29.                 char *string, unsigned long *timePtr));
  30.  
  31. /*
  32.  *-----------------------------------------------------------------------------
  33.  *
  34.  * Tcl_ClockCmd --
  35.  *
  36.  *    This procedure is invoked to process the "clock" Tcl command.
  37.  *    See the user documentation for details on what it does.
  38.  *
  39.  * Results:
  40.  *    A standard Tcl result.
  41.  *
  42.  * Side effects:
  43.  *    See the user documentation.
  44.  *
  45.  *-----------------------------------------------------------------------------
  46.  */
  47.  
  48. int
  49. Tcl_ClockCmd (dummy, interp, argc, argv)
  50.     ClientData dummy;            /* Not used. */
  51.     Tcl_Interp *interp;            /* Current interpreter. */
  52.     int argc;                /* Number of arguments. */
  53.     char **argv;            /* Argument strings. */
  54. {
  55.     int c;
  56.     size_t length;
  57.     char **argPtr;
  58.     int useGMT = 0;
  59.     unsigned long clockVal;
  60.     
  61.     if (argc < 2) {
  62.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  63.         argv[0], " option ?arg ...?\"", (char *) NULL);
  64.     return TCL_ERROR;
  65.     }
  66.     c = argv[1][0];
  67.     length = strlen(argv[1]);
  68.     if ((c == 'c') && (strncmp(argv[1], "clicks", length) == 0)) {
  69.     if (argc != 2) {
  70.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  71.             argv[0], " clicks\"", (char *) NULL);
  72.         return TCL_ERROR;
  73.     }
  74.     sprintf(interp->result, "%lu", TclGetClicks());
  75.     return TCL_OK;
  76.     } else if ((c == 'f') && (strncmp(argv[1], "format", length) == 0)) {
  77.     char *format = "%a %b %d %X %Z %Y";
  78.     
  79.     if ((argc < 3) || (argc > 7)) {
  80.         wrongFmtArgs:
  81.         Tcl_AppendResult(interp, "wrong # args: ", argv [0], 
  82.             " format clockval ?-format string? ?-gmt boolean?",
  83.             (char *) NULL);
  84.         return TCL_ERROR;
  85.     }
  86.  
  87.     if (ParseTime(interp, argv[2], &clockVal) != TCL_OK) {
  88.         return TCL_ERROR;
  89.     }
  90.  
  91.     argPtr = argv+3;
  92.     argc -= 3;
  93.     while ((argc > 1) && (argPtr[0][0] == '-')) {
  94.         if (strcmp(argPtr[0], "-format") == 0) {
  95.             format = argPtr[1];
  96.         } else if (strcmp(argPtr[0], "-gmt") == 0) {
  97.         if (Tcl_GetBoolean(interp, argPtr[1], &useGMT) != TCL_OK) {
  98.             return TCL_ERROR;
  99.         }
  100.         } else {
  101.         Tcl_AppendResult(interp, "bad option \"", argPtr[0],
  102.             "\": must be -format or -gmt", (char *) NULL);
  103.         return TCL_ERROR;
  104.         }
  105.         argPtr += 2;
  106.         argc -= 2;
  107.     }
  108.     if (argc != 0) {
  109.         goto wrongFmtArgs;
  110.     }
  111.  
  112.     return FormatClock(interp, clockVal, useGMT, format);
  113.     } else if ((c == 's') && (strncmp(argv[1], "scan", length) == 0)) {
  114.     unsigned long baseClock;
  115.     long zone;
  116.     char * baseStr = NULL;
  117.  
  118.     if ((argc < 3) || (argc > 7)) {
  119.         wrongScanArgs:
  120.         Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  121.             " scan dateString ?-base clockValue? ?-gmt boolean?",
  122.             (char *) NULL);
  123.         return TCL_ERROR;
  124.     }
  125.  
  126.     argPtr = argv+3;
  127.     argc -= 3;
  128.     while ((argc > 1) && (argPtr[0][0] == '-')) {
  129.         if (strcmp(argPtr[0], "-base") == 0) {
  130.             baseStr = argPtr[1];
  131.         } else if (strcmp(argPtr[0], "-gmt") == 0) {
  132.         if (Tcl_GetBoolean(interp, argPtr[1], &useGMT) != TCL_OK) {
  133.             return TCL_ERROR;
  134.         }
  135.         } else {
  136.         Tcl_AppendResult(interp, "bad option \"", argPtr[0],
  137.             "\": must be -base or -gmt", (char *) NULL);
  138.         return TCL_ERROR;
  139.         }
  140.         argPtr += 2;
  141.         argc -= 2;
  142.     }
  143.     if (argc != 0) {
  144.         goto wrongScanArgs;
  145.     }
  146.     
  147.     if (baseStr != NULL) {
  148.         if (ParseTime(interp, baseStr, &baseClock) != TCL_OK)
  149.         return TCL_ERROR;
  150.     } else {
  151.         baseClock = TclGetSeconds();
  152.     }
  153.  
  154.     if (useGMT) {
  155.         zone = -50000; /* Force GMT */
  156.     } else {
  157.         zone = TclGetTimeZone(baseClock);
  158.     }
  159.  
  160.     if (TclGetDate(argv[2], baseClock, zone, &clockVal) < 0) {
  161.         Tcl_AppendResult(interp, "unable to convert date-time string \"",
  162.             argv[2], "\"", (char *) NULL);
  163.         return TCL_ERROR;
  164.     }
  165.  
  166.     sprintf(interp->result, "%lu", (long) clockVal);
  167.     return TCL_OK;
  168.     } else if ((c == 's') && (strncmp(argv[1], "seconds", length) == 0)) {
  169.     if (argc != 2) {
  170.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  171.             argv[0], " seconds\"", (char *) NULL);
  172.         return TCL_ERROR;
  173.     }
  174.     sprintf(interp->result, "%lu", TclGetSeconds());
  175.     return TCL_OK;
  176.     } else {
  177.     Tcl_AppendResult(interp, "unknown option \"", argv[1],
  178.         "\": must be clicks, format, scan, or seconds",
  179.         (char *) NULL);
  180.     return TCL_ERROR;
  181.     }
  182. }
  183.  
  184. /*
  185.  *-----------------------------------------------------------------------------
  186.  *
  187.  * ParseTime --
  188.  *
  189.  *      Given a string, produce the corresponding time_t value.
  190.  *
  191.  * Results:
  192.  *      The return value is normally TCL_OK;  in this case *timePtr
  193.  *      will be set to the integer value equivalent to string.  If
  194.  *      string is improperly formed then TCL_ERROR is returned and
  195.  *      an error message will be left in interp->result.
  196.  *
  197.  * Side effects:
  198.  *      None.
  199.  *
  200.  *-----------------------------------------------------------------------------
  201.  */
  202.  
  203. static int
  204. ParseTime(interp, string, timePtr)
  205.     Tcl_Interp *interp;
  206.     char *string;
  207.     unsigned long *timePtr;
  208. {
  209.     char *end, *p;
  210.     unsigned long  i;
  211.  
  212.     /*
  213.      * Since some strtoul functions don't detect negative numbers, check
  214.      * in advance.
  215.      */
  216.     errno = 0;
  217.     for (p = (char *) string; isspace(UCHAR(*p)); p++) {
  218.         /* Empty loop body. */
  219.     }
  220.     if (*p == '+') {
  221.         p++;
  222.     }
  223.     i = strtoul(p, &end, 0);
  224.     if (end == p) {
  225.         goto badTime;
  226.     }
  227.     if (errno == ERANGE) {
  228.     interp->result = "integer value too large to represent";
  229.     Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  230.         interp->result, (char *) NULL);
  231.     return TCL_ERROR;
  232.     }
  233.     while ((*end != '\0') && isspace(UCHAR(*end))) {
  234.         end++;
  235.     }
  236.     if (*end != '\0') {
  237.         goto badTime;
  238.     }
  239.  
  240.     *timePtr = (time_t) i;
  241.     if (*timePtr != i) {
  242.         goto badTime;
  243.     }
  244.     return TCL_OK;
  245.  
  246.   badTime:
  247.     Tcl_AppendResult (interp, "expected unsigned time but got \"", 
  248.                       string, "\"", (char *) NULL);
  249.     return TCL_ERROR;
  250. }
  251.  
  252. /*
  253.  *-----------------------------------------------------------------------------
  254.  *
  255.  * FormatClock --
  256.  *
  257.  *      Formats a time value based on seconds into a human readable
  258.  *    string.
  259.  *
  260.  * Results:
  261.  *      Standard Tcl result.
  262.  *
  263.  * Side effects:
  264.  *      None.
  265.  *
  266.  *-----------------------------------------------------------------------------
  267.  */
  268.  
  269. static int
  270. FormatClock(interp, clockVal, useGMT, format)
  271.     Tcl_Interp *interp;            /* Current interpreter. */
  272.     unsigned long clockVal;               /* Time in seconds. */
  273.     int useGMT;                /* Boolean */
  274.     char *format;            /* Format string */
  275. {
  276.     struct tm *timeDataPtr;
  277.     Tcl_DString buffer;
  278.     int bufSize;
  279. #ifdef TCL_USE_TIMEZONE_VAR
  280.     int savedTimeZone;
  281.     char *savedTZEnv;
  282. #endif
  283.  
  284. #ifdef HAVE_TZSET
  285.     /*
  286.      * Some systems forgot to call tzset in localtime, make sure its done.
  287.      */
  288.     static int  calledTzset = 0;
  289.  
  290.     if (!calledTzset) {
  291.         tzset();
  292.         calledTzset = 1;
  293.     }
  294. #endif
  295.  
  296. #ifdef TCL_USE_TIMEZONE_VAR
  297.     /*
  298.      * This is a horrible kludge for systems not having the timezone in
  299.      * struct tm.  No matter what was specified, they use the global time
  300.      * zone.  (Thanks Solaris).
  301.      */
  302.     if (useGMT) {
  303.         char *varValue;
  304.  
  305.         varValue = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
  306.         if (varValue != NULL) {
  307.         savedTZEnv = strcpy(ckalloc(strlen(varValue) + 1), varValue);
  308.         } else {
  309.             savedTZEnv = NULL;
  310.     }
  311.         Tcl_SetVar2(interp, "env", "TZ", "GMT", TCL_GLOBAL_ONLY);
  312.         savedTimeZone = timezone;
  313.         timezone = 0;
  314.         tzset();
  315.     }
  316. #endif
  317.  
  318.     if (useGMT) {
  319.         timeDataPtr = gmtime((time_t *) &clockVal);
  320.     } else {
  321.         timeDataPtr = localtime((time_t *) &clockVal);
  322.     }
  323.     
  324.     /*
  325.      * Format the time, increasing the buffer size until strftime succeeds.
  326.      */
  327.     bufSize = TCL_DSTRING_STATIC_SIZE - 1;
  328.     Tcl_DStringInit(&buffer);
  329.     Tcl_DStringSetLength(&buffer, bufSize);
  330.  
  331.     while (strftime(buffer.string, (unsigned int) bufSize, format,
  332.         timeDataPtr) == 0) {
  333.         bufSize *= 2;
  334.         Tcl_DStringSetLength(&buffer, bufSize);
  335.     }
  336.  
  337. #ifdef TCL_USE_TIMEZONE_VAR
  338.     if (useGMT) {
  339.         if (savedTZEnv != NULL) {
  340.             Tcl_SetVar2(interp, "env", "TZ", savedTZEnv, TCL_GLOBAL_ONLY);
  341.             ckfree(savedTZEnv);
  342.         } else {
  343.             Tcl_UnsetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
  344.         }
  345.         timezone = savedTimeZone;
  346.         tzset();
  347.     }
  348. #endif
  349.  
  350.     Tcl_DStringResult(interp, &buffer);
  351.     return TCL_OK;
  352. }
  353.  
  354.