#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#define TZFILE "/etc/TZ"
static char TZ[128];
static char std[32] = "GMT0";
static char dst[32];
char *tzname[2] = {
std, dst
};
time_t tzoffset, tzdstoffset;
int tzdst = 0;
static int
offset(char *env, time_t *off)
{
int n, sign;
size_t len, retlen;
retlen = 0;
sign = 1;
/*
* strictly, no sign is allowed in the 'time' part of the
* dst start/stop rules, but who cares?
*/
if (*env == '-' || *env == '+') {
if (*env++ == '-')
sign = -1;
retlen++;
}
if ((len = strspn(env, ":0123456789")) == 0)
return 0;
retlen += len;
for (*off = 0; len && isdigit(*env); len--) /* hours */
*off = *off*10 + (*env++ - '0')*60*60;
if (len) {
if (*env++ != ':')
return 0;
len--;
}
for (n = 0; len && isdigit(*env); len--) /* minutes */
n = n*10 + (*env++ - '0')*60;
*off += n;
if (len) {
if (*env++ != ':')
return 0;
len--;
}
for (n = 0; len && isdigit(*env); len--) /* seconds */
n = n*10 + (*env++ - '0');
*off = (*off + n)*sign;
return retlen;
}
/*
* TZ=stdoffset[dst[offset][,start[/time],end[/time]]]
*/
void
tzset(void)
{
char *env, *p, envbuf[128];
int fd, i;
size_t len, retlen;
time_t off;
/*
* get the TZ environment variable and check for validity.
* the implementation-defined manner for dealing with the
* leading ':' format is to reject it.
* if it's ok, stash a copy away for quick comparison next time.
*/
if ((env = getenv("TZ")) == 0) {
if ((fd = open(TZFILE, O_RDONLY)) == -1)
return;
if (read(fd, envbuf, sizeof(envbuf)-1) == -1) {
close(fd);
return;
}
close(fd);
for (i = 0; i < sizeof(envbuf); i++) {
if (envbuf[i] != '\n')
continue;
envbuf[i] = '\0';
break;
}
env = envbuf;
}
if (strcmp(env, TZ) == 0)
return;
if (*env == 0 || *env == ':')
return;
strncpy(TZ, env, sizeof(TZ)-1);
TZ[sizeof(TZ)-1] = 0;
/*
* get the 'std' string.
* before committing, check there is a valid offset.
*/
if ((len = strcspn(env, ":0123456789,-+")) == 0)
return;
if ((retlen = offset(env+len, &off)) == 0)
return;
for (p = std, i = len+retlen; i; i--)
*p++ = *env++;
*p = 0;
tzoffset = -off;
/*
* get the 'dst' string (if any).
*/
if (*env == 0 || (len = strcspn(env, ":0123456789,-+")) == 0)
return;
for (p = dst; len; len--)
*p++ = *env++;
*p = 0;
/*
* optional dst offset.
* default is one hour.
*/
tzdst = 1;
if (retlen = offset(env+len, &off)) {
tzdstoffset = -off;
env += retlen;
}
else
tzdstoffset = tzoffset + 60*60;
/*
* optional rule(s) for start/end of dst.
*/
if (*env == 0 || *env != ',' || *(env+1) == 0)
return;
env++;
/*
* we could go on...
* but why bother?
*/
USED(env);
}
|