New utility: `beep', which attempts to make a beeping noise by any
[sgt/utils] / beep / beep.c
CommitLineData
932fdefd 1/*
2 * beep: quickly pipe text data into, or out of, the primary X
3 * selection
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <errno.h>
10#include <ctype.h>
11
12#ifndef NO_X11
13#include <X11/X.h>
14#include <X11/Xlib.h>
15#endif
16
17#include <unistd.h>
18#include <fcntl.h>
19
20const char usagemsg[] =
21 "usage: beep [ -v ] ["
22#ifndef NO_X11
23 " -X |"
24#endif
25 " -T | -S ]\n"
26 "where: "
27#ifndef NO_X11
28 "-X beep using the X display or not at all\n "
29#endif
30 "-T beep using /dev/tty or not at all\n"
31 " -S beep using standard output or not at all\n"
32 " -v log failed and successful beep attempts\n"
33 " also: beep --version report version number\n"
34 " beep --help display this help text\n"
35 " beep --licence display the (MIT) licence text\n"
36 ;
37
38void usage(void) {
39 fputs(usagemsg, stdout);
40}
41
42const char licencemsg[] =
43 "beep is copyright 2006 Simon Tatham.\n"
44 "\n"
45 "Permission is hereby granted, free of charge, to any person\n"
46 "obtaining a copy of this software and associated documentation files\n"
47 "(the \"Software\"), to deal in the Software without restriction,\n"
48 "including without limitation the rights to use, copy, modify, merge,\n"
49 "publish, distribute, sublicense, and/or sell copies of the Software,\n"
50 "and to permit persons to whom the Software is furnished to do so,\n"
51 "subject to the following conditions:\n"
52 "\n"
53 "The above copyright notice and this permission notice shall be\n"
54 "included in all copies or substantial portions of the Software.\n"
55 "\n"
56 "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
57 "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
58 "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
59 "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
60 "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
61 "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
62 "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
63 "SOFTWARE.\n"
64 ;
65
66void licence(void) {
67 fputs(licencemsg, stdout);
68}
69
70void version(void) {
71#define SVN_REV "$Revision$"
72 char rev[sizeof(SVN_REV)];
73 char *p, *q;
74
75 strcpy(rev, SVN_REV);
76
77 for (p = rev; *p && *p != ':'; p++);
78 if (*p) {
79 p++;
80 while (*p && isspace((unsigned char)*p)) p++;
81 for (q = p; *q && !isspace((unsigned char)*q) && *q != '$'; q++);
82 if (*q) *q = '\0';
83 printf("beep revision %s", p);
84 } else {
85 printf("beep: unknown version");
86 }
87#ifdef NO_X11
88 printf(", compiled without X11");
89#endif
90 putchar('\n');
91}
92
93int main(int argc, char **argv) {
94#ifndef NO_X11
95 char *display = NULL;
96#endif
97 int verbose = 0;
98 enum { X11 = 1, TTY = 2, STDOUT = 4 } mode = X11 | TTY | STDOUT;
99 char errbuf[4096];
100 int errlen = 0;
101 int done = 0;
102 char *pname = argv[0];
103
104 /* parse the command line arguments */
105 while (--argc) {
106 char *p = *++argv;
107
108#ifndef NO_X11
109 if (!strcmp(p, "-display") || !strcmp(p, "-disp")) {
110 if (!argv[1]) {
111 fprintf(stderr, "%s: option `%s' expects a parameter\n",
112 pname, p);
113 return 1;
114 }
115 display = *++argv, --argc;
116 } else if (!strcmp(p, "-X")) {
117 mode = X11;
118 } else
119#endif
120 if (!strcmp(p, "-T")) {
121 mode = TTY;
122 } else if (!strcmp(p, "-S")) {
123 mode = STDOUT;
124 } else if (!strcmp(p, "-v")) {
125 verbose = 1;
126 } else if (!strcmp(p, "--help")) {
127 usage();
128 return 0;
129 } else if (!strcmp(p, "--version")) {
130 version();
131 return 0;
132 } else if (!strcmp(p, "--licence") || !strcmp(p, "--license")) {
133 licence();
134 return 0;
135 } else if (*p=='-') {
136 fprintf(stderr, "%s: unrecognised option `%s'\n", pname, p);
137 return 1;
138 } else {
139 fprintf(stderr, "%s: parameter `%s' unexpected\n", pname, p);
140 return 1;
141 }
142 }
143
144#ifndef NO_X11
145 if (!done && (mode & X11)) {
146 Display *disp = XOpenDisplay(display);
147 if (!disp) {
148 errlen += sprintf(errbuf+errlen,
149 "%s: unable to open X display\n", pname);
150 } else {
151 XBell(disp, 0);
152 XCloseDisplay(disp);
153 if (verbose) {
154 errlen += sprintf(errbuf+errlen,
155 "%s: successfully beeped via X11\n", pname);
156 }
157 done = 1;
158 }
159 }
160#endif
161
162 if (!done && (mode & TTY)) {
163 int fd = open("/dev/tty", O_WRONLY);
164 if (fd < 0) {
165 errlen += sprintf(errbuf+errlen,
166 "%s: unable to open /dev/tty: %s\n",
167 pname, strerror(errno));
168 } else {
169 if (write(fd, "\007", 1) < 0) {
170 errlen += sprintf(errbuf+errlen, "%s: unable to write to"
171 " /dev/tty: %s\n", pname, strerror(errno));
172 } else {
173 if (verbose) {
174 errlen += sprintf(errbuf+errlen, "%s: successfully beeped"
175 " via /dev/tty\n", pname);
176 }
177 done = 1;
178 }
179 close(fd);
180 }
181 }
182
183 if (!done && (mode & STDOUT)) {
184 if (write(1, "\007", 1) < 0) {
185 errlen += sprintf(errbuf+errlen, "%s: unable to write to standard "
186 "output: %s\n", pname, strerror(errno));
187 } else {
188 if (verbose) {
189 errlen += sprintf(errbuf+errlen, "%s: successfully beeped"
190 " via standard output\n", pname);
191 }
192 done = 1;
193 }
194 }
195
196 if (verbose || !done) {
197 errbuf[errlen] = '\0';
198 fputs(errbuf, stderr);
199 }
200
201 return (done ? EXIT_SUCCESS : EXIT_FAILURE);
202}