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