Fix "ls: not found" problem during buildworld. mdate.sh script
[dragonfly.git] / games / morse / morse.c
blob07a82d90dd7300c8c6d6e4b364009a0d8e1c3c6f
1 /*
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 * @(#) Copyright (c) 1988, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)morse.c 8.1 (Berkeley) 5/31/93
35 * $FreeBSD: src/games/morse/morse.c,v 1.12.2.2 2002/03/12 17:45:15 phantom Exp $
36 * $DragonFly: src/games/morse/morse.c,v 1.3 2005/04/25 16:10:24 liamfoy Exp $
40 * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
41 * <lyndon@orthanc.com>
44 #include <sys/time.h>
46 #include <ctype.h>
47 #include <fcntl.h>
48 #include <langinfo.h>
49 #include <locale.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <termios.h>
55 #include <unistd.h>
57 #ifdef SPEAKER
58 #include <machine/speaker.h>
59 #endif
61 struct morsetab {
62 char inchar;
63 const char *morse;
66 static const struct morsetab mtab[] = {
68 /* letters */
70 {'a', ".-"},
71 {'b', "-..."},
72 {'c', "-.-."},
73 {'d', "-.."},
74 {'e', "."},
75 {'f', "..-."},
76 {'g', "--."},
77 {'h', "...."},
78 {'i', ".."},
79 {'j', ".---"},
80 {'k', "-.-"},
81 {'l', ".-.."},
82 {'m', "--"},
83 {'n', "-."},
84 {'o', "---"},
85 {'p', ".--."},
86 {'q', "--.-"},
87 {'r', ".-."},
88 {'s', "..."},
89 {'t', "-"},
90 {'u', "..-"},
91 {'v', "...-"},
92 {'w', ".--"},
93 {'x', "-..-"},
94 {'y', "-.--"},
95 {'z', "--.."},
97 /* digits */
99 {'0', "-----"},
100 {'1', ".----"},
101 {'2', "..---"},
102 {'3', "...--"},
103 {'4', "....-"},
104 {'5', "....."},
105 {'6', "-...."},
106 {'7', "--..."},
107 {'8', "---.."},
108 {'9', "----."},
110 /* punctuation */
112 {',', "--..--"},
113 {'.', ".-.-.-"},
114 {'?', "..--.."},
115 {'/', "-..-."},
116 {'-', "-....-"},
117 {'=', "-...-"}, /* BT */
118 {':', "---..."},
119 {';', "-.-.-."},
120 {'(', "-.--."}, /* KN */
121 {')', "-.--.-"},
122 {'$', "...-..-"},
123 {'+', ".-.-."}, /* AR */
125 /* prosigns without already assigned values */
127 {'#', ".-..."}, /* AS */
128 {'@', "...-.-"}, /* SK */
129 {'*', "...-."}, /* VE */
130 {'%', "-...-.-"}, /* BK */
132 {'\0', ""}
136 static const struct morsetab iso8859tab[] = {
137 {'á', ".--.-"},
138 {'à', ".--.-"},
139 {'â', ".--.-"},
140 {'ä', ".-.-"},
141 {'ç', "-.-.."},
142 {'é', "..-.."},
143 {'è', "..-.."},
144 {'ê', "-..-."},
145 {'ö', "---."},
146 {'ü', "..--"},
148 {'\0', ""}
151 static const struct morsetab koi8rtab[] = {
153 * the cyrillic alphabet; you'll need a KOI8R font in order
154 * to see the actual characters
156 {'Á', ".-"}, /* a */
157 {'Â', "-..."}, /* be */
158 {'×', ".--"}, /* ve */
159 {'Ç', "--."}, /* ge */
160 {'Ä', "-.."}, /* de */
161 {'Å', "."}, /* ye */
162 {'£', "."}, /* yo, the same as ye */
163 {'Ö', "...-"}, /* she */
164 {'Ú', "--.."}, /* ze */
165 {'É', ".."}, /* i */
166 {'Ê', ".---"}, /* i kratkoye */
167 {'Ë', "-.-"}, /* ka */
168 {'Ì', ".-.."}, /* el */
169 {'Í', "--"}, /* em */
170 {'Î', "-."}, /* en */
171 {'Ï', "---"}, /* o */
172 {'Ð', ".--."}, /* pe */
173 {'Ò', ".-."}, /* er */
174 {'Ó', "..."}, /* es */
175 {'Ô', "-"}, /* te */
176 {'Õ', "..-"}, /* u */
177 {'Æ', "..-."}, /* ef */
178 {'È', "...."}, /* kha */
179 {'Ã', "-.-."}, /* ce */
180 {'Þ', "---."}, /* che */
181 {'Û', "----"}, /* sha */
182 {'Ý', "--.-"}, /* shcha */
183 {'Ù', "-.--"}, /* yi */
184 {'Ø', "-..-"}, /* myakhkij znak */
185 {'Ü', "..-.."}, /* ae */
186 {'À', "..--"}, /* yu */
187 {'Ñ', ".-.-"}, /* ya */
189 {'\0', ""}
192 void show(const char *), play(const char *), morse(char);
193 void ttyout(const char *);
194 void sighandler(int);
196 #define GETOPTOPTS "d:ef:sw:"
197 #define USAGE \
198 "usage: morse [-s] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n"
200 static int pflag, sflag, eflag;
201 static int wpm = 20; /* words per minute */
202 #define FREQUENCY 600
203 static int freq = FREQUENCY;
204 static char *device; /* for tty-controlled generator */
206 #define DASH_LEN 3
207 #define CHAR_SPACE 3
208 #define WORD_SPACE (7 - CHAR_SPACE - 1)
209 static float dot_clock;
210 int spkr, line;
211 struct termios otty, ntty;
212 int olflags;
214 #ifdef SPEAKER
215 tone_t sound;
216 #undef GETOPTOPTS
217 #define GETOPTOPTS "d:ef:psw:"
218 #undef USAGE
219 #define USAGE \
220 "usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n"
221 #endif
223 static const struct morsetab *hightab;
226 main(int argc, char **argv)
228 int ch, lflags;
229 char *p, *codeset;
231 while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
232 switch ((char) ch) {
233 case 'd':
234 device = optarg;
235 break;
236 case 'e':
237 eflag = 1;
238 setvbuf(stdout, 0, _IONBF, 0);
239 break;
240 case 'f':
241 freq = atoi(optarg);
242 break;
243 #ifdef SPEAKER
244 case 'p':
245 pflag = 1;
246 break;
247 #endif
248 case 's':
249 sflag = 1;
250 break;
251 case 'w':
252 wpm = atoi(optarg);
253 break;
254 case '?':
255 default:
256 fputs(USAGE, stderr);
257 exit(1);
259 if ((pflag || device) && sflag) {
260 fputs("morse: only one of -p, -d and -s allowed\n", stderr);
261 exit(1);
263 if ((pflag || device) && ((wpm < 1) || (wpm > 60))) {
264 fputs("morse: insane speed\n", stderr);
265 exit(1);
267 if ((pflag || device) && (freq == 0))
268 freq = FREQUENCY;
270 #ifdef SPEAKER
271 if (pflag) {
272 if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
273 perror(SPEAKER);
274 exit(1);
276 } else
277 #endif
278 if (device) {
279 if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
280 perror("open tty line");
281 exit(1);
283 if (tcgetattr(line, &otty) == -1) {
284 perror("tcgetattr() failed");
285 exit(1);
287 ntty = otty;
288 ntty.c_cflag |= CLOCAL;
289 tcsetattr(line, TCSANOW, &ntty);
290 lflags = fcntl(line, F_GETFL);
291 lflags &= ~O_NONBLOCK;
292 fcntl(line, F_SETFL, &lflags);
293 ioctl(line, TIOCMGET, &lflags);
294 lflags &= ~TIOCM_RTS;
295 olflags = lflags;
296 ioctl(line, TIOCMSET, &lflags);
297 (void)signal(SIGHUP, sighandler);
298 (void)signal(SIGINT, sighandler);
299 (void)signal(SIGQUIT, sighandler);
300 (void)signal(SIGTERM, sighandler);
302 if (pflag || device) {
303 dot_clock = wpm / 2.4; /* dots/sec */
304 dot_clock = 1 / dot_clock; /* duration of a dot */
305 dot_clock = dot_clock / 2; /* dot_clock runs at twice */
306 /* the dot rate */
307 dot_clock = dot_clock * 100; /* scale for ioctl */
310 argc -= optind;
311 argv += optind;
313 if (setlocale(LC_CTYPE, "") != NULL &&
314 *(codeset = nl_langinfo(CODESET)) != '\0') {
315 if (strcmp(codeset, "KOI8-R") == 0)
316 hightab = koi8rtab;
317 else if (strcmp(codeset, "ISO8859-1") == 0 ||
318 strcmp(codeset, "ISO8859-15") == 0)
319 hightab = iso8859tab;
322 if (*argv) {
323 do {
324 for (p = *argv; *p; ++p) {
325 if (eflag)
326 putchar(*p);
327 morse(*p);
329 if (eflag)
330 putchar(' ');
331 morse(' ');
332 } while (*++argv);
333 } else {
334 while ((ch = getchar()) != EOF) {
335 if (eflag)
336 putchar(ch);
337 morse(ch);
340 if (device)
341 tcsetattr(line, TCSANOW, &otty);
342 exit(0);
345 void
346 morse(char c)
348 const struct morsetab *m;
350 if (isalpha((unsigned char)c))
351 c = tolower((unsigned char)c);
352 if ((c == '\r') || (c == '\n'))
353 c = ' ';
354 if (c == ' ') {
355 if (pflag) {
356 play(" ");
357 return;
358 } else if (device) {
359 ttyout(" ");
360 return;
361 } else {
362 show("");
363 return;
366 for (m = ((unsigned char)c < 0x80? mtab: hightab);
367 m != NULL && m->inchar != '\0';
368 m++) {
369 if (m->inchar == c) {
370 if (pflag) {
371 play(m->morse);
372 } else if (device) {
373 ttyout(m->morse);
374 } else
375 show(m->morse);
380 void
381 show(const char *s)
383 if (sflag)
384 printf(" %s", s);
385 else
386 for (; *s; ++s)
387 printf(" %s", *s == '.' ? "dit" : "dah");
388 printf("\n");
391 void
392 play(const char *s)
394 #ifdef SPEAKER
395 const char *c;
397 for (c = s; *c != '\0'; c++) {
398 switch (*c) {
399 case '.':
400 sound.frequency = freq;
401 sound.duration = dot_clock;
402 break;
403 case '-':
404 sound.frequency = freq;
405 sound.duration = dot_clock * DASH_LEN;
406 break;
407 case ' ':
408 sound.frequency = 0;
409 sound.duration = dot_clock * WORD_SPACE;
410 break;
411 default:
412 sound.duration = 0;
414 if (sound.duration) {
415 if (ioctl(spkr, SPKRTONE, &sound) == -1) {
416 perror("ioctl play");
417 exit(1);
420 sound.frequency = 0;
421 sound.duration = dot_clock;
422 if (ioctl(spkr, SPKRTONE, &sound) == -1) {
423 perror("ioctl rest");
424 exit(1);
427 sound.frequency = 0;
428 sound.duration = dot_clock * CHAR_SPACE;
429 ioctl(spkr, SPKRTONE, &sound);
430 #endif
433 void
434 ttyout(const char *s)
436 const char *c;
437 int duration, on, lflags;
439 for (c = s; *c != '\0'; c++) {
440 switch (*c) {
441 case '.':
442 on = 1;
443 duration = dot_clock;
444 break;
445 case '-':
446 on = 1;
447 duration = dot_clock * DASH_LEN;
448 break;
449 case ' ':
450 on = 0;
451 duration = dot_clock * WORD_SPACE;
452 break;
453 default:
454 on = 0;
455 duration = 0;
457 if (on) {
458 ioctl(line, TIOCMGET, &lflags);
459 lflags |= TIOCM_RTS;
460 ioctl(line, TIOCMSET, &lflags);
462 duration *= 10000;
463 if (duration)
464 usleep(duration);
465 ioctl(line, TIOCMGET, &lflags);
466 lflags &= ~TIOCM_RTS;
467 ioctl(line, TIOCMSET, &lflags);
468 duration = dot_clock * 10000;
469 usleep(duration);
471 duration = dot_clock * CHAR_SPACE * 10000;
472 usleep(duration);
475 void
476 sighandler(int signo)
479 ioctl(line, TIOCMSET, &olflags);
480 tcsetattr(line, TCSANOW, &otty);
482 signal(signo, SIG_DFL);
483 (void)kill(getpid(), signo);