[BACK]Return to ts.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ts

File: [local] / src / usr.bin / ts / ts.c (download)

Revision 1.3, Thu Jun 30 07:42:50 2022 UTC (23 months, 1 week ago) by claudio
Branch: MAIN
Changes since 1.2: +21 -28 lines

Fix interval timers by forcing TZ to UTC, else some strftime formats
print strange offsets.

While there rework the main loop to only use localtime and now.
Calculate the relative time offset for -m mode just once at startup.
OK sthen@ job@

/*	$OpenBSD: ts.c,v 1.3 2022/06/30 07:42:50 claudio Exp $	*/
/*
 * Copyright (c) 2022 Job Snijders <job@openbsd.org>
 * Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/cdefs.h>
#include <sys/time.h>

#include <err.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>

static char		*format = "%b %d %H:%M:%S";
static char		*buf;
static char		*outbuf;
static size_t		 bufsize;

static void		 fmtfmt(struct tm *, long);
static void __dead	 usage(void);

int
main(int argc, char *argv[])
{
	int iflag, mflag, sflag;
	int ch, prev;
	struct timespec roff, start, now;
	struct tm *tm;
	int clock = CLOCK_REALTIME;

	if (pledge("stdio", NULL) == -1)
		err(1, "pledge");

	iflag = mflag = sflag = 0;

	while ((ch = getopt(argc, argv, "ims")) != -1) {
		switch (ch) {
		case 'i':
			iflag = 1;
			format = "%H:%M:%S";
			clock = CLOCK_MONOTONIC;
			break;
		case 'm':
			mflag = 1;
			clock = CLOCK_MONOTONIC;
			break;
		case 's':
			sflag = 1;
			format = "%H:%M:%S";
			clock = CLOCK_MONOTONIC;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if ((iflag && sflag) || argc > 1)
		usage();

	if (argc == 1)
		format = *argv;

	bufsize = strlen(format);
	if (bufsize > SIZE_MAX / 10)
		errx(1, "format string too big");

	bufsize *= 10;
	if ((buf = calloc(1, bufsize)) == NULL)
		err(1, NULL);
	if ((outbuf = calloc(1, bufsize)) == NULL)
		err(1, NULL);

	/* force UTC for interval calculations */
	if (iflag || sflag)
		if (setenv("TZ", "UTC", 1) == -1)
			err(1, "setenv UTC");

	clock_gettime(CLOCK_REALTIME, &roff);
	clock_gettime(clock, &start);
	timespecsub(&roff, &start, &roff);

	for (prev = '\n'; (ch = getchar()) != EOF; prev = ch) {
		if (prev == '\n') {
			clock_gettime(clock, &now);
			if (iflag || sflag)
				timespecsub(&now, &start, &now);
			else if (mflag)
				timespecadd(&now, &roff, &now);
			if (iflag)
				clock_gettime(clock, &start);
			if ((tm = localtime(&now.tv_sec)) == NULL)
				err(1, "localtime/gmtime");
			fmtfmt(tm, now.tv_nsec);
		}
		if (putchar(ch) == EOF)
			break;
	}

	if (fclose(stdout))
		err(1, "stdout");
	return 0;
}

static void __dead
usage(void)
{
	fprintf(stderr, "usage: %s [-i | -s] [-m] [format]\n", getprogname());
	exit(1);
}

/*
 * yo dawg, i heard you like format strings
 * so i put format strings in your user supplied input
 * so you can format while you format
 */
static void
fmtfmt(struct tm *tm, long tv_nsec)
{
	char *f, ms[7];

	snprintf(ms, sizeof(ms), "%06ld", tv_nsec / 1000);
	strlcpy(buf, format, bufsize);
	f = buf;

	do {
		while ((f = strchr(f, '%')) != NULL && f[1] == '%')
			f += 2;

		if (f == NULL)
			break;

		f++;
		if (f[0] == '.' &&
		    (f[1] == 'S' || f[1] == 's' || f[1] == 'T')) {
			size_t l;

			f[0] = f[1];
			f[1] = '.';
			f += 2;
			l = strlen(f);
			memmove(f + 6, f, l + 1);
			memcpy(f, ms, 6);
			f += 6;
		}
	} while (*f != '\0');

	if (strftime(outbuf, bufsize, buf, tm) == 0)
		errx(1, "strftime");

	fprintf(stdout, "%s ", outbuf);
	if (ferror(stdout))
		exit(1);
}