]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - games/morse/morse.c
This commit was generated by cvs2svn to compensate for changes in r123315,
[FreeBSD/FreeBSD.git] / games / morse / morse.c
1 /*
2  * Copyright (c) 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
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.
20  *
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.
32  */
33
34 /*
35  * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
36  * <lyndon@orthanc.com>
37  */
38
39 #ifndef lint
40 static const char copyright[] =
41 "@(#) Copyright (c) 1988, 1993\n\
42         The Regents of the University of California.  All rights reserved.\n";
43 #endif /* not lint */
44
45 #ifndef lint
46 #if 0
47 static char sccsid[] = "@(#)morse.c     8.1 (Berkeley) 5/31/93";
48 #endif
49 static const char rcsid[] =
50  "$FreeBSD$";
51 #endif /* not lint */
52
53 #include <sys/time.h>
54
55 #include <ctype.h>
56 #include <fcntl.h>
57 #include <langinfo.h>
58 #include <locale.h>
59 #include <signal.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <termios.h>
64 #include <unistd.h>
65
66 #ifdef SPEAKER
67 #include <machine/speaker.h>
68 #endif
69
70 struct morsetab {
71         char            inchar;
72         char           *morse;
73 };
74
75 static const struct morsetab mtab[] = {
76
77         /* letters */
78
79         {'a', ".-"},
80         {'b', "-..."},
81         {'c', "-.-."},
82         {'d', "-.."},
83         {'e', "."},
84         {'f', "..-."},
85         {'g', "--."},
86         {'h', "...."},
87         {'i', ".."},
88         {'j', ".---"},
89         {'k', "-.-"},
90         {'l', ".-.."},
91         {'m', "--"},
92         {'n', "-."},
93         {'o', "---"},
94         {'p', ".--."},
95         {'q', "--.-"},
96         {'r', ".-."},
97         {'s', "..."},
98         {'t', "-"},
99         {'u', "..-"},
100         {'v', "...-"},
101         {'w', ".--"},
102         {'x', "-..-"},
103         {'y', "-.--"},
104         {'z', "--.."},
105
106         /* digits */
107
108         {'0', "-----"},
109         {'1', ".----"},
110         {'2', "..---"},
111         {'3', "...--"},
112         {'4', "....-"},
113         {'5', "....."},
114         {'6', "-...."},
115         {'7', "--..."},
116         {'8', "---.."},
117         {'9', "----."},
118
119         /* punctuation */
120
121         {',', "--..--"},
122         {'.', ".-.-.-"},
123         {'?', "..--.."},
124         {'/', "-..-."},
125         {'-', "-....-"},
126         {'=', "-...-"},         /* BT */
127         {':', "---..."},
128         {';', "-.-.-."},
129         {'(', "-.--."},         /* KN */
130         {')', "-.--.-"},
131         {'$', "...-..-"},
132         {'+', ".-.-."},         /* AR */
133
134         /* prosigns without already assigned values */
135
136         {'#', ".-..."},         /* AS */
137         {'@', "...-.-"},        /* SK */
138         {'*', "...-."},         /* VE */
139         {'%', "-...-.-"},       /* BK */
140
141         {'\0', ""}
142 };
143
144
145 static const struct morsetab iso8859tab[] = {
146         {'á', ".--.-"},
147         {'à', ".--.-"},
148         {'â', ".--.-"},
149         {'ä', ".-.-"},
150         {'ç', "-.-.."},
151         {'é', "..-.."},
152         {'è', "..-.."},
153         {'ê', "-..-."},
154         {'ö', "---."},
155         {'ü', "..--"},
156
157         {'\0', ""}
158 };
159
160 static const struct morsetab koi8rtab[] = {
161         /*
162          * the cyrillic alphabet; you'll need a KOI8R font in order
163          * to see the actual characters
164          */
165         {'Á', ".-"},            /* a */
166         {'Â', "-..."},  /* be */
167         {'×', ".--"},   /* ve */
168         {'Ç', "--."},   /* ge */
169         {'Ä', "-.."},   /* de */
170         {'Å', "."},             /* ye */
171         {'£', "."},             /* yo, the same as ye */
172         {'Ö', "...-"},  /* she */
173         {'Ú', "--.."},  /* ze */
174         {'É', ".."},            /* i */
175         {'Ê', ".---"},  /* i kratkoye */
176         {'Ë', "-.-"},   /* ka */
177         {'Ì', ".-.."},  /* el */
178         {'Í', "--"},            /* em */
179         {'Î', "-."},            /* en */
180         {'Ï', "---"},   /* o */
181         {'Ð', ".--."},  /* pe */
182         {'Ò', ".-."},   /* er */
183         {'Ó', "..."},   /* es */
184         {'Ô', "-"},             /* te */
185         {'Õ', "..-"},   /* u */
186         {'Æ', "..-."},  /* ef */
187         {'È', "...."},  /* kha */
188         {'Ã', "-.-."},  /* ce */
189         {'Þ', "---."},  /* che */
190         {'Û', "----"},  /* sha */
191         {'Ý', "--.-"},  /* shcha */
192         {'Ù', "-.--"},  /* yi */
193         {'Ø', "-..-"},  /* myakhkij znak */
194         {'Ü', "..-.."}, /* ae */
195         {'À', "..--"},  /* yu */
196         {'Ñ', ".-.-"},  /* ya */
197
198         {'\0', ""}
199 };
200
201 void            show(const char *), play(const char *), morse(char);
202 void            ttyout(const char *);
203 void            sighandler(int);
204
205 #define GETOPTOPTS "d:ef:lsw:"
206 #define USAGE \
207 "usage: morse [-els] [-d device] [-w speed] [-f frequency] [string ...]\n"
208
209 static int      pflag, lflag, sflag, eflag;
210 static int      wpm = 20;       /* words per minute */
211 #define FREQUENCY 600
212 static int      freq = FREQUENCY;
213 static char     *device;        /* for tty-controlled generator */
214
215 #define DASH_LEN 3
216 #define CHAR_SPACE 3
217 #define WORD_SPACE (7 - CHAR_SPACE - 1)
218 static float    dot_clock;
219 int             spkr, line;
220 struct termios  otty, ntty;
221 int             olflags;
222
223 #ifdef SPEAKER
224 tone_t          sound;
225 #undef GETOPTOPTS
226 #define GETOPTOPTS "d:ef:lpsw:"
227 #undef USAGE
228 #define USAGE \
229 "usage: morse [-s] [-p] [-e] [-d device] [-w speed] [-f frequency] [string ...]\n"
230 #endif
231
232 static const struct morsetab *hightab;
233
234 int
235 main(int argc, char **argv)
236 {
237         int    ch, lflags;
238         char  *p, *codeset;
239
240         while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
241                 switch ((char) ch) {
242                 case 'd':
243                         device = optarg;
244                         break;
245                 case 'e':
246                         eflag = 1;
247                         setvbuf(stdout, 0, _IONBF, 0);
248                         break;
249                 case 'f':
250                         freq = atoi(optarg);
251                         break;
252                 case 'l':
253                         lflag = 1;
254                         break;
255 #ifdef SPEAKER
256                 case 'p':
257                         pflag = 1;
258                         break;
259 #endif
260                 case 's':
261                         sflag = 1;
262                         break;
263                 case 'w':
264                         wpm = atoi(optarg);
265                         break;
266                 case '?':
267                 default:
268                         fputs(USAGE, stderr);
269                         exit(1);
270                 }
271         if (sflag && lflag) {
272                 fputs("morse: only one of -l and -s allowed\n", stderr);
273                 exit(1);
274         }
275         if ((pflag || device) && (sflag || lflag)) {
276                 fputs("morse: only one of -p, -d and -l, -s allowed\n", stderr);
277                 exit(1);
278         }
279         if ((pflag || device) && ((wpm < 1) || (wpm > 60))) {
280                 fputs("morse: insane speed\n", stderr);
281                 exit(1);
282         }
283         if ((pflag || device) && (freq == 0))
284                 freq = FREQUENCY;
285
286 #ifdef SPEAKER
287         if (pflag) {
288                 if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
289                         perror(SPEAKER);
290                         exit(1);
291                 }
292         } else
293 #endif
294         if (device) {
295                 if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
296                         perror("open tty line");
297                         exit(1);
298                 }
299                 if (tcgetattr(line, &otty) == -1) {
300                         perror("tcgetattr() failed");
301                         exit(1);
302                 }
303                 ntty = otty;
304                 ntty.c_cflag |= CLOCAL;
305                 tcsetattr(line, TCSANOW, &ntty);
306                 lflags = fcntl(line, F_GETFL);
307                 lflags &= ~O_NONBLOCK;
308                 fcntl(line, F_SETFL, &lflags);
309                 ioctl(line, TIOCMGET, &lflags);
310                 lflags &= ~TIOCM_RTS;
311                 olflags = lflags;
312                 ioctl(line, TIOCMSET, &lflags);
313                 (void)signal(SIGHUP, sighandler);
314                 (void)signal(SIGINT, sighandler);
315                 (void)signal(SIGQUIT, sighandler);
316                 (void)signal(SIGTERM, sighandler);
317         }
318         if (pflag || device) {
319                 dot_clock = wpm / 2.4;          /* dots/sec */
320                 dot_clock = 1 / dot_clock;      /* duration of a dot */
321                 dot_clock = dot_clock / 2;      /* dot_clock runs at twice */
322                                                 /* the dot rate */
323                 dot_clock = dot_clock * 100;    /* scale for ioctl */
324         }
325
326         argc -= optind;
327         argv += optind;
328
329         if (setlocale(LC_CTYPE, "") != NULL &&
330             *(codeset = nl_langinfo(CODESET)) != '\0') {
331                 if (strcmp(codeset, "KOI8-R") == 0)
332                         hightab = koi8rtab;
333                 else if (strcmp(codeset, "ISO8859-1") == 0 ||
334                          strcmp(codeset, "ISO8859-15") == 0)
335                         hightab = iso8859tab;
336         }
337
338         if (lflag)
339                 printf("m");
340         if (*argv) {
341                 do {
342                         for (p = *argv; *p; ++p) {
343                                 if (eflag)
344                                         putchar(*p);
345                                 morse(*p);
346                         }
347                         if (eflag)
348                                 putchar(' ');
349                         morse(' ');
350                 } while (*++argv);
351         } else {
352                 while ((ch = getchar()) != EOF) {
353                         if (eflag)
354                                 putchar(ch);
355                         morse(ch);
356                 }
357         }
358         if (device)
359                 tcsetattr(line, TCSANOW, &otty);
360         exit(0);
361 }
362
363 void
364 morse(char c)
365 {
366         const struct morsetab *m;
367
368         if (isalpha((unsigned char)c))
369                 c = tolower((unsigned char)c);
370         if ((c == '\r') || (c == '\n'))
371                 c = ' ';
372         if (c == ' ') {
373                 if (pflag)
374                         play(" ");
375                 else if (device)
376                         ttyout(" ");
377                 else if (lflag)
378                         printf("\n");
379                 else
380                         show("");
381                 return;
382         }
383         for (m = ((unsigned char)c < 0x80? mtab: hightab);
384              m != NULL && m->inchar != '\0';
385              m++) {
386                 if (m->inchar == c) {
387                         if (pflag) {
388                                 play(m->morse);
389                         } else if (device) {
390                                 ttyout(m->morse);
391                         } else
392                                 show(m->morse);
393                 }
394         }
395 }
396
397 void
398 show(const char *s)
399 {
400         if (lflag) {
401                 printf("%s ", s);
402         } else if (sflag) {
403                 printf(" %s\n", s);
404         } else {
405                 for (; *s; ++s)
406                         printf(" %s", *s == '.' ? "dit" : "dah");
407                 printf("\n");
408         }
409 }
410
411 void
412 play(const char *s)
413 {
414 #ifdef SPEAKER
415         const char *c;
416
417         for (c = s; *c != '\0'; c++) {
418                 switch (*c) {
419                 case '.':
420                         sound.frequency = freq;
421                         sound.duration = dot_clock;
422                         break;
423                 case '-':
424                         sound.frequency = freq;
425                         sound.duration = dot_clock * DASH_LEN;
426                         break;
427                 case ' ':
428                         sound.frequency = 0;
429                         sound.duration = dot_clock * WORD_SPACE;
430                         break;
431                 default:
432                         sound.duration = 0;
433                 }
434                 if (sound.duration) {
435                         if (ioctl(spkr, SPKRTONE, &sound) == -1) {
436                                 perror("ioctl play");
437                                 exit(1);
438                         }
439                 }
440                 sound.frequency = 0;
441                 sound.duration = dot_clock;
442                 if (ioctl(spkr, SPKRTONE, &sound) == -1) {
443                         perror("ioctl rest");
444                         exit(1);
445                 }
446         }
447         sound.frequency = 0;
448         sound.duration = dot_clock * CHAR_SPACE;
449         ioctl(spkr, SPKRTONE, &sound);
450 #endif
451 }
452
453 void
454 ttyout(const char *s)
455 {
456         const char *c;
457         int duration, on, lflags;
458
459         for (c = s; *c != '\0'; c++) {
460                 switch (*c) {
461                 case '.':
462                         on = 1;
463                         duration = dot_clock;
464                         break;
465                 case '-':
466                         on = 1;
467                         duration = dot_clock * DASH_LEN;
468                         break;
469                 case ' ':
470                         on = 0;
471                         duration = dot_clock * WORD_SPACE;
472                         break;
473                 default:
474                         on = 0;
475                         duration = 0;
476                 }
477                 if (on) {
478                         ioctl(line, TIOCMGET, &lflags);
479                         lflags |= TIOCM_RTS;
480                         ioctl(line, TIOCMSET, &lflags);
481                 }
482                 duration *= 10000;
483                 if (duration)
484                         usleep(duration);
485                 ioctl(line, TIOCMGET, &lflags);
486                 lflags &= ~TIOCM_RTS;
487                 ioctl(line, TIOCMSET, &lflags);
488                 duration = dot_clock * 10000;
489                 usleep(duration);
490         }
491         duration = dot_clock * CHAR_SPACE * 10000;
492         usleep(duration);
493 }
494
495 void
496 sighandler(int signo)
497 {
498
499         ioctl(line, TIOCMSET, &olflags);
500         tcsetattr(line, TCSANOW, &otty);
501
502         signal(signo, SIG_DFL);
503         (void)kill(getpid(), signo);
504 }