summaryrefslogtreecommitdiff
path: root/sys/src/ape/lib/ap/posix/tzset.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/ape/lib/ap/posix/tzset.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/ape/lib/ap/posix/tzset.c')
-rwxr-xr-xsys/src/ape/lib/ap/posix/tzset.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/sys/src/ape/lib/ap/posix/tzset.c b/sys/src/ape/lib/ap/posix/tzset.c
new file mode 100755
index 000000000..8502c6d66
--- /dev/null
+++ b/sys/src/ape/lib/ap/posix/tzset.c
@@ -0,0 +1,141 @@
+#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?
+ */
+}