tclClock.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:10k
源码类别:

通讯编程

开发平台:

Visual C++

  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.  * RCS: @(#) $Id: tclClock.c,v 1.20.2.4 2007/08/25 17:12:20 kennykb Exp $
  15.  */
  16. #include "tcl.h"
  17. #include "tclInt.h"
  18. #include "tclPort.h"
  19. /*
  20.  * The date parsing stuff uses lexx and has tons o statics.
  21.  */
  22. TCL_DECLARE_MUTEX(clockMutex)
  23. /*
  24.  * Function prototypes for local procedures in this file:
  25.  */
  26. static int FormatClock _ANSI_ARGS_((Tcl_Interp *interp,
  27.     Tcl_WideInt clockVal, int useGMT,
  28.     char *format));
  29. /*
  30.  *-------------------------------------------------------------------------
  31.  *
  32.  * Tcl_ClockObjCmd --
  33.  *
  34.  * This procedure is invoked to process the "clock" Tcl command.
  35.  * See the user documentation for details on what it does.
  36.  *
  37.  * Results:
  38.  * A standard Tcl result.
  39.  *
  40.  * Side effects:
  41.  * See the user documentation.
  42.  *
  43.  *-------------------------------------------------------------------------
  44.  */
  45. int
  46. Tcl_ClockObjCmd (client, interp, objc, objv)
  47.     ClientData client; /* Not used. */
  48.     Tcl_Interp *interp; /* Current interpreter. */
  49.     int objc; /* Number of arguments. */
  50.     Tcl_Obj *CONST objv[]; /* Argument values. */
  51. {
  52.     Tcl_Obj *resultPtr;
  53.     int index;
  54.     Tcl_Obj *CONST *objPtr;
  55.     int useGMT = 0;
  56.     char *format = "%a %b %d %X %Z %Y";
  57.     int dummy;
  58.     Tcl_WideInt baseClock, clockVal;
  59.     long zone;
  60.     Tcl_Obj *baseObjPtr = NULL;
  61.     char *scanStr;
  62.     int n;
  63.     
  64.     static CONST char *switches[] =
  65. {"clicks", "format", "scan", "seconds", (char *) NULL};
  66.     enum command { COMMAND_CLICKS, COMMAND_FORMAT, COMMAND_SCAN,
  67.        COMMAND_SECONDS
  68.     };
  69.     static CONST char *formatSwitches[] = {"-format", "-gmt", (char *) NULL};
  70.     static CONST char *scanSwitches[] = {"-base", "-gmt", (char *) NULL};
  71.     resultPtr = Tcl_GetObjResult(interp);
  72.     if (objc < 2) {
  73. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
  74. return TCL_ERROR;
  75.     }
  76.     if (Tcl_GetIndexFromObj(interp, objv[1], switches, "option", 0, &index)
  77.     != TCL_OK) {
  78. return TCL_ERROR;
  79.     }
  80.     switch ((enum command) index) {
  81. case COMMAND_CLICKS: { /* clicks */
  82.     int forceMilli = 0;
  83.     if (objc == 3) {
  84. format = Tcl_GetStringFromObj(objv[2], &n);
  85. if ( ( n >= 2 ) 
  86.      && ( strncmp( format, "-milliseconds",
  87.    (unsigned int) n) == 0 ) ) {
  88.     forceMilli = 1;
  89. } else {
  90.     Tcl_AppendStringsToObj(resultPtr,
  91.     "bad switch "", format,
  92.     "": must be -milliseconds", (char *) NULL);
  93.     return TCL_ERROR;
  94. }
  95.     } else if (objc != 2) {
  96. Tcl_WrongNumArgs(interp, 2, objv, "?-milliseconds?");
  97. return TCL_ERROR;
  98.     }
  99.     if (forceMilli) {
  100. /*
  101.  * We can enforce at least millisecond granularity
  102.  */
  103. Tcl_Time time;
  104. Tcl_GetTime(&time);
  105. Tcl_SetLongObj(resultPtr,
  106. (long) (time.sec*1000 + time.usec/1000));
  107.     } else {
  108. Tcl_SetLongObj(resultPtr, (long) TclpGetClicks());
  109.     }
  110.     return TCL_OK;
  111. }
  112. case COMMAND_FORMAT: /* format */
  113.     if ((objc < 3) || (objc > 7)) {
  114. wrongFmtArgs:
  115. Tcl_WrongNumArgs(interp, 2, objv,
  116. "clockval ?-format string? ?-gmt boolean?");
  117. return TCL_ERROR;
  118.     }
  119.     if (Tcl_GetWideIntFromObj(interp, objv[2], &clockVal)
  120.     != TCL_OK) {
  121. return TCL_ERROR;
  122.     }
  123.     
  124.     objPtr = objv+3;
  125.     objc -= 3;
  126.     while (objc > 1) {
  127. if (Tcl_GetIndexFromObj(interp, objPtr[0], formatSwitches,
  128. "switch", 0, &index) != TCL_OK) {
  129.     return TCL_ERROR;
  130. }
  131. switch (index) {
  132.     case 0: /* -format */
  133. format = Tcl_GetStringFromObj(objPtr[1], &dummy);
  134. break;
  135.     case 1: /* -gmt */
  136. if (Tcl_GetBooleanFromObj(interp, objPtr[1],
  137. &useGMT) != TCL_OK) {
  138.     return TCL_ERROR;
  139. }
  140. break;
  141. }
  142. objPtr += 2;
  143. objc -= 2;
  144.     }
  145.     if (objc != 0) {
  146. goto wrongFmtArgs;
  147.     }
  148.     return FormatClock(interp, clockVal, useGMT,
  149.     format);
  150. case COMMAND_SCAN: /* scan */
  151.     if ((objc < 3) || (objc > 7)) {
  152. wrongScanArgs:
  153. Tcl_WrongNumArgs(interp, 2, objv,
  154. "dateString ?-base clockValue? ?-gmt boolean?");
  155. return TCL_ERROR;
  156.     }
  157.     objPtr = objv+3;
  158.     objc -= 3;
  159.     while (objc > 1) {
  160. if (Tcl_GetIndexFromObj(interp, objPtr[0], scanSwitches,
  161. "switch", 0, &index) != TCL_OK) {
  162.     return TCL_ERROR;
  163. }
  164. switch (index) {
  165.     case 0: /* -base */
  166. baseObjPtr = objPtr[1];
  167. break;
  168.     case 1: /* -gmt */
  169. if (Tcl_GetBooleanFromObj(interp, objPtr[1],
  170. &useGMT) != TCL_OK) {
  171.     return TCL_ERROR;
  172. }
  173. break;
  174. }
  175. objPtr += 2;
  176. objc -= 2;
  177.     }
  178.     if (objc != 0) {
  179. goto wrongScanArgs;
  180.     }
  181.     if (baseObjPtr != NULL) {
  182. if (Tcl_GetWideIntFromObj(interp, baseObjPtr,
  183.   &baseClock) != TCL_OK) {
  184.     return TCL_ERROR;
  185. }
  186.     } else {
  187. baseClock = TclpGetSeconds();
  188.     }
  189.     if (useGMT) {
  190. zone = -50000; /* Force GMT */
  191.     } else {
  192. zone = TclpGetTimeZone(baseClock);
  193.     }
  194.     scanStr = Tcl_GetStringFromObj(objv[2], &dummy);
  195.     Tcl_MutexLock(&clockMutex);
  196.     if (TclGetDate(scanStr, baseClock, zone,
  197.     &clockVal) < 0) {
  198. Tcl_MutexUnlock(&clockMutex);
  199. Tcl_AppendStringsToObj(resultPtr,
  200. "unable to convert date-time string "",
  201. scanStr, """, (char *) NULL);
  202. return TCL_ERROR;
  203.     }
  204.     Tcl_MutexUnlock(&clockMutex);
  205.     Tcl_SetWideIntObj(resultPtr, clockVal);
  206.     return TCL_OK;
  207. case COMMAND_SECONDS: /* seconds */
  208.     if (objc != 2) {
  209. Tcl_WrongNumArgs(interp, 2, objv, NULL);
  210. return TCL_ERROR;
  211.     }
  212.     Tcl_SetLongObj(resultPtr, (long) TclpGetSeconds());
  213.     return TCL_OK;
  214. default:
  215.     return TCL_ERROR; /* Should never be reached. */
  216.     }
  217. }
  218. /*
  219.  *-----------------------------------------------------------------------------
  220.  *
  221.  * FormatClock --
  222.  *
  223.  *      Formats a time value based on seconds into a human readable
  224.  * string.
  225.  *
  226.  * Results:
  227.  *      Standard Tcl result.
  228.  *
  229.  * Side effects:
  230.  *      None.
  231.  *
  232.  *-----------------------------------------------------------------------------
  233.  */
  234. static int
  235. FormatClock(interp, clockVal, useGMT, format)
  236.     Tcl_Interp *interp; /* Current interpreter. */
  237.     Tcl_WideInt clockVal;         /* Time in seconds. */
  238.     int useGMT; /* Boolean */
  239.     char *format; /* Format string */
  240. {
  241.     struct tm *timeDataPtr;
  242.     Tcl_DString buffer, uniBuffer;
  243.     int bufSize;
  244.     char *p;
  245.     int result;
  246.     time_t tclockVal;
  247. #if !defined(HAVE_TM_ZONE) && !defined(WIN32)
  248.     TIMEZONE_t savedTimeZone = 0; /* lint. */
  249.     char *savedTZEnv = NULL; /* lint. */
  250. #endif
  251. #ifdef HAVE_TZSET
  252.     /*
  253.      * Some systems forgot to call tzset in localtime, make sure its done.
  254.      */
  255.     static int  calledTzset = 0;
  256.     Tcl_MutexLock(&clockMutex);
  257.     if (!calledTzset) {
  258.         tzset();
  259.         calledTzset = 1;
  260.     }
  261.     Tcl_MutexUnlock(&clockMutex);
  262. #endif
  263.     /*
  264.      * If the user gave us -format "", just return now
  265.      */
  266.     if (*format == '') {
  267. return TCL_OK;
  268.     }
  269. #if !defined(HAVE_TM_ZONE) && !defined(WIN32)
  270.     /*
  271.      * This is a kludge for systems not having the timezone string in
  272.      * struct tm.  No matter what was specified, they use the local
  273.      * timezone string.  Since this kludge requires fiddling with the
  274.      * TZ environment variable, it will mess up if done on multiple
  275.      * threads at once.  Protect it with a the clock mutex.
  276.      */
  277.     Tcl_MutexLock( &clockMutex );
  278.     if (useGMT) {
  279.         CONST char *varValue;
  280.         varValue = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
  281.         if (varValue != NULL) {
  282.     savedTZEnv = strcpy(ckalloc(strlen(varValue) + 1), varValue);
  283.         } else {
  284.             savedTZEnv = NULL;
  285. }
  286.         Tcl_SetVar2(interp, "env", "TZ", "GMT0", TCL_GLOBAL_ONLY);
  287.         savedTimeZone = timezone;
  288.         timezone = 0;
  289.         tzset();
  290.     }
  291. #endif
  292.     tclockVal = (time_t) clockVal;
  293.     timeDataPtr = TclpGetDate((TclpTime_t) &tclockVal, useGMT);
  294.     
  295.     /*
  296.      * Make a guess at the upper limit on the substituted string size
  297.      * based on the number of percents in the string.
  298.      */
  299.     for (bufSize = 1, p = format; *p != ''; p++) {
  300. if (*p == '%') {
  301.     bufSize += 40;
  302.     if (p[1] == 'c') {
  303. bufSize += 226;
  304.     }
  305. } else {
  306.     bufSize++;
  307. }
  308.     }
  309.     Tcl_DStringInit(&uniBuffer);
  310.     Tcl_UtfToExternalDString(NULL, format, -1, &uniBuffer);
  311.     Tcl_DStringInit(&buffer);
  312.     Tcl_DStringSetLength(&buffer, bufSize);
  313.     /* If we haven't locked the clock mutex up above, lock it now. */
  314. #if defined(HAVE_TM_ZONE) || defined(WIN32)
  315.     Tcl_MutexLock(&clockMutex);
  316. #endif
  317.     result = TclpStrftime(buffer.string, (unsigned int) bufSize,
  318.     Tcl_DStringValue(&uniBuffer), timeDataPtr, useGMT);
  319. #if defined(HAVE_TM_ZONE) || defined(WIN32)
  320.     Tcl_MutexUnlock(&clockMutex);
  321. #endif
  322.     Tcl_DStringFree(&uniBuffer);
  323. #if !defined(HAVE_TM_ZONE) && !defined(WIN32)
  324.     if (useGMT) {
  325.         if (savedTZEnv != NULL) {
  326.             Tcl_SetVar2(interp, "env", "TZ", savedTZEnv, TCL_GLOBAL_ONLY);
  327.             ckfree(savedTZEnv);
  328.         } else {
  329.             Tcl_UnsetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
  330.         }
  331.         timezone = savedTimeZone;
  332.         tzset();
  333.     }
  334.     Tcl_MutexUnlock( &clockMutex );
  335. #endif
  336.     if (result == 0) {
  337. /*
  338.  * A zero return is the error case (can also mean the strftime
  339.  * didn't get enough space to write into).  We know it doesn't
  340.  * mean that we wrote zero chars because the check for an empty
  341.  * format string is above.
  342.  */
  343. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  344. "bad format string "", format, """, (char *) NULL);
  345. return TCL_ERROR;
  346.     }
  347.     /*
  348.      * Convert the time to UTF from external encoding [Bug: 3345]
  349.      */
  350.     Tcl_DStringInit(&uniBuffer);
  351.     Tcl_ExternalToUtfDString(NULL, buffer.string, -1, &uniBuffer);
  352.     Tcl_SetStringObj(Tcl_GetObjResult(interp), uniBuffer.string, -1);
  353.     Tcl_DStringFree(&uniBuffer);
  354.     Tcl_DStringFree(&buffer);
  355.     return TCL_OK;
  356. }