chiark / gitweb /
Add `pause' program. 1.1.1
authormdw <mdw>
Sat, 11 Sep 2004 17:20:44 +0000 (17:20 +0000)
committermdw <mdw>
Sat, 11 Sep 2004 17:20:44 +0000 (17:20 +0000)
Makefile
debian/changelog
debian/control
debian/inst
gorp.1
pause.1 [new file with mode: 0644]
pause.c [new file with mode: 0644]

index bfa978e561ce39252939f14154d8089b67047fa6..514bab26a9650c5186b3ccb457203c421f695586 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,26 +3,26 @@
 ## No proper build system here.  Just kludgy hacks.
 
 PACKAGE = nsict-utils
-VERSION = 1.1.0
+VERSION = 1.1.1
 
 BINSCRIPTS = cdb-assign cdb-list check-sender unfwd splitconf z
 SBINSCRIPTS = shadowfix
 SCRIPTS = $(BINSCRIPTS) $(SBINSCRIPTS)
-BINPROGS = not cdb-probe cdb-check-domain gorp locking if-mtu
+BINPROGS = not cdb-probe cdb-check-domain gorp locking if-mtu pause
 SBINPROGS = qmail-checkspam
 PROGS = $(BINPROGS) $(SBINPROGS)
 PERLLIBS = MdwOpt.pm
 LIBS = xtitle.so
 DISTMAN1 = \
        not.1 z.1 cdb-assign.1 cdb-list.1 cdb-probe.1 cdb-check-domain.1 \
-       gorp.1 unfwd.1 splitconf.1 locking.1 if-mtu.1
+       gorp.1 unfwd.1 splitconf.1 locking.1 if-mtu.1 pause.1
 MAN1 = $(DISTMAN1)
 DISTMAN8 = qmail-checkspam.8
 MAN8 = $(DISTMAN8) shadowfix.8
 BUILDFILES = shadowfix.8
 SOURCES = \
        not.c cdb-probe.c cdb-check-domain.c gorp.c locking.c if-mtu.c \
-       qmail-checkspam.c xtitle.c
+       qmail-checkspam.c xtitle.c pause.c
 
 CC = gcc
 LD = gcc
@@ -85,6 +85,9 @@ xtitle.so: xtitle.o
 gorp: gorp.o
        $(LINK) -lcatacomb -lmLib
 
+pause: pause.o
+       $(LINK) -lmLib
+
 locking: locking.o
        $(LINK) -lmLib
 
index 6b41c19a013f53d9a470f72b1977753cd83b9e49..8e19ae52c1c7c3e7df7687a7c0b2fdb9fd697877 100644 (file)
@@ -1,3 +1,9 @@
+nsict-utils (1.1.1) experimental; urgency=low
+
+  * Add pause program.
+
+ -- Mark Wooding <mdw@nsict.org>  Sat, 11 Sep 2004 18:13:25 +0100
+
 nsict-utils (1.1.0) experimental; urgency=low
 
   * Make gorp a much more useful program.
index c1d2749dbbd14ea255de9d3ca2bc338339e11abc..f928af9b28a30be977ec2e9aebfbb5f4e29210de 100644 (file)
@@ -79,3 +79,10 @@ Architecture: any
 Depends: ${shlibs:Depends}
 Section: utils
 Description: Print a random base64 string.
+
+Package: pause
+Architecture: any
+Depends: ${shlibs:Depends}
+Section: utils
+Description: Wait for a given time, or until a key is pressed.
+
index 9052cc6fd235d0087f28c5b59326abce569f0d3a..9793edecfa602d6613da8d428df18ee44187fdeb 100644 (file)
@@ -17,6 +17,8 @@ locking locking /usr/bin
 locking.1 locking /usr/share/man/man1
 not nsict-mail /usr/bin
 not.1 nsict-mail /usr/share/man/man1
+pause pause /usr/bin
+pause.1 pause /usr/share/man/man1
 qmail-checkspam qmail-checkspam /usr/sbin
 qmail-checkspam.8 qmail-checkspam /usr/share/man/man8
 shadowfix shadowfix /usr/sbin
@@ -25,6 +27,6 @@ splitconf splitconf /usr/bin
 splitconf.1 splitconf /usr/share/man/man1
 unfwd nsict-mail /usr/bin
 unfwd.1 nsict-mail /usr/share/man/man1
-xtitle.so xtitle /usr/lib/bash/
+xtitle.so xtitle /usr/lib/bash
 z zz /usr/bin
 z.1 zz /usr/share/man/man1
diff --git a/gorp.1 b/gorp.1
index 6f9000d922a01213ac30b495181fa714c2a701c2..66de0a1cc6826493f7af652c814ad50900a38a5d 100644 (file)
--- a/gorp.1
+++ b/gorp.1
@@ -46,7 +46,7 @@ so the output is suitable for use as a filename),
 .B raw
 (raw binary output, not printable).
 .TP
-.B "\-l, \-\-line=" length
+.BI "\-l, \-\-line=" length
 Breaks textual output into lines of at most
 .I length
 characters, and does all encoding in a strictly conforming way.  By
diff --git a/pause.1 b/pause.1
new file mode 100644 (file)
index 0000000..6aeef11
--- /dev/null
+++ b/pause.1
@@ -0,0 +1,52 @@
+.\" -*-nroff-*-
+.de hP
+.IP
+.ft B
+\h'-\w'\\$1\ 'u'\\$1\ \c
+.ft P
+..
+.ie t .ds o \(bu
+.el .ds o o
+.TH pause 1 "27 October 1999"
+.SH "NAME"
+pause \- wait for a period of time, or for a keypress
+.SH "SYNOPSIS"
+.B pause
+.RI [ time ]
+.SH "DESCRIPTION"
+The
+.B pause
+program will wait until one of the following conditions is true:
+.hP \*o
+Standard input is a terminal, and a key has been pressed on the terminal
+since the program started.
+.hP \*o
+A time limit was specified on the command line, and sufficient time has
+elapsed since the program started.
+.hP \*o
+The program received a fatal signal.
+.PP
+The time limit is given as a positive real number, followed by a suffix
+of
+.RB ` d ',
+.RB ` h ',
+.RB ` m '
+or
+.RB ` s '
+denoting days, hours, minutes or seconds (which are the default).
+.PP
+The standard GNU help options are understood:
+.B \-\-help
+(which may be abbreviated as
+.BR \-h )
+prints a description of the program to standard output and exits;
+.B \-\-version
+.RB ( \-v )
+prints the version number and exits; and
+.B \-\-usage
+.RB ( \-u )
+prints a brief usage summary and exits.
+.SH "SEE ALSO"
+.BR sleep (1).
+.SH "AUTHOR"
+Mark Wooding, <mdw@nsict.org>
diff --git a/pause.c b/pause.c
new file mode 100644 (file)
index 0000000..fd688e5
--- /dev/null
+++ b/pause.c
@@ -0,0 +1,304 @@
+/* -*-c-*-
+ *
+ * $Id$
+ *
+ * Pause for a while
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of Pause.
+ *
+ * Pause is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later ersion.
+ * 
+ * Pause is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Pause; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <termios.h>
+
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+#include <mLib/tv.h>
+
+/*----- Static variables --------------------------------------------------*/
+
+static struct termios ts_old, ts;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @sig@ --- *
+ *
+ * Arguments:  @int s@ = signal number
+ *
+ * Returns:    Doesn't.
+ *
+ * Use:                Handles various fatal signals by resetting the terminal state
+ *             and re-emitting the signal.
+ */
+
+static void sig(int s)
+{
+  tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts_old);
+  signal(s, SIG_DFL);
+  raise(s);
+}
+
+/* --- @suspend@ --- *
+ *
+ * Arguments:  @int s@ = signal number
+ *
+ * Returns:    ---
+ *
+ * Use:                Handles a job control signal, as recommended in APUE.  It
+ *             resets the terminal state, resets the signal disposition,
+ *             unblocks the signal and re-emits it (so that the shell
+ *             shows the right message).  When that call returns, the
+ *             signal handler is reattached, and the terminal state is set
+ *             again.
+ */
+
+static void suspend(int s)
+{
+  sigset_t ss;
+
+  tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts_old);
+  signal(s, SIG_DFL);
+  sigemptyset(&ss);
+  sigaddset(&ss, s);
+  sigprocmask(SIG_UNBLOCK, &ss, 0);
+  raise(s);
+  signal(s, suspend);
+  tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts);
+}
+
+/* --- Traditional GNUey help options --- */
+
+static void usage(FILE *fp)
+{
+  pquis(fp, "Usage: $ [time]\n");
+}
+
+static void version(FILE *fp)
+{
+  pquis(fp, "$ version " VERSION "\n");
+}
+
+static void help(FILE *fp)
+{
+  version(fp);
+  fputc('\n', fp);
+  usage(fp);
+  pquis(fp, "\n\
+Pauses until a key is pressed or an optional time-limit expires.  The\n\
+time is given as a floating point number with an option suffix of `s',\n\
+`m', `h' or `d' (for `seconds', `minutes', `hours' or `days'\n\
+respectively).\n\
+\n\
+Options available:\n\
+\n\
+-h, --help     Show this help message.\n\
+-v, --version  Show program's version number.\n\
+-u, --usage    Show terse usage summary.\n\
+");
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments:  @int argc@ = number of command line arguments
+ *             @char *argv[]@ = vector of command line arguments
+ *
+ * Returns:    Nonzero if it failed, zero if everything went well.
+ *
+ * Use:                Souped-up version of `sleep'.
+ */
+
+int main(int argc, char *argv[])
+{
+  struct termios ts;
+  unsigned f = 0;
+  struct timeval when;
+
+  enum {
+    f_bogus = 1u,
+    f_timer = 2u,
+    f_key = 4u
+  };
+
+  /* --- Library initialization --- */
+
+  ego(argv[0]);
+
+  /* --- Parse command line options --- */
+
+  for (;;) {
+    static struct option opt[] = {
+      { "help",                0,              0,      'h' },
+      { "version",     0,              0,      'v' },
+      { "usage",       0,              0,      'u' },
+      { 0,             0,              0,      0 }
+    };
+    int i = mdwopt(argc, argv, "hvu", opt, 0, 0, 0);
+    if (i < 0)
+      break;
+    switch (i) {
+      case 'h':
+       help(stderr);
+       exit(0);
+      case 'v':
+       version(stderr);
+       exit(0);
+      case 'u':
+       usage(stderr);
+       exit(0);
+      default:
+       f |= f_bogus;
+       break;
+    }
+  }
+
+  /* --- Parse a timer spec --- */
+
+  if (!(f & f_bogus) && optind < argc) {
+    const char *p =argv[optind++];
+    char *q;
+    double t = strtod(p, &q);
+    switch (*q) {
+      case 'd': t *= 24;
+      case 'h': t *= 60;
+      case 'm': t *= 60;
+      case 's':        if (q[1] != 0)
+      default:    t = 0;
+      case 0:  break;
+    }
+    if (t <= 0)
+      die(1, "bad time specification `%s'", p);
+    gettimeofday(&when, 0);
+    TV_ADDL(&when, &when, t, (t - floor(t)) * MILLION);
+    f |= f_timer;
+  }
+
+  /* --- Report a syntax error --- */
+
+  if (optind < argc)
+    f |= f_bogus;
+  if (f & f_bogus) {
+    usage(stderr);
+    exit(1);
+  }
+
+  /* --- Set up terminal for single keypresses --- */
+
+  if (tcgetattr(STDIN_FILENO, &ts_old) == 0) {
+    static struct { int sig; void (*func)(int); } sigs[] = {
+      { SIGINT, sig },
+      { SIGQUIT, sig },
+      { SIGTERM, sig },
+      { SIGTSTP, suspend },
+      { 0, 0 }
+    };
+    int i;
+
+    /* --- Set up the new terminal attributes --- */
+
+    ts = ts_old;
+    ts.c_lflag &= ~(ECHO | ICANON | TOSTOP);
+
+    /* --- Set up signal handlers to reset attributes --- */
+
+    for (i = 0; sigs[i].sig; i++) {
+      struct sigaction sa;
+      sigaction(sigs[i].sig, 0, &sa);
+      if (sa.sa_handler != SIG_IGN)
+       signal(sigs[i].sig, sigs[i].func);
+    }
+    signal(SIGTTIN, suspend);
+
+    /* --- Commit the terminal attribute changes --- */
+
+    tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts);
+    f |= f_key;
+  }
+
+  /* --- Main loop --- */
+
+  for (;;) {
+    fd_set fd, *pfd;
+    int maxfd;
+    struct timeval tv, *ptv;
+
+    /* --- Wait for a keypress --- */
+
+    if (f & f_key) {
+      FD_ZERO(&fd);
+      FD_SET(STDIN_FILENO, &fd);
+      maxfd = STDIN_FILENO + 1;
+      pfd = &fd;
+    } else {
+      maxfd = 0;
+      pfd = 0;
+    }
+
+    /* --- Wait for the timer to expire --- */
+
+    if (f & f_timer) {
+      gettimeofday(&tv, 0);
+      TV_SUB(&tv, &when, &tv);
+      ptv = &tv;
+    } else
+      ptv = 0;
+
+    /* --- See what interesting things have happened --- */
+
+    if (select(maxfd, pfd, 0, 0, ptv) < 0) {
+      if (errno == EINTR || errno == EAGAIN)
+       continue;
+      die(1, "error in select: %s", strerror(errno));
+    }
+
+    /* --- Check the timer --- */
+
+    if (f & f_timer) {
+      gettimeofday(&tv, 0);
+      if (TV_CMP(&tv, >=, &when))
+       break;
+    }
+
+    /* --- Check the key state --- */
+
+    if (f & f_key && FD_ISSET(STDIN_FILENO, &fd))
+      break;
+  }
+
+  /* --- See what gives --- */
+
+  if (f & f_key)
+    tcsetattr(STDIN_FILENO, TCSAFLUSH, &ts_old);
+  return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/