Annotation of src/usr.bin/ts/ts.c, Revision 1.6
1.6 ! cheloha 1: /* $OpenBSD: ts.c,v 1.5 2022/07/03 15:06:06 deraadt Exp $ */
1.1 job 2: /*
3: * Copyright (c) 2022 Job Snijders <job@openbsd.org>
4: * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
1.5 deraadt 19: #include <sys/types.h>
1.1 job 20: #include <sys/time.h>
21:
22: #include <err.h>
23: #include <stdint.h>
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <unistd.h>
28: #include <time.h>
29:
30: static char *format = "%b %d %H:%M:%S";
31: static char *buf;
32: static char *outbuf;
33: static size_t bufsize;
34:
35: static void fmtfmt(struct tm *, long);
36: static void __dead usage(void);
37:
38: int
39: main(int argc, char *argv[])
40: {
1.2 job 41: int iflag, mflag, sflag;
1.1 job 42: int ch, prev;
1.3 claudio 43: struct timespec roff, start, now;
44: struct tm *tm;
1.6 ! cheloha 45: clockid_t clock = CLOCK_REALTIME;
1.1 job 46:
47: if (pledge("stdio", NULL) == -1)
48: err(1, "pledge");
49:
1.2 job 50: iflag = mflag = sflag = 0;
1.1 job 51:
1.2 job 52: while ((ch = getopt(argc, argv, "ims")) != -1) {
1.1 job 53: switch (ch) {
54: case 'i':
55: iflag = 1;
56: format = "%H:%M:%S";
1.2 job 57: clock = CLOCK_MONOTONIC;
58: break;
59: case 'm':
60: mflag = 1;
61: clock = CLOCK_MONOTONIC;
1.1 job 62: break;
63: case 's':
64: sflag = 1;
65: format = "%H:%M:%S";
1.2 job 66: clock = CLOCK_MONOTONIC;
1.1 job 67: break;
68: default:
69: usage();
70: }
71: }
72: argc -= optind;
73: argv += optind;
74:
75: if ((iflag && sflag) || argc > 1)
76: usage();
77:
78: if (argc == 1)
79: format = *argv;
80:
81: bufsize = strlen(format);
82: if (bufsize > SIZE_MAX / 10)
83: errx(1, "format string too big");
84:
85: bufsize *= 10;
86: if ((buf = calloc(1, bufsize)) == NULL)
87: err(1, NULL);
88: if ((outbuf = calloc(1, bufsize)) == NULL)
89: err(1, NULL);
90:
1.3 claudio 91: /* force UTC for interval calculations */
92: if (iflag || sflag)
93: if (setenv("TZ", "UTC", 1) == -1)
94: err(1, "setenv UTC");
95:
96: clock_gettime(CLOCK_REALTIME, &roff);
97: clock_gettime(clock, &start);
98: timespecsub(&roff, &start, &roff);
1.1 job 99:
100: for (prev = '\n'; (ch = getchar()) != EOF; prev = ch) {
101: if (prev == '\n') {
1.3 claudio 102: clock_gettime(clock, &now);
103: if (iflag || sflag)
104: timespecsub(&now, &start, &now);
105: else if (mflag)
106: timespecadd(&now, &roff, &now);
107: if (iflag)
108: clock_gettime(clock, &start);
109: if ((tm = localtime(&now.tv_sec)) == NULL)
1.4 job 110: err(1, "localtime");
1.3 claudio 111: fmtfmt(tm, now.tv_nsec);
1.1 job 112: }
113: if (putchar(ch) == EOF)
114: break;
115: }
116:
117: if (fclose(stdout))
118: err(1, "stdout");
119: return 0;
120: }
121:
122: static void __dead
123: usage(void)
124: {
1.2 job 125: fprintf(stderr, "usage: %s [-i | -s] [-m] [format]\n", getprogname());
1.1 job 126: exit(1);
127: }
128:
129: /*
130: * yo dawg, i heard you like format strings
131: * so i put format strings in your user supplied input
132: * so you can format while you format
133: */
134: static void
135: fmtfmt(struct tm *tm, long tv_nsec)
136: {
137: char *f, ms[7];
138:
139: snprintf(ms, sizeof(ms), "%06ld", tv_nsec / 1000);
140: strlcpy(buf, format, bufsize);
141: f = buf;
142:
143: do {
144: while ((f = strchr(f, '%')) != NULL && f[1] == '%')
145: f += 2;
146:
147: if (f == NULL)
148: break;
149:
150: f++;
151: if (f[0] == '.' &&
152: (f[1] == 'S' || f[1] == 's' || f[1] == 'T')) {
153: size_t l;
154:
155: f[0] = f[1];
156: f[1] = '.';
157: f += 2;
158: l = strlen(f);
159: memmove(f + 6, f, l + 1);
160: memcpy(f, ms, 6);
161: f += 6;
162: }
163: } while (*f != '\0');
164:
165: if (strftime(outbuf, bufsize, buf, tm) == 0)
166: errx(1, "strftime");
167:
168: fprintf(stdout, "%s ", outbuf);
169: if (ferror(stdout))
170: exit(1);
171: }