morse.c revision 129299
1249109Sjkim/*
2249109Sjkim * Copyright (c) 1988, 1993
3249109Sjkim *	The Regents of the University of California.  All rights reserved.
4249109Sjkim *
5249109Sjkim * Redistribution and use in source and binary forms, with or without
6249109Sjkim * modification, are permitted provided that the following conditions
7249109Sjkim * are met:
8306536Sjkim * 1. Redistributions of source code must retain the above copyright
9249109Sjkim *    notice, this list of conditions and the following disclaimer.
10249109Sjkim * 2. Redistributions in binary form must reproduce the above copyright
11249109Sjkim *    notice, this list of conditions and the following disclaimer in the
12249109Sjkim *    documentation and/or other materials provided with the distribution.
13249109Sjkim * 3. All advertising materials mentioning features or use of this software
14249109Sjkim *    must display the following acknowledgement:
15249109Sjkim *	This product includes software developed by the University of
16249109Sjkim *	California, Berkeley and its contributors.
17249109Sjkim * 4. Neither the name of the University nor the names of its contributors
18249109Sjkim *    may be used to endorse or promote products derived from this software
19249109Sjkim *    without specific prior written permission.
20249109Sjkim *
21249109Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22249109Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23249109Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24249109Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25249109Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26249109Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27249109Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28249109Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29249109Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30249109Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31249109Sjkim * SUCH DAMAGE.
32249109Sjkim */
33249109Sjkim
34249109Sjkim/*
35249109Sjkim * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
36249109Sjkim * <lyndon@orthanc.com>
37249109Sjkim */
38249109Sjkim
39249109Sjkim#ifndef lint
40249109Sjkimstatic const char copyright[] =
41249109Sjkim"@(#) Copyright (c) 1988, 1993\n\
42249109Sjkim	The Regents of the University of California.  All rights reserved.\n";
43249109Sjkim#endif /* not lint */
44249112Sjkim
45249109Sjkim#ifndef lint
46249112Sjkim#if 0
47249112Sjkimstatic char sccsid[] = "@(#)morse.c	8.1 (Berkeley) 5/31/93";
48249109Sjkim#endif
49249109Sjkimstatic const char rcsid[] =
50249109Sjkim "$FreeBSD: head/games/morse/morse.c 129299 2004-05-16 21:49:23Z ru $";
51249109Sjkim#endif /* not lint */
52249109Sjkim
53249109Sjkim#include <sys/time.h>
54249109Sjkim
55249109Sjkim#include <ctype.h>
56249109Sjkim#include <fcntl.h>
57249109Sjkim#include <langinfo.h>
58249109Sjkim#include <locale.h>
59249109Sjkim#include <signal.h>
60253690Sjkim#include <stdio.h>
61249109Sjkim#include <stdlib.h>
62249109Sjkim#include <string.h>
63249109Sjkim#include <termios.h>
64253690Sjkim#include <unistd.h>
65253690Sjkim
66249109Sjkim#ifdef SPEAKER
67249109Sjkim#include <machine/speaker.h>
68249109Sjkim#endif
69249109Sjkim
70249109Sjkimstruct morsetab {
71249109Sjkim	char            inchar;
72249109Sjkim	char           *morse;
73249109Sjkim};
74249109Sjkim
75249109Sjkimstatic const struct morsetab mtab[] = {
76249109Sjkim
77249109Sjkim	/* letters */
78249109Sjkim
79249109Sjkim	{'a', ".-"},
80249109Sjkim	{'b', "-..."},
81250838Sjkim	{'c', "-.-."},
82250838Sjkim	{'d', "-.."},
83250838Sjkim	{'e', "."},
84249109Sjkim	{'f', "..-."},
85249109Sjkim	{'g', "--."},
86249109Sjkim	{'h', "...."},
87249109Sjkim	{'i', ".."},
88249109Sjkim	{'j', ".---"},
89249109Sjkim	{'k', "-.-"},
90249109Sjkim	{'l', ".-.."},
91249109Sjkim	{'m', "--"},
92249109Sjkim	{'n', "-."},
93249109Sjkim	{'o', "---"},
94249109Sjkim	{'p', ".--."},
95249109Sjkim	{'q', "--.-"},
96249109Sjkim	{'r', ".-."},
97249109Sjkim	{'s', "..."},
98249109Sjkim	{'t', "-"},
99253690Sjkim	{'u', "..-"},
100253690Sjkim	{'v', "...-"},
101250838Sjkim	{'w', ".--"},
102249109Sjkim	{'x', "-..-"},
103249109Sjkim	{'y', "-.--"},
104249109Sjkim	{'z', "--.."},
105249109Sjkim
106249109Sjkim	/* digits */
107249109Sjkim
108249109Sjkim	{'0', "-----"},
109249109Sjkim	{'1', ".----"},
110249109Sjkim	{'2', "..---"},
111249109Sjkim	{'3', "...--"},
112249109Sjkim	{'4', "....-"},
113249109Sjkim	{'5', "....."},
114249109Sjkim	{'6', "-...."},
115249109Sjkim	{'7', "--..."},
116249109Sjkim	{'8', "---.."},
117249109Sjkim	{'9', "----."},
118249109Sjkim
119249109Sjkim	/* punctuation */
120249109Sjkim
121249109Sjkim	{',', "--..--"},
122249109Sjkim	{'.', ".-.-.-"},
123249109Sjkim	{'"', ".-..-."},
124249109Sjkim	{'!', "..--."},
125253690Sjkim	{'?', "..--.."},
126253690Sjkim	{'/', "-..-."},
127253690Sjkim	{'-', "-....-"},
128250838Sjkim	{'=', "-...-"},		/* BT */
129250838Sjkim	{':', "---..."},
130249109Sjkim	{';', "-.-.-."},
131249109Sjkim	{'(', "-.--."},		/* KN */
132250838Sjkim	{')', "-.--.-"},
133250838Sjkim	{'$', "...-..-"},
134250838Sjkim	{'+', ".-.-."},		/* AR */
135249109Sjkim	{'@', ".--.-."},	/* AC */
136250838Sjkim
137250838Sjkim	/* prosigns without already assigned values */
138249109Sjkim
139249109Sjkim	{'#', ".-..."},		/* AS */
140249109Sjkim	{'&', "...-.-"},	/* SK */
141249109Sjkim	{'*', "...-."},		/* VE */
142249109Sjkim	{'%', "-...-.-"},	/* BK */
143249109Sjkim
144249109Sjkim	{'\0', ""}
145253690Sjkim};
146249109Sjkim
147249109Sjkim
148249109Sjkimstatic const struct morsetab iso8859_1tab[] = {
149249109Sjkim	{'�', ".--.-"},
150249109Sjkim	{'�', ".--.-"},
151253690Sjkim	{'�', ".--.-"},
152253690Sjkim	{'�', ".-.-"},
153253690Sjkim	{'�', "-.-.."},
154253690Sjkim	{'�', "..-.."},
155253690Sjkim	{'�', "..-.."},
156253690Sjkim	{'�', "-..-."},
157253690Sjkim	{'�', "---."},
158253690Sjkim	{'�', "..--"},
159249109Sjkim
160249109Sjkim	{'\0', ""}
161249109Sjkim};
162249109Sjkim
163249109Sjkimstatic const struct morsetab iso8859_7tab[] = {
164249109Sjkim	/*
165249109Sjkim	 * The greek alphabet; you'll need an 8859-7 font in order
166249109Sjkim	 * to see the actual characters.
167249109Sjkim	 * This table does not implement:
168249109Sjkim	 * - the special sequences for the seven diphthongs,
169250838Sjkim	 * - the punctuation differences.
170249109Sjkim	 * Implementing these features would introduce too many
171253690Sjkim	 * special-cases in the program's main loop.
172250838Sjkim	 * The diphtong sequences are:
173253690Sjkim	 * alpha iota		.-.-
174249109Sjkim	 * alpha upsilon	..--
175249109Sjkim	 * epsilon upsilon	---.
176253690Sjkim	 * eta upsilon		...-
177253690Sjkim	 * omikron iota		---..
178253690Sjkim	 * omikron upsilon	..-
179253690Sjkim	 * upsilon iota		.---
180253690Sjkim	 * The different punctuation symbols are:
181253690Sjkim	 * ;	..-.-
182253690Sjkim	 * !	--..--
183253690Sjkim	 */
184253690Sjkim	{'�', ".-"},	/* alpha */
185253690Sjkim	{'�', ".-"},	/* alpha with acute */
186253690Sjkim	{'�', "-..."},	/* beta */
187250838Sjkim	{'�', "--."},	/* gamma */
188250838Sjkim	{'�', "-.."},	/* delta */
189250838Sjkim	{'�', "."},	/* epsilon */
190253690Sjkim	{'�', "."},	/* epsilon with acute */
191253690Sjkim	{'�', "--.."},	/* zeta */
192250838Sjkim	{'�', "...."},	/* eta */
193250838Sjkim	{'�', "...."},	/* eta with acute */
194253690Sjkim	{'�', "-.-."},	/* theta */
195253690Sjkim	{'�', ".."},	/* iota */
196253690Sjkim	{'�', ".."},	/* iota with acute */
197249109Sjkim	{'�', ".."},	/* iota with diairesis */
198250838Sjkim	{'�', ".."},	/* iota with acute and diairesis */
199250838Sjkim	{'�', "-.-"},	/* kappa */
200250838Sjkim	{'�', ".-.."},	/* lamda */
201249109Sjkim	{'�', "--"},	/* mu */
202249109Sjkim	{'�', "-."},	/* nu */
203249109Sjkim	{'�', "-..-"},	/* xi */
204249109Sjkim	{'�', "---"},	/* omicron */
205249109Sjkim	{'�', "---"},	/* omicron with acute */
206250838Sjkim	{'�', ".--."},	/* pi */
207249109Sjkim	{'�', ".-."},	/* rho */
208250838Sjkim	{'�', "..."},	/* sigma */
209250838Sjkim	{'�', "..."},	/* final sigma */
210249109Sjkim	{'�', "-"},	/* tau */
211249109Sjkim	{'�', "-.--"},	/* upsilon */
212249109Sjkim	{'�', "-.--"},	/* upsilon with acute */
213249109Sjkim	{'�', "-.--"},	/* upsilon and diairesis */
214250838Sjkim	{'�', "-.--"},	/* upsilon with acute and diairesis */
215249109Sjkim	{'�', "..-."},	/* phi */
216253690Sjkim	{'�', "----"},	/* chi */
217253690Sjkim	{'�', "--.-"},	/* psi */
218253690Sjkim	{'�', ".--"},	/* omega */
219253690Sjkim	{'�', ".--"},	/* omega with acute */
220253690Sjkim
221253690Sjkim	{'\0', ""}
222253690Sjkim};
223253690Sjkim
224249109Sjkimstatic const struct morsetab koi8rtab[] = {
225249109Sjkim	/*
226250838Sjkim	 * the cyrillic alphabet; you'll need a KOI8R font in order
227250838Sjkim	 * to see the actual characters
228249109Sjkim	 */
229250838Sjkim	{'�', ".-"},		/* a */
230249109Sjkim	{'�', "-..."},	/* be */
231249109Sjkim	{'�', ".--"},	/* ve */
232249109Sjkim	{'�', "--."},	/* ge */
233249109Sjkim	{'�', "-.."},	/* de */
234249109Sjkim	{'�', "."},		/* ye */
235249109Sjkim	{'�', "."},         	/* yo, the same as ye */
236249109Sjkim	{'�', "...-"},	/* she */
237249109Sjkim	{'�', "--.."},	/* ze */
238249109Sjkim	{'�', ".."},		/* i */
239249109Sjkim	{'�', ".---"},	/* i kratkoye */
240249109Sjkim	{'�', "-.-"},	/* ka */
241253690Sjkim	{'�', ".-.."},	/* el */
242250838Sjkim	{'�', "--"},		/* em */
243253690Sjkim	{'�', "-."},		/* en */
244249109Sjkim	{'�', "---"},	/* o */
245249109Sjkim	{'�', ".--."},	/* pe */
246249109Sjkim	{'�', ".-."},	/* er */
247249109Sjkim	{'�', "..."},	/* es */
248249109Sjkim	{'�', "-"},		/* te */
249249109Sjkim	{'�', "..-"},	/* u */
250249109Sjkim	{'�', "..-."},	/* ef */
251250838Sjkim	{'�', "...."},	/* kha */
252250838Sjkim	{'�', "-.-."},	/* ce */
253250838Sjkim	{'�', "---."},	/* che */
254250838Sjkim	{'�', "----"},	/* sha */
255250838Sjkim	{'�', "--.-"},	/* shcha */
256250838Sjkim	{'�', "-.--"},	/* yi */
257250838Sjkim	{'�', "-..-"},	/* myakhkij znak */
258250838Sjkim	{'�', "..-.."},	/* ae */
259250838Sjkim	{'�', "..--"},	/* yu */
260250838Sjkim	{'�', ".-.-"},	/* ya */
261250838Sjkim
262250838Sjkim	{'\0', ""}
263253690Sjkim};
264250838Sjkim
265253690Sjkimvoid            show(const char *), play(const char *), morse(char);
266253690Sjkimvoid		ttyout(const char *);
267250838Sjkimvoid		sighandler(int);
268253690Sjkim
269253690Sjkim#define GETOPTOPTS "d:ef:lsw:"
270253690Sjkim#define USAGE \
271253690Sjkim"usage: morse [-els] [-d device] [-w speed] [-f frequency] [string ...]\n"
272253690Sjkim
273253690Sjkimstatic int      pflag, lflag, sflag, eflag;
274253690Sjkimstatic int      wpm = 20;	/* words per minute */
275253690Sjkim#define FREQUENCY 600
276253690Sjkimstatic int      freq = FREQUENCY;
277253690Sjkimstatic char	*device;	/* for tty-controlled generator */
278250838Sjkim
279250838Sjkim#define DASH_LEN 3
280253690Sjkim#define CHAR_SPACE 3
281253690Sjkim#define WORD_SPACE (7 - CHAR_SPACE - 1)
282253690Sjkimstatic float    dot_clock;
283253690Sjkimint             spkr, line;
284253690Sjkimstruct termios	otty, ntty;
285253690Sjkimint		olflags;
286253690Sjkim
287253690Sjkim#ifdef SPEAKER
288253690Sjkimtone_t          sound;
289253690Sjkim#undef GETOPTOPTS
290253690Sjkim#define GETOPTOPTS "d:ef:lpsw:"
291253690Sjkim#undef USAGE
292253690Sjkim#define USAGE \
293253690Sjkim"usage: morse [-elps] [-d device] [-w speed] [-f frequency] [string ...]\n"
294253690Sjkim#endif
295253690Sjkim
296253690Sjkimstatic const struct morsetab *hightab;
297253690Sjkim
298253690Sjkimint
299253690Sjkimmain(int argc, char **argv)
300253690Sjkim{
301253690Sjkim	int    ch, lflags;
302253690Sjkim	char  *p, *codeset;
303253690Sjkim
304253690Sjkim	while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
305253690Sjkim		switch ((char) ch) {
306253690Sjkim		case 'd':
307253690Sjkim			device = optarg;
308253690Sjkim			break;
309253690Sjkim		case 'e':
310253690Sjkim			eflag = 1;
311253690Sjkim			setvbuf(stdout, 0, _IONBF, 0);
312253690Sjkim			break;
313253690Sjkim		case 'f':
314253690Sjkim			freq = atoi(optarg);
315253690Sjkim			break;
316253690Sjkim		case 'l':
317253690Sjkim			lflag = 1;
318253690Sjkim			break;
319253690Sjkim#ifdef SPEAKER
320253690Sjkim		case 'p':
321250838Sjkim			pflag = 1;
322250838Sjkim			break;
323249109Sjkim#endif
324249109Sjkim		case 's':
325249109Sjkim			sflag = 1;
326249109Sjkim			break;
327249109Sjkim		case 'w':
328249109Sjkim			wpm = atoi(optarg);
329249109Sjkim			break;
330249109Sjkim		case '?':
331249109Sjkim		default:
332249109Sjkim			fputs(USAGE, stderr);
333249109Sjkim			exit(1);
334249109Sjkim		}
335249109Sjkim	if (sflag && lflag) {
336249109Sjkim		fputs("morse: only one of -l and -s allowed\n", stderr);
337249109Sjkim		exit(1);
338249109Sjkim	}
339249109Sjkim	if ((pflag || device) && (sflag || lflag)) {
340253690Sjkim		fputs("morse: only one of -p, -d and -l, -s allowed\n", stderr);
341249109Sjkim		exit(1);
342249109Sjkim	}
343249109Sjkim	if ((pflag || device) && ((wpm < 1) || (wpm > 60))) {
344249109Sjkim		fputs("morse: insane speed\n", stderr);
345249109Sjkim		exit(1);
346249109Sjkim	}
347249109Sjkim	if ((pflag || device) && (freq == 0))
348249109Sjkim		freq = FREQUENCY;
349249109Sjkim
350249109Sjkim#ifdef SPEAKER
351249109Sjkim	if (pflag) {
352253690Sjkim		if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
353249109Sjkim			perror(SPEAKER);
354249109Sjkim			exit(1);
355249109Sjkim		}
356253690Sjkim	} else
357253690Sjkim#endif
358249109Sjkim	if (device) {
359249109Sjkim		if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
360249109Sjkim			perror("open tty line");
361249109Sjkim			exit(1);
362249109Sjkim		}
363249109Sjkim		if (tcgetattr(line, &otty) == -1) {
364249109Sjkim			perror("tcgetattr() failed");
365249109Sjkim			exit(1);
366306536Sjkim		}
367249109Sjkim		ntty = otty;
368249109Sjkim		ntty.c_cflag |= CLOCAL;
369249109Sjkim		tcsetattr(line, TCSANOW, &ntty);
370249109Sjkim		lflags = fcntl(line, F_GETFL);
371249109Sjkim		lflags &= ~O_NONBLOCK;
372249109Sjkim		fcntl(line, F_SETFL, &lflags);
373249109Sjkim		ioctl(line, TIOCMGET, &lflags);
374249109Sjkim		lflags &= ~TIOCM_RTS;
375249109Sjkim		olflags = lflags;
376249109Sjkim		ioctl(line, TIOCMSET, &lflags);
377249109Sjkim		(void)signal(SIGHUP, sighandler);
378249109Sjkim		(void)signal(SIGINT, sighandler);
379249109Sjkim		(void)signal(SIGQUIT, sighandler);
380249109Sjkim		(void)signal(SIGTERM, sighandler);
381249109Sjkim	}
382249109Sjkim	if (pflag || device) {
383249109Sjkim		dot_clock = wpm / 2.4;		/* dots/sec */
384253690Sjkim		dot_clock = 1 / dot_clock;	/* duration of a dot */
385253690Sjkim		dot_clock = dot_clock / 2;	/* dot_clock runs at twice */
386253690Sjkim						/* the dot rate */
387249109Sjkim		dot_clock = dot_clock * 100;	/* scale for ioctl */
388249109Sjkim	}
389249109Sjkim
390249109Sjkim	argc -= optind;
391249109Sjkim	argv += optind;
392249109Sjkim
393249109Sjkim	if (setlocale(LC_CTYPE, "") != NULL &&
394249109Sjkim	    *(codeset = nl_langinfo(CODESET)) != '\0') {
395249109Sjkim		if (strcmp(codeset, "KOI8-R") == 0)
396249109Sjkim			hightab = koi8rtab;
397249109Sjkim		else if (strcmp(codeset, "ISO8859-1") == 0 ||
398249109Sjkim			 strcmp(codeset, "ISO8859-15") == 0)
399249109Sjkim			hightab = iso8859_1tab;
400249109Sjkim		else if (strcmp(codeset, "ISO8859-7") == 0)
401249109Sjkim			hightab = iso8859_7tab;
402249109Sjkim	}
403249109Sjkim
404249109Sjkim	if (lflag)
405249109Sjkim		printf("m");
406249109Sjkim	if (*argv) {
407249109Sjkim		do {
408249109Sjkim			for (p = *argv; *p; ++p) {
409249109Sjkim				if (eflag)
410249109Sjkim					putchar(*p);
411249109Sjkim				morse(*p);
412253690Sjkim			}
413253690Sjkim			if (eflag)
414253690Sjkim				putchar(' ');
415253690Sjkim			morse(' ');
416253690Sjkim		} while (*++argv);
417253690Sjkim	} else {
418249109Sjkim		while ((ch = getchar()) != EOF) {
419249109Sjkim			if (eflag)
420249109Sjkim				putchar(ch);
421249109Sjkim			morse(ch);
422249109Sjkim		}
423249109Sjkim	}
424250838Sjkim	if (device)
425253690Sjkim		tcsetattr(line, TCSANOW, &otty);
426250838Sjkim	exit(0);
427250838Sjkim}
428253690Sjkim
429253690Sjkimvoid
430250838Sjkimmorse(char c)
431250838Sjkim{
432250838Sjkim	const struct morsetab *m;
433250838Sjkim
434253690Sjkim	if (isalpha((unsigned char)c))
435250838Sjkim		c = tolower((unsigned char)c);
436253690Sjkim	if ((c == '\r') || (c == '\n'))
437250838Sjkim		c = ' ';
438250838Sjkim	if (c == ' ') {
439250838Sjkim		if (pflag)
440253690Sjkim			play(" ");
441250838Sjkim		else if (device)
442250838Sjkim			ttyout(" ");
443250838Sjkim		else if (lflag)
444253690Sjkim			printf("\n");
445253690Sjkim		else
446250838Sjkim			show("");
447253690Sjkim		return;
448253690Sjkim	}
449253690Sjkim	for (m = ((unsigned char)c < 0x80? mtab: hightab);
450250838Sjkim	     m != NULL && m->inchar != '\0';
451253690Sjkim	     m++) {
452250838Sjkim		if (m->inchar == c) {
453253690Sjkim			if (pflag) {
454253690Sjkim				play(m->morse);
455253690Sjkim			} else if (device) {
456250838Sjkim				ttyout(m->morse);
457250838Sjkim			} else
458250838Sjkim				show(m->morse);
459249109Sjkim		}
460249109Sjkim	}
461249109Sjkim}
462249109Sjkim
463249109Sjkimvoid
464249109Sjkimshow(const char *s)
465249109Sjkim{
466249109Sjkim	if (lflag) {
467249109Sjkim		printf("%s ", s);
468249109Sjkim	} else if (sflag) {
469249109Sjkim		printf(" %s\n", s);
470253690Sjkim	} else {
471249109Sjkim		for (; *s; ++s)
472249109Sjkim			printf(" %s", *s == '.' ? "dit" : "dah");
473		printf("\n");
474	}
475}
476
477void
478play(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
519void
520ttyout(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
561void
562sighandler(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}
571