]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - games/morse/morse.c
This commit was generated by cvs2svn to compensate for changes in r147078,
[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         {'/', "-..-."},
127         {'-', "-....-"},
128         {'=', "-...-"},         /* BT */
129         {':', "---..."},
130         {';', "-.-.-."},
131         {'(', "-.--."},         /* KN */
132         {')', "-.--.-"},
133         {'$', "...-..-"},
134         {'+', ".-.-."},         /* AR */
135         {'@', ".--.-."},        /* AC */
136
137         /* prosigns without already assigned values */
138
139         {'#', ".-..."},         /* AS */
140         {'&', "...-.-"},        /* SK */
141         {'*', "...-."},         /* VE */
142         {'%', "-...-.-"},       /* BK */
143
144         {'\0', ""}
145 };
146
147
148 static const struct morsetab iso8859_1tab[] = {
149         {'á', ".--.-"},
150         {'à', ".--.-"},
151         {'â', ".--.-"},
152         {'ä', ".-.-"},
153         {'ç', "-.-.."},
154         {'é', "..-.."},
155         {'è', "..-.."},
156         {'ê', "-..-."},
157         {'ö', "---."},
158         {'ü', "..--"},
159
160         {'\0', ""}
161 };
162
163 static const struct morsetab iso8859_7tab[] = {
164         /*
165          * The greek alphabet; you'll need an 8859-7 font in order
166          * to see the actual characters.
167          * This table does not implement:
168          * - the special sequences for the seven diphthongs,
169          * - the punctuation differences.
170          * Implementing these features would introduce too many
171          * special-cases in the program's main loop.
172          * The diphtong sequences are:
173          * alpha iota           .-.-
174          * alpha upsilon        ..--
175          * epsilon upsilon      ---.
176          * eta upsilon          ...-
177          * omikron iota         ---..
178          * omikron upsilon      ..-
179          * upsilon iota         .---
180          * The different punctuation symbols are:
181          * ;    ..-.-
182          * !    --..--
183          */
184         {'á', ".-"},    /* alpha */
185         {'Ü', ".-"},    /* alpha with acute */
186         {'â', "-..."},  /* beta */
187         {'ã', "--."},   /* gamma */
188         {'ä', "-.."},   /* delta */
189         {'å', "."},     /* epsilon */
190         {'Ý', "."},     /* epsilon with acute */
191         {'æ', "--.."},  /* zeta */
192         {'ç', "...."},  /* eta */
193         {'Þ', "...."},  /* eta with acute */
194         {'è', "-.-."},  /* theta */
195         {'é', ".."},    /* iota */
196         {'ß', ".."},    /* iota with acute */
197         {'ú', ".."},    /* iota with diairesis */
198         {'À', ".."},    /* iota with acute and diairesis */
199         {'ê', "-.-"},   /* kappa */
200         {'ë', ".-.."},  /* lamda */
201         {'ì', "--"},    /* mu */
202         {'í', "-."},    /* nu */
203         {'î', "-..-"},  /* xi */
204         {'ï', "---"},   /* omicron */
205         {'ü', "---"},   /* omicron with acute */
206         {'ð', ".--."},  /* pi */
207         {'ñ', ".-."},   /* rho */
208         {'ó', "..."},   /* sigma */
209         {'ò', "..."},   /* final sigma */
210         {'ô', "-"},     /* tau */
211         {'õ', "-.--"},  /* upsilon */
212         {'ý', "-.--"},  /* upsilon with acute */
213         {'û', "-.--"},  /* upsilon and diairesis */
214         {'à', "-.--"},  /* upsilon with acute and diairesis */
215         {'ö', "..-."},  /* phi */
216         {'÷', "----"},  /* chi */
217         {'ø', "--.-"},  /* psi */
218         {'ù', ".--"},   /* omega */
219         {'þ', ".--"},   /* omega with acute */
220
221         {'\0', ""}
222 };
223
224 static const struct morsetab koi8rtab[] = {
225         /*
226          * the cyrillic alphabet; you'll need a KOI8R font in order
227          * to see the actual characters
228          */
229         {'Á', ".-"},            /* a */
230         {'Â', "-..."},  /* be */
231         {'×', ".--"},   /* ve */
232         {'Ç', "--."},   /* ge */
233         {'Ä', "-.."},   /* de */
234         {'Å', "."},             /* ye */
235         {'£', "."},             /* yo, the same as ye */
236         {'Ö', "...-"},  /* she */
237         {'Ú', "--.."},  /* ze */
238         {'É', ".."},            /* i */
239         {'Ê', ".---"},  /* i kratkoye */
240         {'Ë', "-.-"},   /* ka */
241         {'Ì', ".-.."},  /* el */
242         {'Í', "--"},            /* em */
243         {'Î', "-."},            /* en */
244         {'Ï', "---"},   /* o */
245         {'Ð', ".--."},  /* pe */
246         {'Ò', ".-."},   /* er */
247         {'Ó', "..."},   /* es */
248         {'Ô', "-"},             /* te */
249         {'Õ', "..-"},   /* u */
250         {'Æ', "..-."},  /* ef */
251         {'È', "...."},  /* kha */
252         {'Ã', "-.-."},  /* ce */
253         {'Þ', "---."},  /* che */
254         {'Û', "----"},  /* sha */
255         {'Ý', "--.-"},  /* shcha */
256         {'Ù', "-.--"},  /* yi */
257         {'Ø', "-..-"},  /* myakhkij znak */
258         {'Ü', "..-.."}, /* ae */
259         {'À', "..--"},  /* yu */
260         {'Ñ', ".-.-"},  /* ya */
261
262         {'\0', ""}
263 };
264
265 void            show(const char *), play(const char *), morse(char);
266 void            ttyout(const char *);
267 void            sighandler(int);
268
269 #define GETOPTOPTS "d:ef:lsw:"
270 #define USAGE \
271 "usage: morse [-els] [-d device] [-w speed] [-f frequency] [string ...]\n"
272
273 static int      pflag, lflag, sflag, eflag;
274 static int      wpm = 20;       /* words per minute */
275 #define FREQUENCY 600
276 static int      freq = FREQUENCY;
277 static char     *device;        /* for tty-controlled generator */
278
279 #define DASH_LEN 3
280 #define CHAR_SPACE 3
281 #define WORD_SPACE (7 - CHAR_SPACE - 1)
282 static float    dot_clock;
283 int             spkr, line;
284 struct termios  otty, ntty;
285 int             olflags;
286
287 #ifdef SPEAKER
288 tone_t          sound;
289 #undef GETOPTOPTS
290 #define GETOPTOPTS "d:ef:lpsw:"
291 #undef USAGE
292 #define USAGE \
293 "usage: morse [-elps] [-d device] [-w speed] [-f frequency] [string ...]\n"
294 #endif
295
296 static const struct morsetab *hightab;
297
298 int
299 main(int argc, char **argv)
300 {
301         int    ch, lflags;
302         char  *p, *codeset;
303
304         while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
305                 switch ((char) ch) {
306                 case 'd':
307                         device = optarg;
308                         break;
309                 case 'e':
310                         eflag = 1;
311                         setvbuf(stdout, 0, _IONBF, 0);
312                         break;
313                 case 'f':
314                         freq = atoi(optarg);
315                         break;
316                 case 'l':
317                         lflag = 1;
318                         break;
319 #ifdef SPEAKER
320                 case 'p':
321                         pflag = 1;
322                         break;
323 #endif
324                 case 's':
325                         sflag = 1;
326                         break;
327                 case 'w':
328                         wpm = atoi(optarg);
329                         break;
330                 case '?':
331                 default:
332                         fputs(USAGE, stderr);
333                         exit(1);
334                 }
335         if (sflag && lflag) {
336                 fputs("morse: only one of -l and -s allowed\n", stderr);
337                 exit(1);
338         }
339         if ((pflag || device) && (sflag || lflag)) {
340                 fputs("morse: only one of -p, -d and -l, -s allowed\n", stderr);
341                 exit(1);
342         }
343         if ((pflag || device) && ((wpm < 1) || (wpm > 60))) {
344                 fputs("morse: insane speed\n", stderr);
345                 exit(1);
346         }
347         if ((pflag || device) && (freq == 0))
348                 freq = FREQUENCY;
349
350 #ifdef SPEAKER
351         if (pflag) {
352                 if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
353                         perror(SPEAKER);
354                         exit(1);
355                 }
356         } else
357 #endif
358         if (device) {
359                 if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
360                         perror("open tty line");
361                         exit(1);
362                 }
363                 if (tcgetattr(line, &otty) == -1) {
364                         perror("tcgetattr() failed");
365                         exit(1);
366                 }
367                 ntty = otty;
368                 ntty.c_cflag |= CLOCAL;
369                 tcsetattr(line, TCSANOW, &ntty);
370                 lflags = fcntl(line, F_GETFL);
371                 lflags &= ~O_NONBLOCK;
372                 fcntl(line, F_SETFL, &lflags);
373                 ioctl(line, TIOCMGET, &lflags);
374                 lflags &= ~TIOCM_RTS;
375                 olflags = lflags;
376                 ioctl(line, TIOCMSET, &lflags);
377                 (void)signal(SIGHUP, sighandler);
378                 (void)signal(SIGINT, sighandler);
379                 (void)signal(SIGQUIT, sighandler);
380                 (void)signal(SIGTERM, sighandler);
381         }
382         if (pflag || device) {
383                 dot_clock = wpm / 2.4;          /* dots/sec */
384                 dot_clock = 1 / dot_clock;      /* duration of a dot */
385                 dot_clock = dot_clock / 2;      /* dot_clock runs at twice */
386                                                 /* the dot rate */
387                 dot_clock = dot_clock * 100;    /* scale for ioctl */
388         }
389
390         argc -= optind;
391         argv += optind;
392
393         if (setlocale(LC_CTYPE, "") != NULL &&
394             *(codeset = nl_langinfo(CODESET)) != '\0') {
395                 if (strcmp(codeset, "KOI8-R") == 0)
396                         hightab = koi8rtab;
397                 else if (strcmp(codeset, "ISO8859-1") == 0 ||
398                          strcmp(codeset, "ISO8859-15") == 0)
399                         hightab = iso8859_1tab;
400                 else if (strcmp(codeset, "ISO8859-7") == 0)
401                         hightab = iso8859_7tab;
402         }
403
404         if (lflag)
405                 printf("m");
406         if (*argv) {
407                 do {
408                         for (p = *argv; *p; ++p) {
409                                 if (eflag)
410                                         putchar(*p);
411                                 morse(*p);
412                         }
413                         if (eflag)
414                                 putchar(' ');
415                         morse(' ');
416                 } while (*++argv);
417         } else {
418                 while ((ch = getchar()) != EOF) {
419                         if (eflag)
420                                 putchar(ch);
421                         morse(ch);
422                 }
423         }
424         if (device)
425                 tcsetattr(line, TCSANOW, &otty);
426         exit(0);
427 }
428
429 void
430 morse(char c)
431 {
432         const struct morsetab *m;
433
434         if (isalpha((unsigned char)c))
435                 c = tolower((unsigned char)c);
436         if ((c == '\r') || (c == '\n'))
437                 c = ' ';
438         if (c == ' ') {
439                 if (pflag)
440                         play(" ");
441                 else if (device)
442                         ttyout(" ");
443                 else if (lflag)
444                         printf("\n");
445                 else
446                         show("");
447                 return;
448         }
449         for (m = ((unsigned char)c < 0x80? mtab: hightab);
450              m != NULL && m->inchar != '\0';
451              m++) {
452                 if (m->inchar == c) {
453                         if (pflag) {
454                                 play(m->morse);
455                         } else if (device) {
456                                 ttyout(m->morse);
457                         } else
458                                 show(m->morse);
459                 }
460         }
461 }
462
463 void
464 show(const char *s)
465 {
466         if (lflag) {
467                 printf("%s ", s);
468         } else if (sflag) {
469                 printf(" %s\n", s);
470         } else {
471                 for (; *s; ++s)
472                         printf(" %s", *s == '.' ? "dit" : "dah");
473                 printf("\n");
474         }
475 }
476
477 void
478 play(const char *s)
479 {
480 #ifdef SPEAKER
481         const char *c;
482
483         for (c = s; *c != '\0'; c++) {
484                 switch (*c) {
485                 case '.':
486                         sound.frequency = freq;
487                         sound.duration = dot_clock;
488                         break;
489                 case '-':
490                         sound.frequency = freq;
491                         sound.duration = dot_clock * DASH_LEN;
492                         break;
493                 case ' ':
494                         sound.frequency = 0;
495                         sound.duration = dot_clock * WORD_SPACE;
496                         break;
497                 default:
498                         sound.duration = 0;
499                 }
500                 if (sound.duration) {
501                         if (ioctl(spkr, SPKRTONE, &sound) == -1) {
502                                 perror("ioctl play");
503                                 exit(1);
504                         }
505                 }
506                 sound.frequency = 0;
507                 sound.duration = dot_clock;
508                 if (ioctl(spkr, SPKRTONE, &sound) == -1) {
509                         perror("ioctl rest");
510                         exit(1);
511                 }
512         }
513         sound.frequency = 0;
514         sound.duration = dot_clock * CHAR_SPACE;
515         ioctl(spkr, SPKRTONE, &sound);
516 #endif
517 }
518
519 void
520 ttyout(const char *s)
521 {
522         const char *c;
523         int duration, on, lflags;
524
525         for (c = s; *c != '\0'; c++) {
526                 switch (*c) {
527                 case '.':
528                         on = 1;
529                         duration = dot_clock;
530                         break;
531                 case '-':
532                         on = 1;
533                         duration = dot_clock * DASH_LEN;
534                         break;
535                 case ' ':
536                         on = 0;
537                         duration = dot_clock * WORD_SPACE;
538                         break;
539                 default:
540                         on = 0;
541                         duration = 0;
542                 }
543                 if (on) {
544                         ioctl(line, TIOCMGET, &lflags);
545                         lflags |= TIOCM_RTS;
546                         ioctl(line, TIOCMSET, &lflags);
547                 }
548                 duration *= 10000;
549                 if (duration)
550                         usleep(duration);
551                 ioctl(line, TIOCMGET, &lflags);
552                 lflags &= ~TIOCM_RTS;
553                 ioctl(line, TIOCMSET, &lflags);
554                 duration = dot_clock * 10000;
555                 usleep(duration);
556         }
557         duration = dot_clock * CHAR_SPACE * 10000;
558         usleep(duration);
559 }
560
561 void
562 sighandler(int signo)
563 {
564
565         ioctl(line, TIOCMSET, &olflags);
566         tcsetattr(line, TCSANOW, &otty);
567
568         signal(signo, SIG_DFL);
569         (void)kill(getpid(), signo);
570 }