Annotation of src/usr.bin/ts/ts.c, Revision 1.1
1.1 ! job 1: /* $OpenBSD$ */
! 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:
! 19: #include <sys/cdefs.h>
! 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: {
! 41: int iflag, sflag;
! 42: int ch, prev;
! 43: struct timespec start, now, elapsed;
! 44: struct tm *lt, tm;
! 45:
! 46: if (pledge("stdio", NULL) == -1)
! 47: err(1, "pledge");
! 48:
! 49: iflag = sflag = 0;
! 50:
! 51: while ((ch = getopt(argc, argv, "is")) != -1) {
! 52: switch (ch) {
! 53: case 'i':
! 54: iflag = 1;
! 55: format = "%H:%M:%S";
! 56: break;
! 57: case 's':
! 58: sflag = 1;
! 59: format = "%H:%M:%S";
! 60: break;
! 61: default:
! 62: usage();
! 63: }
! 64: }
! 65: argc -= optind;
! 66: argv += optind;
! 67:
! 68: if ((iflag && sflag) || argc > 1)
! 69: usage();
! 70:
! 71: if (argc == 1)
! 72: format = *argv;
! 73:
! 74: bufsize = strlen(format);
! 75: if (bufsize > SIZE_MAX / 10)
! 76: errx(1, "format string too big");
! 77:
! 78: bufsize *= 10;
! 79: if ((buf = calloc(1, bufsize)) == NULL)
! 80: err(1, NULL);
! 81: if ((outbuf = calloc(1, bufsize)) == NULL)
! 82: err(1, NULL);
! 83:
! 84: clock_gettime(CLOCK_MONOTONIC, &start);
! 85:
! 86: for (prev = '\n'; (ch = getchar()) != EOF; prev = ch) {
! 87: if (prev == '\n') {
! 88: if (iflag || sflag) {
! 89: if (clock_gettime(CLOCK_MONOTONIC, &now))
! 90: err(1, "clock_gettime");
! 91: timespecsub(&now, &start, &elapsed);
! 92: if (gmtime_r(&elapsed.tv_sec, &tm) == NULL)
! 93: err(1, "gmtime_r");
! 94: if (iflag)
! 95: clock_gettime(CLOCK_MONOTONIC, &start);
! 96: fmtfmt(&tm, elapsed.tv_nsec);
! 97: } else {
! 98: if (clock_gettime(CLOCK_REALTIME, &now))
! 99: err(1, "clock_gettime");
! 100: lt = localtime(&now.tv_sec);
! 101: if (lt == NULL)
! 102: err(1, "localtime");
! 103: fmtfmt(lt, now.tv_nsec);
! 104: }
! 105: }
! 106: if (putchar(ch) == EOF)
! 107: break;
! 108: }
! 109:
! 110: if (fclose(stdout))
! 111: err(1, "stdout");
! 112: return 0;
! 113: }
! 114:
! 115: static void __dead
! 116: usage(void)
! 117: {
! 118: fprintf(stderr, "usage: %s [-i | -s] [format]\n", getprogname());
! 119: exit(1);
! 120: }
! 121:
! 122: /*
! 123: * yo dawg, i heard you like format strings
! 124: * so i put format strings in your user supplied input
! 125: * so you can format while you format
! 126: */
! 127: static void
! 128: fmtfmt(struct tm *tm, long tv_nsec)
! 129: {
! 130: char *f, ms[7];
! 131:
! 132: snprintf(ms, sizeof(ms), "%06ld", tv_nsec / 1000);
! 133: strlcpy(buf, format, bufsize);
! 134: f = buf;
! 135:
! 136: do {
! 137: while ((f = strchr(f, '%')) != NULL && f[1] == '%')
! 138: f += 2;
! 139:
! 140: if (f == NULL)
! 141: break;
! 142:
! 143: f++;
! 144: if (f[0] == '.' &&
! 145: (f[1] == 'S' || f[1] == 's' || f[1] == 'T')) {
! 146: size_t l;
! 147:
! 148: f[0] = f[1];
! 149: f[1] = '.';
! 150: f += 2;
! 151: l = strlen(f);
! 152: memmove(f + 6, f, l + 1);
! 153: memcpy(f, ms, 6);
! 154: f += 6;
! 155: }
! 156: } while (*f != '\0');
! 157:
! 158: if (strftime(outbuf, bufsize, buf, tm) == 0)
! 159: errx(1, "strftime");
! 160:
! 161: fprintf(stdout, "%s ", outbuf);
! 162: if (ferror(stdout))
! 163: exit(1);
! 164: }