+/* -*-
+ *
+ * Like cat, with datestamps
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <unistd.h>
+
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+static const char *fmt = "%Y-%m-%d %H:%M:%S %Z: ";
+static struct tm *(*cvt)(const time_t *) = localtime;
+
+static void version(void) { pquis(stdout, "$ " VERSION); }
+static void usage(FILE *fp)
+ { pquis(fp, "Usage: $ [-z] [-f FORMAT] [FILE...]"); }
+
+static void help(void)
+{
+ version(); putchar('\n');
+ usage(stdout);
+ fputs("\n\
+Copy the FILEs (or standard input) to standard output, prefixing each line\n\
+with a datestamp.\n\
+\n\
+-h, --help Show this help text.\n\
+-v, --version Show the program's version number.\n\
+-u, --usage Show a brief usage message.\n\
+\n\
+-f, --format=FORMAT Write datestamps using the strftime(3) FORMAT.\n\
+-z, --utc, --zulu Use UTC rather than local time for datestamps.\n\
+", stdout);
+}
+
+static void cat(FILE *in)
+{
+ unsigned ln = 1;
+ time_t t;
+ struct tm *tm;
+ char buf[256];
+ int ch;
+
+ for (;;) {
+ if ((ch = getc(in)) == EOF)
+ break;
+ if (ln) {
+ t = time(0);
+ tm = cvt(&t);
+ strftime(buf, sizeof(buf), fmt, tm);
+ fwrite(buf, 1, strlen(buf), stdout);
+ }
+ putchar(ch);
+ ln = (ch == '\n');
+ }
+ if (!ln)
+ putchar('\n');
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ FILE *fp;
+ unsigned f = 0;
+#define F_BOGUS 1u
+
+ ego(argv[0]);
+ setvbuf(stdin, 0, _IOLBF, 0);
+
+ for (;;) {
+ static const struct option opt[] = {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'v' },
+ { "usage", 0, 0, 'u' },
+ { "format", OPTF_ARGREQ, 0, 'f' },
+ { "utc", 0, 0, 'z' },
+ { "zulu", 0, 0, 'z' },
+ { 0, 0, 0, 0 }
+ };
+
+ if ((i = mdwopt(argc, argv, "hvuf:z", opt, 0, 0, 0)) < 0)
+ break;
+ switch (i) {
+ case 'h':
+ help();
+ exit(0);
+ case 'v':
+ version();
+ exit(0);
+ case 'u':
+ usage(stdout);
+ exit(0);
+ case 'f':
+ fmt = optarg;
+ break;
+ case 'z':
+ cvt = gmtime;
+ break;
+ default:
+ f |= F_BOGUS;
+ break;
+ }
+ }
+
+ if (f & F_BOGUS) {
+ usage(stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (optind == argc) {
+ if (isatty(STDIN_FILENO))
+ die(EXIT_FAILURE, "no arguments, and stdin is a terminal");
+ cat(stdin);
+ } else for (i = optind; i < argc; i++) {
+ if (strcmp(argv[i], "-") == 0)
+ cat(stdin);
+ else if ((fp = fopen(argv[i], "r")) == 0) {
+ moan("failed to open `%s': %s", argv[i], strerror(errno));
+ f |= F_BOGUS;
+ } else {
+ cat(fp);
+ fclose(fp);
+ }
+ }
+
+ if (ferror(stdout) || fflush(stdout) || fclose(stdout)) {
+ moan("error writing output: %s", strerror(errno));
+ f |= F_BOGUS;
+ }
+
+ return ((f & F_BOGUS) ? EXIT_FAILURE : 0);
+}