route: ensure RTM_IFINFO is sent first when bring interface down/up
[dragonfly.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. 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
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
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
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
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
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
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
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
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 }