New utility: `beep', which attempts to make a beeping noise by any
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Wed, 15 Feb 2006 18:37:35 +0000 (18:37 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Wed, 15 Feb 2006 18:37:35 +0000 (18:37 +0000)
means available.

git-svn-id: svn://svn.tartarus.org/sgt/utils@6561 cda61777-01e9-0310-a592-d414129be87e

Makefile
beep/Makefile [new file with mode: 0644]
beep/beep.but [new file with mode: 0644]
beep/beep.c [new file with mode: 0644]

index 95c3e45..8f58cde 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = base64 cvt-utf8 lns multi nntpid reservoir xcopy
+SUBDIRS = base64 beep cvt-utf8 lns multi nntpid reservoir xcopy
 
 # for `make html' and `make release'; should be a relative path
 DESTDIR = .
diff --git a/beep/Makefile b/beep/Makefile
new file mode 100644 (file)
index 0000000..8dbc570
--- /dev/null
@@ -0,0 +1,47 @@
+# for `make release' and `make html'
+DESTDIR = .
+
+# for `make install'
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+SCRIPTDIR = $(PREFIX)/bin
+MANDIR = $(PREFIX)/man/man1
+INSTALL = install
+IPROG =#   flags for installing programs (default none)
+IDATA = -m 0644  # flags for installing data
+
+X11LIB=-L/usr/X11R6/lib -lX11
+
+all: beep.1 beep
+man: beep.1
+progs: beep
+
+beep: beep.c
+       $(CC) $(CFLAGS) -o $@ $< $(X11LIB)
+
+%.1: %.but
+       halibut --man=$@ $<
+
+clean:
+       rm -f *.1 beep *.html *.tar.gz
+
+html:
+       halibut --html=$(DESTDIR)/beep.html beep.but
+
+release: beep.1
+       mkdir -p reltmp/beep
+       ln -s ../../beep.c reltmp/beep
+       ln -s ../../beep.1 reltmp/beep
+       ln -s ../../beep.but reltmp/beep
+       ln -s ../../Makefile reltmp/beep
+       tar -C reltmp -chzf $(DESTDIR)/beep.tar.gz beep
+       rm -rf reltmp
+
+install: install-progs install-man
+
+install-progs: beep
+       mkdir -p $(BINDIR)
+       $(INSTALL) $(IPROG) beep $(BINDIR)/beep
+install-man: beep.1
+       mkdir -p $(MANDIR)
+       $(INSTALL) $(IDATA) beep.1 $(MANDIR)/beep.1
diff --git a/beep/beep.but b/beep/beep.but
new file mode 100644 (file)
index 0000000..b059de8
--- /dev/null
@@ -0,0 +1,86 @@
+\cfg{man-identity}{beep}{1}{2006-02-15}{Simon Tatham}{Simon Tatham}
+
+\title Man page for \c{beep}
+
+\U NAME
+
+\c{beep} - produce a beeping noise, by any available method
+
+\U SYNOPSIS
+
+\c beep [ -v ] [ -X | -T | -S ]
+\e bbbb   bb     bb   bb   bb
+
+\U DESCRIPTION
+
+\c{beep} is a command-line utility for making a computer go beep.
+
+Under normal circumstances, you should be able to use it just by
+typing \cq{beep}, with no options.
+
+The traditional method of producing a beep in a shell script is to
+write an ASCII BEL (\cw{\\007}) character to standard output, by
+means of a shell command such as \cq{echo -ne '\\007'}. This only
+works if the calling shell's standard output is currently directed
+to a terminal device of some sort; if not, the beep will produce no
+sound and might even cause unwanted corruption in whatever file the
+output is directed to.
+
+There are other ways to cause a beeping noise. A slightly more
+reliable method is to open \cw{/dev/tty} and send your BEL character
+there. This is robust against I/O redirection, but still fails in
+the case where the shell script wishing to generate a beep does not
+\e{have} a controlling terminal, for example because it is run from
+an X window manager.
+
+A third approach is to connect to your X display and send it a bell
+command. This does not depend on a Unix terminal device, but does
+(of course) require an X display.
+
+The \c{beep} command supports all these methods of generating a
+beep, and will try them in order until one works. Its order of
+preference is to use the X server, then to fall back to
+\cw{/dev/tty}, and if all else fails it will simply write a BEL to
+its standard output.
+
+\U OPTIONS
+
+\dt \cw{-X}
+
+\dd Restricts \c{beep} to only using the X server to generate its
+beep. If there is no X server available, no beep will be generated
+and \c{beep} will return failure.
+
+\dt \cw{-T}
+
+\dd Restricts \c{beep} to only using \cw{/dev/tty} to generate its
+beep. If \cw{/dev/tty} cannot be opened or written to, no beep will
+be generated and \c{beep} will return failure.
+
+\dt \cw{-S}
+
+\dd Restricts \c{beep} to only using standard output to generate its
+beep. If its standard output cannot be written to, no beep will be
+generated and \c{beep} will return failure.
+
+\dt \cw{-v}
+
+\dd Causes \c{beep} to log everything it did even if it succeeds. By
+default, error messages will only be output if none of the available
+beep methods succeeded.
+
+\U EXIT STATUS
+
+\c{beep} will return a success (0) status if it thinks it
+successfully beeped, and failure (1) otherwise.
+
+\U BUGS
+
+None known at present.
+
+\U LICENCE
+
+\cw{xcopy} is free software, distributed under the MIT licence. Type
+\cw{xcopy --licence} to see the full licence text.
+
+\versionid $Id$
diff --git a/beep/beep.c b/beep/beep.c
new file mode 100644 (file)
index 0000000..ab23728
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * beep: quickly pipe text data into, or out of, the primary X
+ * selection
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#ifndef NO_X11
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+
+const char usagemsg[] =
+    "usage: beep [ -v ] ["
+#ifndef NO_X11
+    " -X |"
+#endif
+    " -T | -S ]\n"
+    "where: "
+#ifndef NO_X11
+    "-X     beep using the X display or not at all\n       "
+#endif
+    "-T     beep using /dev/tty or not at all\n"
+    "       -S     beep using standard output or not at all\n"
+    "       -v     log failed and successful beep attempts\n"
+    " also: beep --version              report version number\n"
+    "       beep --help                 display this help text\n"
+    "       beep --licence              display the (MIT) licence text\n"
+    ;
+
+void usage(void) {
+    fputs(usagemsg, stdout);
+}
+
+const char licencemsg[] =
+    "beep is copyright 2006 Simon Tatham.\n"
+    "\n"
+    "Permission is hereby granted, free of charge, to any person\n"
+    "obtaining a copy of this software and associated documentation files\n"
+    "(the \"Software\"), to deal in the Software without restriction,\n"
+    "including without limitation the rights to use, copy, modify, merge,\n"
+    "publish, distribute, sublicense, and/or sell copies of the Software,\n"
+    "and to permit persons to whom the Software is furnished to do so,\n"
+    "subject to the following conditions:\n"
+    "\n"
+    "The above copyright notice and this permission notice shall be\n"
+    "included in all copies or substantial portions of the Software.\n"
+    "\n"
+    "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
+    "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
+    "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
+    "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
+    "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
+    "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
+    "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
+    "SOFTWARE.\n"
+    ;
+
+void licence(void) {
+    fputs(licencemsg, stdout);
+}
+
+void version(void) {
+#define SVN_REV "$Revision$"
+    char rev[sizeof(SVN_REV)];
+    char *p, *q;
+
+    strcpy(rev, SVN_REV);
+
+    for (p = rev; *p && *p != ':'; p++);
+    if (*p) {
+        p++;
+        while (*p && isspace((unsigned char)*p)) p++;
+        for (q = p; *q && !isspace((unsigned char)*q) && *q != '$'; q++);
+        if (*q) *q = '\0';
+        printf("beep revision %s", p);
+    } else {
+        printf("beep: unknown version");
+    }
+#ifdef NO_X11
+    printf(", compiled without X11");
+#endif
+    putchar('\n');
+}
+
+int main(int argc, char **argv) {
+#ifndef NO_X11
+    char *display = NULL;
+#endif
+    int verbose = 0;
+    enum { X11 = 1, TTY = 2, STDOUT = 4 } mode = X11 | TTY | STDOUT;
+    char errbuf[4096];
+    int errlen = 0;
+    int done = 0;
+    char *pname = argv[0];
+
+    /* parse the command line arguments */
+    while (--argc) {
+       char *p = *++argv;
+
+#ifndef NO_X11
+       if (!strcmp(p, "-display") || !strcmp(p, "-disp")) {
+           if (!argv[1]) {
+               fprintf(stderr, "%s: option `%s' expects a parameter\n",
+                       pname, p);
+               return 1;
+           }
+           display = *++argv, --argc;
+        } else if (!strcmp(p, "-X")) {
+            mode = X11;
+        } else
+#endif
+       if (!strcmp(p, "-T")) {
+            mode = TTY;
+        } else if (!strcmp(p, "-S")) {
+            mode = STDOUT;
+        } else if (!strcmp(p, "-v")) {
+            verbose = 1;
+        } else if (!strcmp(p, "--help")) {
+           usage();
+           return 0;
+        } else if (!strcmp(p, "--version")) {
+            version();
+           return 0;
+        } else if (!strcmp(p, "--licence") || !strcmp(p, "--license")) {
+            licence();
+           return 0;
+       } else if (*p=='-') {
+           fprintf(stderr, "%s: unrecognised option `%s'\n", pname, p);
+           return 1;
+       } else {
+           fprintf(stderr, "%s: parameter `%s' unexpected\n", pname, p);
+           return 1;
+       }
+    }
+
+#ifndef NO_X11
+    if (!done && (mode & X11)) {
+       Display *disp = XOpenDisplay(display);
+       if (!disp) {
+           errlen += sprintf(errbuf+errlen,
+                             "%s: unable to open X display\n", pname);
+       } else {
+           XBell(disp, 0);
+           XCloseDisplay(disp);
+           if (verbose) {
+               errlen += sprintf(errbuf+errlen,
+                                 "%s: successfully beeped via X11\n", pname);
+           }
+           done = 1;
+       }
+    }
+#endif
+
+    if (!done && (mode & TTY)) {
+       int fd = open("/dev/tty", O_WRONLY);
+       if (fd < 0) {
+           errlen += sprintf(errbuf+errlen,
+                             "%s: unable to open /dev/tty: %s\n",
+                             pname, strerror(errno));
+       } else {
+           if (write(fd, "\007", 1) < 0) {
+               errlen += sprintf(errbuf+errlen, "%s: unable to write to"
+                                 " /dev/tty: %s\n", pname, strerror(errno));
+           } else {
+               if (verbose) {
+                   errlen += sprintf(errbuf+errlen, "%s: successfully beeped"
+                                     " via /dev/tty\n", pname);
+               }
+               done = 1;
+           }
+           close(fd);
+       }
+    }
+
+    if (!done && (mode & STDOUT)) {
+       if (write(1, "\007", 1) < 0) {
+           errlen += sprintf(errbuf+errlen, "%s: unable to write to standard "
+                             "output: %s\n", pname, strerror(errno));
+       } else {
+           if (verbose) {
+               errlen += sprintf(errbuf+errlen, "%s: successfully beeped"
+                                 " via standard output\n", pname);
+           }
+           done = 1;
+       }
+    }
+
+    if (verbose || !done) {
+       errbuf[errlen] = '\0';
+       fputs(errbuf, stderr);
+    }
+
+    return (done ? EXIT_SUCCESS : EXIT_FAILURE);
+}