xref: /dragonfly/games/morse/morse.c (revision 27bec85a12535ea0911620f9fd3715fd9e94f358)
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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#) Copyright (c) 1988, 1993 The Regents of the University of California.  All rights reserved.
30  * @(#)morse.c      8.1 (Berkeley) 5/31/93
31  * $FreeBSD: src/games/morse/morse.c,v 1.12.2.2 2002/03/12 17:45:15 phantom Exp $
32  * $OpenBSD: morse.c,v 1.22 2016/03/07 12:07:56 mestre Exp $
33  */
34 
35 /*
36  * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
37  * <lyndon@orthanc.ca>
38  */
39 
40 #include <sys/time.h>
41 #include <sys/soundcard.h>
42 
43 #include <ctype.h>
44 #include <err.h>
45 #include <fcntl.h>
46 #include <langinfo.h>
47 #include <locale.h>
48 #include <math.h>
49 #include <signal.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <termios.h>
54 #include <unistd.h>
55 
56 static const char *digit[] = {
57           "-----",
58           ".----",
59           "..---",
60           "...--",
61           "....-",
62           ".....",
63           "-....",
64           "--...",
65           "---..",
66           "----.",
67 };
68 
69 static const char *alph[] = {
70           ".-",
71           "-...",
72           "-.-.",
73           "-..",
74           ".",
75           "..-.",
76           "--.",
77           "....",
78           "..",
79           ".---",
80           "-.-",
81           ".-..",
82           "--",
83           "-.",
84           "---",
85           ".--.",
86           "--.-",
87           ".-.",
88           "...",
89           "-",
90           "..-",
91           "...-",
92           ".--",
93           "-..-",
94           "-.--",
95           "--..",
96 };
97 
98 struct punc {
99           char c;
100           const char *morse;
101 };
102 
103 static const struct punc other[] = {
104           { 'e', "..-.." },   /* accented e - only decodes */
105           { ',', "--..--" },
106           { '.', ".-.-.-" },
107           { '?', "..--.." },
108           { '/', "-..-." },
109           { '-', "-....-" },
110           { ':', "---..." },
111           { ';', "-.-.-." },
112           { '(', "-.--." },   /* KN */
113           { ')', "-.--.-" },
114           { '"', ".-..-." },
115           { '`', ".-..-." },
116           { '\'', ".----." },
117           { '+', ".-.-." },   /* AR \n\n\n */
118           { '=', "-...-" },   /* BT \n\n */
119           { '@', ".--.-." },
120           { '\n', ".-.-" },   /* AA (will only decode) */
121           { '\0', NULL }
122 };
123 
124 struct prosign {
125           const char *c;
126           const char *morse;
127 };
128 
129 static const struct prosign ps[] = {
130           { "<AS>", ".-..." },          /* wait */
131           { "<CL>", "-.-..-.." },
132           { "<CT>", "-.-.-" },          /* start */
133           { "<EE5>", "......" },        /* error */
134           { "<EE5>", "......." },
135           { "<EE5>", "........" },
136           { "<SK>", "...-.-" },
137           { "<SN>", "...-." },          /* understood */
138           { "<SOS>", "...---..." },
139           { NULL, NULL }
140 };
141 
142 struct morsetab {
143           char            inchar;
144           const char      *morse;
145 };
146 
147 static const struct morsetab mtab[] = {
148 
149           /* letters */
150 
151           {'a', ".-"},
152           {'b', "-..."},
153           {'c', "-.-."},
154           {'d', "-.."},
155           {'e', "."},
156           {'f', "..-."},
157           {'g', "--."},
158           {'h', "...."},
159           {'i', ".."},
160           {'j', ".---"},
161           {'k', "-.-"},
162           {'l', ".-.."},
163           {'m', "--"},
164           {'n', "-."},
165           {'o', "---"},
166           {'p', ".--."},
167           {'q', "--.-"},
168           {'r', ".-."},
169           {'s', "..."},
170           {'t', "-"},
171           {'u', "..-"},
172           {'v', "...-"},
173           {'w', ".--"},
174           {'x', "-..-"},
175           {'y', "-.--"},
176           {'z', "--.."},
177 
178           /* digits */
179 
180           {'0', "-----"},
181           {'1', ".----"},
182           {'2', "..---"},
183           {'3', "...--"},
184           {'4', "....-"},
185           {'5', "....."},
186           {'6', "-...."},
187           {'7', "--..."},
188           {'8', "---.."},
189           {'9', "----."},
190 
191           /* punctuation */
192 
193           {',', "--..--"},
194           {'.', ".-.-.-"},
195           {'?', "..--.."},
196           {'!', "-.-.--"},    /* KW */
197           {'/', "-..-."},
198           {'-', "-....-"},
199           {'_', "..--.."},
200           {'=', "-...-"},               /* BT */
201           {':', "---..."},
202           {';', "-.-.-."},
203           {'(', "-.--."},               /* KN */
204           {')', "-.--.-"},
205           {'$', "...-..-"},
206           {'+', ".-.-."},               /* AR */
207           {'\'', ".----."},
208           {'"', ".-..-."},
209           {'@', ".--.-."},    /* AC */
210 
211           {'\0', ""}
212 };
213 
214 
215 static const struct morsetab iso8859tab[] = {
216           {'�', ".--.-"},
217           {'�', ".--.-"},
218           {'�', ".--.-"},
219           {'�', ".-.-"},
220           {'�', "-.-.."},
221           {'�', "..-.."},
222           {'�', "..-.."},
223           {'�', "-..-."},
224           {'�', "---."},
225           {'�', "..--"},
226 
227           {'\0', ""}
228 };
229 
230 static const struct morsetab koi8rtab[] = {
231           /*
232            * the cyrillic alphabet; you'll need a KOI8R font in order
233            * to see the actual characters
234            */
235           {'�', ".-"},                  /* a */
236           {'�', "-..."},      /* be */
237           {'�', ".--"},       /* ve */
238           {'�', "--."},       /* ge */
239           {'�', "-.."},       /* de */
240           {'�', "."},                   /* ye */
241           {'�', "."},                   /* yo, the same as ye */
242           {'�', "...-"},      /* she */
243           {'�', "--.."},      /* ze */
244           {'�', ".."},                  /* i */
245           {'�', ".---"},      /* i kratkoye */
246           {'�', "-.-"},       /* ka */
247           {'�', ".-.."},      /* el */
248           {'�', "--"},                  /* em */
249           {'�', "-."},                  /* en */
250           {'�', "---"},       /* o */
251           {'�', ".--."},      /* pe */
252           {'�', ".-."},       /* er */
253           {'�', "..."},       /* es */
254           {'�', "-"},                   /* te */
255           {'�', "..-"},       /* u */
256           {'�', "..-."},      /* ef */
257           {'�', "...."},      /* kha */
258           {'�', "-.-."},      /* ce */
259           {'�', "---."},      /* che */
260           {'�', "----"},      /* sha */
261           {'�', "--.-"},      /* shcha */
262           {'�', "-.--"},      /* yi */
263           {'�', "-..-"},      /* myakhkij znak */
264           {'�', "..-.."},     /* ae */
265           {'�', "..--"},      /* yu */
266           {'�', ".-.-"},      /* ya */
267 
268           {'\0', ""}
269 };
270 
271 struct tone_data {
272           int16_t   *data;
273           size_t    len;
274 };
275 
276 static void                   alloc_soundbuf(struct tone_data *, double, int);
277 static void                   morse(char, int);
278 static void                   decode(const char *);
279 static void                   show(const char *, int);
280 static void                   play(const char *, int);
281 static void                   ttyout(const char *, int);
282 static void                   sighandler(int);
283 
284 #define GETOPTOPTS "d:ef:lopP:rsw:W:"
285 #define USAGE \
286 "usage: morse [-r] [-els] [-p | -o] [-P device] [-d device] [-w speed] [-W speed] [-f frequency] [string ...]\n"
287 
288 static int      lflag, oflag, pflag, rflag, sflag, eflag;
289 static int      wpm = 20;     /* words per minute */
290 static int          farnsworth = -1;
291 #define FREQUENCY 600
292 static int      freq = FREQUENCY;
293 static char         *device;  /* for tty-controlled generator */
294 
295 static struct tone_data tone_dot, tone_dash, tone_silence, tone_letter_silence;
296 #define DSP_RATE 44100
297 static const char *snddev = NULL;
298 
299 #define DASH_LEN 3
300 #define CHAR_SPACE 3
301 #define WORD_SPACE (7 - CHAR_SPACE)
302 static float    dot_clock, word_clock;
303 int             spkr, line;
304 struct termios      otty, ntty;
305 int                 olflags;
306 
307 static const struct morsetab *hightab;
308 
309 int
main(int argc,char * argv[])310 main(int argc, char *argv[])
311 {
312           int    ch, lflags;
313           int    prosign;
314           char  *p, *codeset;
315 
316           while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
317                     switch ((char) ch) {
318                     case 'd':
319                               device = optarg;
320                               break;
321                     case 'e':
322                               eflag = 1;
323                               setvbuf(stdout, 0, _IONBF, 0);
324                               break;
325                     case 'f':
326                               freq = atoi(optarg);
327                               break;
328                     case 'l':
329                               lflag = 1;
330                               break;
331                     case 'o':
332                               oflag = 1;
333                               /* FALLTHROUGH */
334                     case 'p':
335                               pflag = 1;
336                               break;
337                     case 'P':
338                               snddev = optarg;
339                               break;
340                     case 'r':
341                               rflag = 1;
342                               break;
343                     case 's':
344                               sflag = 1;
345                               break;
346                     case 'w':
347                               wpm = atoi(optarg);
348                               break;
349                     case 'W':
350                               farnsworth = atoi(optarg);
351                               break;
352                     case '?':
353                     default:
354                               fputs(USAGE, stderr);
355                               exit(1);
356                     }
357           if (sflag && lflag) {
358                     fputs("morse: only one of -l and -s allowed\n", stderr);
359                     exit(1);
360           }
361           if (pflag + !!device + sflag + lflag > 1) {
362                     fputs("morse: only one of -o, -p, -d and -l, -s allowed\n", stderr);
363                     exit(1);
364           }
365           if ((pflag || device) && ((wpm < 1) || (wpm > 60) || (farnsworth > 60))) {
366                     fputs("morse: insane speed\n", stderr);
367                     exit(1);
368           }
369           if ((pflag || device) && (freq == 0))
370                     freq = FREQUENCY;
371           if (pflag || device) {
372                     /*
373                      * A note on how to get to this magic 1.2:
374                      * x WPM = 50*x dits per minute (norm word "PARIS").
375                      * dits per sec = dits per minute / 60, thus
376                      * dits per sec = 50 * x / 60 = x / (60 / 50) = x / 1.2
377                      */
378                     dot_clock = wpm / 1.2;                  /* dots/sec */
379                     dot_clock = 1 / dot_clock;    /* duration of a dot */
380 
381                     word_clock = dot_clock;
382 
383                     /*
384                      * This is how to get to this formula:
385                      * PARIS = 22 dit (symbols) + 9 symbol spaces = 31 symbol times
386                      *       + 19 space times.
387                      *
388                      * The symbol times are in dot_clock, so the spaces have to
389                      * make up to reach the farnsworth time.
390                      */
391                     if (farnsworth > 0)
392                               word_clock = (60.0 / farnsworth - 31 * dot_clock) / 19;
393           }
394           if (snddev == NULL) {
395                     if (oflag)
396                               snddev = "-";
397                     else /* only pflag */
398                               snddev = "/dev/dsp";
399           }
400 
401           if (pflag) {
402                     snd_chan_param param;
403 
404                     if (oflag && strcmp(snddev, "-") == 0)
405                               spkr = STDOUT_FILENO;
406                     else
407                               spkr = open(snddev, O_WRONLY, 0);
408                     if (spkr == -1)
409                               err(1, "%s", snddev);
410                     param.play_rate = DSP_RATE;
411                     param.play_format = AFMT_S16_NE;
412                     param.rec_rate = 0;
413                     param.rec_format = 0;
414                     if (!oflag && ioctl(spkr, AIOSFMT, &param) != 0)
415                               err(1, "%s: set format", snddev);
416                     alloc_soundbuf(&tone_dot, dot_clock, 1);
417                     alloc_soundbuf(&tone_dash, DASH_LEN * dot_clock, 1);
418                     alloc_soundbuf(&tone_silence, dot_clock, 0);
419                     alloc_soundbuf(&tone_letter_silence, word_clock, 0);
420           } else
421           if (device) {
422                     if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
423                               perror("open tty line");
424                               exit(1);
425                     }
426                     if (tcgetattr(line, &otty) == -1) {
427                               perror("tcgetattr() failed");
428                               exit(1);
429                     }
430                     ntty = otty;
431                     ntty.c_cflag |= CLOCAL;
432                     tcsetattr(line, TCSANOW, &ntty);
433                     lflags = fcntl(line, F_GETFL);
434                     lflags &= ~O_NONBLOCK;
435                     fcntl(line, F_SETFL, &lflags);
436                     ioctl(line, TIOCMGET, &lflags);
437                     lflags &= ~TIOCM_RTS;
438                     olflags = lflags;
439                     ioctl(line, TIOCMSET, &lflags);
440                     signal(SIGHUP, sighandler);
441                     signal(SIGINT, sighandler);
442                     signal(SIGQUIT, sighandler);
443                     signal(SIGTERM, sighandler);
444           }
445 
446           argc -= optind;
447           argv += optind;
448 
449           if (setlocale(LC_CTYPE, "") != NULL &&
450               *(codeset = nl_langinfo(CODESET)) != '\0') {
451                     if (strcmp(codeset, "KOI8-R") == 0)
452                               hightab = koi8rtab;
453                     else if (strcmp(codeset, "ISO8859-1") == 0 ||
454                                strcmp(codeset, "ISO8859-15") == 0)
455                               hightab = iso8859tab;
456           }
457 
458           if (rflag) {
459                     if (*argv) {
460                               do {
461                                         decode(*argv);
462                               } while (*++argv);
463                     } else {
464                               char foo[10];       /* All morse chars shorter than this */
465                               int blank, i;
466 
467                               i = 0;
468                               blank = 0;
469                               while ((ch = getchar()) != EOF) {
470                                         if (ch == '-' || ch == '.') {
471                                                   foo[i++] = ch;
472                                                   if (i == 10) {
473                                                             /* overrun means gibberish--print 'x' and
474                                                              * advance */
475                                                             i = 0;
476                                                             putchar('x');
477                                                             while ((ch = getchar()) != EOF &&
478                                                                 (ch == '.' || ch == '-'))
479                                                                       ;
480                                                             blank = 1;
481                                                   }
482                                         } else if (i) {
483                                                   foo[i] = '\0';
484                                                   decode(foo);
485                                                   i = 0;
486                                                   blank = 0;
487                                         } else if (isspace(ch)) {
488                                                   if (blank) {
489                                                             /* print whitespace for each double blank */
490                                                             putchar(' ');
491                                                             blank = 0;
492                                                   } else
493                                                             blank = 1;
494                                         }
495                               }
496                     }
497                     putchar('\n');
498                     exit(0);
499           }
500 
501           if (lflag)
502                     printf("m");
503           if (*argv) {
504                     do {
505                               prosign = 0;
506                               for (p = *argv; *p; ++p) {
507                                         if (eflag)
508                                                   putchar(*p);
509                                         if (*p == '<' || *p == '>') {
510                                                   prosign = *p == '<';
511                                                   continue;
512                                         }
513                                         if (strchr("> \r\n", *(p + 1)) != NULL)
514                                                   prosign = 0;
515                                         morse(*p, prosign);
516                               }
517                               if (eflag)
518                                         putchar(' ');
519                               morse(' ', 0);
520                     } while (*++argv);
521           } else {
522                     prosign = 0;
523                     while ((ch = getchar()) != EOF) {
524                               if (eflag)
525                                         putchar(ch);
526                               if (ch == '<') {
527                                         prosign = 1;
528                                         continue;
529                               }
530                               if (prosign) {
531                                         int tch;
532 
533                                         tch = getchar();
534                                         if (strchr("> \r\n", tch) != NULL)
535                                                   prosign = 0;
536                                         if (tch != '>')
537                                                   ungetc(tch, stdin);
538                               }
539                               morse(ch, prosign);
540                     }
541           }
542           if (device)
543                     tcsetattr(line, TCSANOW, &otty);
544           exit(0);
545 }
546 
547 static void
alloc_soundbuf(struct tone_data * tone,double len,int on)548 alloc_soundbuf(struct tone_data *tone, double len, int on)
549 {
550           int samples, i;
551 
552           samples = DSP_RATE * len;
553           tone->len = samples * sizeof(*tone->data);
554           tone->data = malloc(tone->len);
555           if (tone->data == NULL)
556                     err(1, NULL);
557           if (!on) {
558                     bzero(tone->data, tone->len);
559                     return;
560           }
561 
562           /*
563            * We create a sinus with the specified frequency and smooth
564            * the edges to reduce key clicks.
565            */
566           for (i = 0; i < samples; i++) {
567                     double filter = 1;
568 
569 #define FILTER_SAMPLES (DSP_RATE * 8 / 1000)      /* 8 ms ramp time */
570                     if (i < FILTER_SAMPLES || i > samples - FILTER_SAMPLES) {
571                               int fi = i;
572 
573                               if (i > FILTER_SAMPLES)
574                                         fi = samples - i;
575 #if defined(TRIANGLE_FILTER)
576                               /*
577                                * Triangle envelope
578                                */
579                               filter = (double)fi / FILTER_SAMPLES;
580 #elif defined(GAUSS_FILTER)
581                               /*
582                                * Gauss envelope
583                                */
584                               filter = exp(-4.0 *
585                                              pow((double)(FILTER_SAMPLES - fi) /
586                                                    FILTER_SAMPLES, 2));
587 #else
588                               /*
589                                * Cosine envelope
590                                */
591                               filter = (1 + cos(M_PI * (FILTER_SAMPLES - fi) / FILTER_SAMPLES)) / 2;
592 #endif
593                     }
594                     tone->data[i] = 32767 * sin((double)i / samples * len * freq * 2 * M_PI) *
595                         filter;
596           }
597 }
598 
599 static void
morse(char c,int prosign)600 morse(char c, int prosign)
601 {
602           const struct morsetab *m;
603 
604           if (isalpha((unsigned char)c))
605                     c = tolower((unsigned char)c);
606           if ((c == '\r') || (c == '\n'))
607                     c = ' ';
608           if (c == ' ') {
609                     if (pflag) {
610                               play(" ", 0);
611                               return;
612                     } else if (device) {
613                               ttyout(" ", 0);
614                               return;
615                     } else if (lflag) {
616                               printf("\n");
617                     } else {
618                               show("", 0);
619                               return;
620                     }
621           }
622           for (m = ((unsigned char)c < 0x80? mtab: hightab);
623                m != NULL && m->inchar != '\0';
624                m++) {
625                     if (m->inchar == c) {
626                               if (pflag) {
627                                         play(m->morse, prosign);
628                               } else if (device) {
629                                         ttyout(m->morse, prosign);
630                               } else
631                                         show(m->morse, prosign);
632                     }
633           }
634 }
635 
636 static void
decode(const char * s)637 decode(const char *s)
638 {
639           int i;
640 
641           for (i = 0; i < 10; i++)
642                     if (strcmp(digit[i], s) == 0) {
643                               putchar('0' + i);
644                               return;
645                     }
646 
647           for (i = 0; i < 26; i++)
648                     if (strcmp(alph[i], s) == 0) {
649                               putchar('A' + i);
650                               return;
651                     }
652           i = 0;
653           while (other[i].c) {
654                     if (strcmp(other[i].morse, s) == 0) {
655                               putchar(other[i].c);
656                               return;
657                     }
658                     i++;
659           }
660           i = 0;
661           while (ps[i].c) {
662                     /* put whitespace around prosigns */
663                     if (strcmp(ps[i].morse, s) == 0) {
664                               printf(" %s ", ps[i].c);
665                               return;
666                     }
667                     i++;
668           }
669           putchar('x');       /* line noise */
670 }
671 
672 static void
show(const char * s,int prosign)673 show(const char *s, int prosign)
674 {
675           if (lflag) {
676                     printf("%s ", s);
677                     return;
678           } else if (sflag)
679                     printf(" %s", s);
680           else
681                     for (; *s; ++s)
682                               printf(" %s", *s == '.' ? "dit" : "dah");
683           if (!prosign)
684                     printf("\n");
685 }
686 
687 static void
play(const char * s,int prosign)688 play(const char *s, int prosign)
689 {
690           const char *c;
691           int duration;
692           struct tone_data *tone;
693 
694           /*
695            * We don't need to usleep() here, as the sound device blocks.
696            */
697           for (c = s; *c != '\0'; c++) {
698                     switch (*c) {
699                     case '.':
700                               duration = 1;
701                               tone = &tone_dot;
702                               break;
703                     case '-':
704                               duration = 1;
705                               tone = &tone_dash;
706                               break;
707                     case ' ':
708                               duration = WORD_SPACE;
709                               tone = &tone_letter_silence;
710                               break;
711                     default:
712                               errx(1, "invalid morse digit");
713                     }
714                     while (duration-- > 0)
715                               write(spkr, tone->data, tone->len);
716                     /* Only space within a symbol */
717                     if (c[1] != '\0' || prosign)
718                               write(spkr, tone_silence.data, tone_silence.len);
719           }
720           if (prosign)
721                     return;
722           duration = CHAR_SPACE;
723           while (duration-- > 0)
724                     write(spkr, tone_letter_silence.data, tone_letter_silence.len);
725 
726           /* Sync out the audio data with other output */
727           if (!oflag)
728                     ioctl(spkr, SNDCTL_DSP_SYNC, NULL);
729 }
730 
731 static void
ttyout(const char * s,int prosign)732 ttyout(const char *s, int prosign)
733 {
734           const char *c;
735           int duration, on, lflags;
736 
737           for (c = s; *c != '\0'; c++) {
738                     switch (*c) {
739                     case '.':
740                               on = 1;
741                               duration = dot_clock;
742                               break;
743                     case '-':
744                               on = 1;
745                               duration = dot_clock * DASH_LEN;
746                               break;
747                     case ' ':
748                               on = 0;
749                               duration = word_clock * WORD_SPACE;
750                               break;
751                     default:
752                               on = 0;
753                               duration = 0;
754                     }
755                     if (on) {
756                               ioctl(line, TIOCMGET, &lflags);
757                               lflags |= TIOCM_RTS;
758                               ioctl(line, TIOCMSET, &lflags);
759                     }
760                     duration *= 1000000;
761                     if (duration)
762                               usleep(duration);
763                     ioctl(line, TIOCMGET, &lflags);
764                     lflags &= ~TIOCM_RTS;
765                     ioctl(line, TIOCMSET, &lflags);
766                     duration = dot_clock * 1000000;
767                     /* Only space within a symbol */
768                     if (c[1] != '\0' || prosign)
769                               usleep(duration);
770           }
771           if (!prosign) {
772                     duration = word_clock * CHAR_SPACE * 1000000;
773                     usleep(duration);
774           }
775 }
776 
777 static void
sighandler(int signo)778 sighandler(int signo)
779 {
780 
781           ioctl(line, TIOCMSET, &olflags);
782           tcsetattr(line, TCSANOW, &otty);
783 
784           signal(signo, SIG_DFL);
785           kill(getpid(), signo);
786 }
787