12490Sjkh/*
22490Sjkh * Copyright (c) 1988, 1993
32490Sjkh *	The Regents of the University of California.  All rights reserved.
42490Sjkh *
52490Sjkh * Redistribution and use in source and binary forms, with or without
62490Sjkh * modification, are permitted provided that the following conditions
72490Sjkh * are met:
82490Sjkh * 1. Redistributions of source code must retain the above copyright
92490Sjkh *    notice, this list of conditions and the following disclaimer.
102490Sjkh * 2. Redistributions in binary form must reproduce the above copyright
112490Sjkh *    notice, this list of conditions and the following disclaimer in the
122490Sjkh *    documentation and/or other materials provided with the distribution.
13203932Simp * 3. Neither the name of the University nor the names of its contributors
142490Sjkh *    may be used to endorse or promote products derived from this software
152490Sjkh *    without specific prior written permission.
162490Sjkh *
172490Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
182490Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
192490Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
202490Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
212490Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
222490Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
232490Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
242490Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
252490Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
262490Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
272490Sjkh * SUCH DAMAGE.
282490Sjkh */
292490Sjkh
3010352Sjoerg/*
31179654Sscf * Taught to send *real* morse by Lyndon Nerenberg (VE6BBM)
32179654Sscf * <lyndon@orthanc.ca>
3310352Sjoerg */
3410352Sjoerg
352490Sjkh#ifndef lint
3653920Sbillfstatic const char copyright[] =
372490Sjkh"@(#) Copyright (c) 1988, 1993\n\
382490Sjkh	The Regents of the University of California.  All rights reserved.\n";
392490Sjkh#endif /* not lint */
402490Sjkh
412490Sjkh#ifndef lint
4253920Sbillf#if 0
432490Sjkhstatic char sccsid[] = "@(#)morse.c	8.1 (Berkeley) 5/31/93";
4453920Sbillf#endif
4553920Sbillfstatic const char rcsid[] =
4653920Sbillf "$FreeBSD$";
472490Sjkh#endif /* not lint */
482490Sjkh
4957527Sjoerg#include <sys/time.h>
5057527Sjoerg
512490Sjkh#include <ctype.h>
5257527Sjoerg#include <fcntl.h>
5378793Sache#include <langinfo.h>
5410352Sjoerg#include <locale.h>
5557527Sjoerg#include <signal.h>
5657527Sjoerg#include <stdio.h>
5710352Sjoerg#include <stdlib.h>
5835857Sjb#include <string.h>
5957527Sjoerg#include <termios.h>
6054622Sbillf#include <unistd.h>
612490Sjkh
62203479Simp/* Always use the speaker, let the open fail if -p is selected */
63203479Simp#define SPEAKER "/dev/speaker"
64203479Simp
6510352Sjoerg#ifdef SPEAKER
66152306Sru#include <dev/speaker/speaker.h>
6710352Sjoerg#endif
6810352Sjoerg
6910352Sjoergstruct morsetab {
70203921Suqs	const char      inchar;
71203921Suqs	const char     *morse;
722490Sjkh};
732490Sjkh
7454622Sbillfstatic const struct morsetab mtab[] = {
752490Sjkh
7610352Sjoerg	/* letters */
7710352Sjoerg
7854622Sbillf	{'a', ".-"},
7954622Sbillf	{'b', "-..."},
8054622Sbillf	{'c', "-.-."},
8154622Sbillf	{'d', "-.."},
8254622Sbillf	{'e', "."},
8354622Sbillf	{'f', "..-."},
8454622Sbillf	{'g', "--."},
8554622Sbillf	{'h', "...."},
8654622Sbillf	{'i', ".."},
8754622Sbillf	{'j', ".---"},
8854622Sbillf	{'k', "-.-"},
8954622Sbillf	{'l', ".-.."},
9054622Sbillf	{'m', "--"},
9154622Sbillf	{'n', "-."},
9254622Sbillf	{'o', "---"},
9354622Sbillf	{'p', ".--."},
9454622Sbillf	{'q', "--.-"},
9554622Sbillf	{'r', ".-."},
9654622Sbillf	{'s', "..."},
9754622Sbillf	{'t', "-"},
9854622Sbillf	{'u', "..-"},
9954622Sbillf	{'v', "...-"},
10054622Sbillf	{'w', ".--"},
10154622Sbillf	{'x', "-..-"},
10254622Sbillf	{'y', "-.--"},
10354622Sbillf	{'z', "--.."},
10410352Sjoerg
10510352Sjoerg	/* digits */
10610352Sjoerg
10754622Sbillf	{'0', "-----"},
10854622Sbillf	{'1', ".----"},
10954622Sbillf	{'2', "..---"},
11054622Sbillf	{'3', "...--"},
11154622Sbillf	{'4', "....-"},
11254622Sbillf	{'5', "....."},
11354622Sbillf	{'6', "-...."},
11454622Sbillf	{'7', "--..."},
11554622Sbillf	{'8', "---.."},
11654622Sbillf	{'9', "----."},
11710352Sjoerg
11810352Sjoerg	/* punctuation */
11910352Sjoerg
12054622Sbillf	{',', "--..--"},
12154622Sbillf	{'.', ".-.-.-"},
122126040Sfanf	{'"', ".-..-."},
123126040Sfanf	{'!', "..--."},
12454622Sbillf	{'?', "..--.."},
12554622Sbillf	{'/', "-..-."},
12654622Sbillf	{'-', "-....-"},
12754622Sbillf	{'=', "-...-"},		/* BT */
12854622Sbillf	{':', "---..."},
12954622Sbillf	{';', "-.-.-."},
13054622Sbillf	{'(', "-.--."},		/* KN */
13154622Sbillf	{')', "-.--.-"},
13254622Sbillf	{'$', "...-..-"},
13354622Sbillf	{'+', ".-.-."},		/* AR */
134126044Sfanf	{'@', ".--.-."},	/* AC */
13510352Sjoerg
13610352Sjoerg	/* prosigns without already assigned values */
13710352Sjoerg
13854622Sbillf	{'#', ".-..."},		/* AS */
139126040Sfanf	{'&', "...-.-"},	/* SK */
14054622Sbillf	{'*', "...-."},		/* VE */
14154622Sbillf	{'%', "-...-.-"},	/* BK */
14210352Sjoerg
14354622Sbillf	{'\0', ""}
14410352Sjoerg};
14510352Sjoerg
146235618Sdim/*
147235618Sdim * Code-points for some Latin1 chars in ISO-8859-1 encoding.
148235618Sdim * UTF-8 encoded chars in the comments.
149235618Sdim */
150129114Sddsstatic const struct morsetab iso8859_1tab[] = {
151235618Sdim	{'\340', ".--.-"},	/* �� */
152235618Sdim	{'\341', ".--.-"},	/* �� */
153235618Sdim	{'\342', ".--.-"},	/* �� */
154235618Sdim	{'\344', ".-.-"},	/* �� */
155235618Sdim	{'\347', "-.-.."},	/* �� */
156235618Sdim	{'\350', "..-.."},	/* �� */
157235618Sdim	{'\351', "..-.."},	/* �� */
158235618Sdim	{'\352', "-..-."},	/* �� */
159235618Sdim	{'\366', "---."},	/* �� */
160235618Sdim	{'\374', "..--"},	/* �� */
16110352Sjoerg
16254622Sbillf	{'\0', ""}
16310352Sjoerg};
16410352Sjoerg
165235618Sdim/*
166235618Sdim * Code-points for some Greek chars in ISO-8859-7 encoding.
167235618Sdim * UTF-8 encoded chars in the comments.
168235618Sdim */
169129114Sddsstatic const struct morsetab iso8859_7tab[] = {
170129114Sdds	/*
171129114Sdds	 * This table does not implement:
172129114Sdds	 * - the special sequences for the seven diphthongs,
173129114Sdds	 * - the punctuation differences.
174129114Sdds	 * Implementing these features would introduce too many
175129114Sdds	 * special-cases in the program's main loop.
176221907Suqs	 * The diphthong sequences are:
177129114Sdds	 * alpha iota		.-.-
178129114Sdds	 * alpha upsilon	..--
179129114Sdds	 * epsilon upsilon	---.
180129114Sdds	 * eta upsilon		...-
181221907Suqs	 * omicron iota		---..
182221907Suqs	 * omicron upsilon	..-
183129114Sdds	 * upsilon iota		.---
184129114Sdds	 * The different punctuation symbols are:
185129114Sdds	 * ;	..-.-
186129114Sdds	 * !	--..--
187129114Sdds	 */
188235618Sdim	{'\341', ".-"},		/* ��, alpha */
189235618Sdim	{'\334', ".-"},		/* ��, alpha with acute */
190235618Sdim	{'\342', "-..."},	/* ��, beta */
191235618Sdim	{'\343', "--."},	/* ��, gamma */
192235618Sdim	{'\344', "-.."},	/* ��, delta */
193235618Sdim	{'\345', "."},		/* ��, epsilon */
194235618Sdim	{'\335', "."},		/* ��, epsilon with acute */
195235618Sdim	{'\346', "--.."},	/* ��, zeta */
196235618Sdim	{'\347', "...."},	/* ��, eta */
197235618Sdim	{'\336', "...."},	/* ��, eta with acute */
198235618Sdim	{'\350', "-.-."},	/* ��, theta */
199235618Sdim	{'\351', ".."},		/* ��, iota */
200235618Sdim	{'\337', ".."},		/* ��, iota with acute */
201235618Sdim	{'\372', ".."},		/* ��, iota with diaeresis */
202235618Sdim	{'\300', ".."},		/* ��, iota with acute and diaeresis */
203235618Sdim	{'\352', "-.-"},	/* ��, kappa */
204235618Sdim	{'\353', ".-.."},	/* ��, lambda */
205235618Sdim	{'\354', "--"},		/* ��, mu */
206235618Sdim	{'\355', "-."},		/* ��, nu */
207235618Sdim	{'\356', "-..-"},	/* ��, xi */
208235618Sdim	{'\357', "---"},	/* ��, omicron */
209235618Sdim	{'\374', "---"},	/* ��, omicron with acute */
210235618Sdim	{'\360', ".--."},	/* ��, pi */
211235618Sdim	{'\361', ".-."},	/* ��, rho */
212235618Sdim	{'\363', "..."},	/* ��, sigma */
213235618Sdim	{'\362', "..."},	/* ��, final sigma */
214235618Sdim	{'\364', "-"},		/* ��, tau */
215235618Sdim	{'\365', "-.--"},	/* ��, upsilon */
216235618Sdim	{'\375', "-.--"},	/* ��, upsilon with acute */
217235618Sdim	{'\373', "-.--"},	/* ��, upsilon and diaeresis */
218235618Sdim	{'\340', "-.--"},	/* ��, upsilon with acute and diaeresis */
219235618Sdim	{'\366', "..-."},	/* ��, phi */
220235618Sdim	{'\367', "----"},	/* ��, chi */
221235618Sdim	{'\370', "--.-"},	/* ��, psi */
222235618Sdim	{'\371', ".--"},	/* ��, omega */
223235618Sdim	{'\376', ".--"},	/* ��, omega with acute */
224129114Sdds
225129114Sdds	{'\0', ""}
226129114Sdds};
227129114Sdds
228235618Sdim/*
229235618Sdim * Code-points for the Cyrillic alphabet in KOI8-R encoding.
230235618Sdim * UTF-8 encoded chars in the comments.
231235618Sdim */
23254622Sbillfstatic const struct morsetab koi8rtab[] = {
233235618Sdim	{'\301', ".-"},		/* ��, a */
234235618Sdim	{'\302', "-..."},	/* ��, be */
235235618Sdim	{'\327', ".--"},	/* ��, ve */
236235618Sdim	{'\307', "--."},	/* ��, ge */
237235618Sdim	{'\304', "-.."},	/* ��, de */
238235618Sdim	{'\305', "."},		/* ��, ye */
239235618Sdim	{'\243', "."},		/* ��, yo, the same as ye */
240235618Sdim	{'\326', "...-"},	/* ��, she */
241235618Sdim	{'\332', "--.."},	/* ��, ze */
242235618Sdim	{'\311', ".."},		/* ��, i */
243235618Sdim	{'\312', ".---"},	/* ��, i kratkoye */
244235618Sdim	{'\313', "-.-"},	/* ��, ka */
245235618Sdim	{'\314', ".-.."},	/* ��, el */
246235618Sdim	{'\315', "--"},		/* ��, em */
247235618Sdim	{'\316', "-."},		/* ��, en */
248235618Sdim	{'\317', "---"},	/* ��, o */
249235618Sdim	{'\320', ".--."},	/* ��, pe */
250235618Sdim	{'\322', ".-."},	/* ��, er */
251235618Sdim	{'\323', "..."},	/* ��, es */
252235618Sdim	{'\324', "-"},		/* ��, te */
253235618Sdim	{'\325', "..-"},	/* ��, u */
254235618Sdim	{'\306', "..-."},	/* ��, ef */
255235618Sdim	{'\310', "...."},	/* ��, kha */
256235618Sdim	{'\303', "-.-."},	/* ��, ce */
257235618Sdim	{'\336', "---."},	/* ��, che */
258235618Sdim	{'\333', "----"},	/* ��, sha */
259235618Sdim	{'\335', "--.-"},	/* ��, shcha */
260235618Sdim	{'\331', "-.--"},	/* ��, yi */
261235618Sdim	{'\330', "-..-"},	/* ��, myakhkij znak */
262235618Sdim	{'\334', "..-.."},	/* ��, ae */
263235618Sdim	{'\300', "..--"},	/* ��, yu */
264235618Sdim	{'\321', ".-.-"},	/* ��, ya */
26510352Sjoerg
26654622Sbillf	{'\0', ""}
26710352Sjoerg};
26810352Sjoerg
269249840Seadlerstatic void	show(const char *), play(const char *), morse(char);
270249840Seadlerstatic void	ttyout(const char *);
271249840Seadlerstatic void	sighandler(int);
27210352Sjoerg
273147110Sjoerg#define GETOPTOPTS "c:d:ef:lsw:"
27457527Sjoerg#define USAGE \
275147110Sjoerg"usage: morse [-els] [-d device] [-w speed] [-c speed] [-f frequency] [string ...]\n"
27657527Sjoerg
277249840Seadlerstatic int	pflag, lflag, sflag, eflag;
278249840Seadlerstatic int	wpm = 20;	/* effective words per minute */
279249840Seadlerstatic int	cpm;		/* effective words per minute between
280147110Sjoerg				 * characters */
28110352Sjoerg#define FREQUENCY 600
282249840Seadlerstatic int	freq = FREQUENCY;
28357527Sjoergstatic char	*device;	/* for tty-controlled generator */
28410352Sjoerg
28510352Sjoerg#define DASH_LEN 3
28610352Sjoerg#define CHAR_SPACE 3
28710352Sjoerg#define WORD_SPACE (7 - CHAR_SPACE - 1)
288249840Seadlerstatic float	dot_clock;
289249840Seadlerstatic float	cdot_clock;
290249840Seadlerstatic int	spkr, line;
291249840Seadlerstatic struct termios otty, ntty;
292249840Seadlerstatic int	olflags;
29357527Sjoerg
29457527Sjoerg#ifdef SPEAKER
295249840Seadlerstatic tone_t	sound;
29657527Sjoerg#undef GETOPTOPTS
297147110Sjoerg#define GETOPTOPTS "c:d:ef:lpsw:"
29857527Sjoerg#undef USAGE
29957527Sjoerg#define USAGE \
300147110Sjoerg"usage: morse [-elps] [-d device] [-w speed] [-c speed] [-f frequency] [string ...]\n"
30110352Sjoerg#endif
30210352Sjoerg
30378793Sachestatic const struct morsetab *hightab;
30410352Sjoerg
30510352Sjoergint
30610352Sjoergmain(int argc, char **argv)
3072490Sjkh{
30857527Sjoerg	int    ch, lflags;
30978793Sache	char  *p, *codeset;
3102490Sjkh
31157527Sjoerg	while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
31210352Sjoerg		switch ((char) ch) {
313221907Suqs		case 'c':
314221907Suqs			cpm = atoi(optarg);
315221907Suqs			break;
31657527Sjoerg		case 'd':
31757527Sjoerg			device = optarg;
31857527Sjoerg			break;
31957527Sjoerg		case 'e':
32057527Sjoerg			eflag = 1;
32157527Sjoerg			setvbuf(stdout, 0, _IONBF, 0);
32257527Sjoerg			break;
32310352Sjoerg		case 'f':
32410352Sjoerg			freq = atoi(optarg);
32510352Sjoerg			break;
326121945Sphk		case 'l':
327121945Sphk			lflag = 1;
328121945Sphk			break;
32957527Sjoerg#ifdef SPEAKER
33010352Sjoerg		case 'p':
33110352Sjoerg			pflag = 1;
33210352Sjoerg			break;
33357527Sjoerg#endif
3342490Sjkh		case 's':
3352490Sjkh			sflag = 1;
3362490Sjkh			break;
33710352Sjoerg		case 'w':
33810352Sjoerg			wpm = atoi(optarg);
33910352Sjoerg			break;
3402490Sjkh		case '?':
3412490Sjkh		default:
34257527Sjoerg			fputs(USAGE, stderr);
3432490Sjkh			exit(1);
3442490Sjkh		}
345121945Sphk	if (sflag && lflag) {
346121945Sphk		fputs("morse: only one of -l and -s allowed\n", stderr);
34710352Sjoerg		exit(1);
34810352Sjoerg	}
349121945Sphk	if ((pflag || device) && (sflag || lflag)) {
350121945Sphk		fputs("morse: only one of -p, -d and -l, -s allowed\n", stderr);
351121945Sphk		exit(1);
352121945Sphk	}
353147110Sjoerg	if (cpm == 0)
354147110Sjoerg		cpm = wpm;
355147110Sjoerg	if ((pflag || device) && ((wpm < 1) || (wpm > 60) || (cpm < 1) || (cpm > 60))) {
35610352Sjoerg		fputs("morse: insane speed\n", stderr);
35710352Sjoerg		exit(1);
35810352Sjoerg	}
35957527Sjoerg	if ((pflag || device) && (freq == 0))
36010352Sjoerg		freq = FREQUENCY;
36110352Sjoerg
36210352Sjoerg#ifdef SPEAKER
36310352Sjoerg	if (pflag) {
36410352Sjoerg		if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
36510352Sjoerg			perror(SPEAKER);
36610352Sjoerg			exit(1);
36710352Sjoerg		}
36857527Sjoerg	} else
36957527Sjoerg#endif
37057527Sjoerg	if (device) {
37157527Sjoerg		if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
37257527Sjoerg			perror("open tty line");
37357527Sjoerg			exit(1);
37457527Sjoerg		}
37557527Sjoerg		if (tcgetattr(line, &otty) == -1) {
37657527Sjoerg			perror("tcgetattr() failed");
37757527Sjoerg			exit(1);
37857527Sjoerg		}
37957527Sjoerg		ntty = otty;
38057527Sjoerg		ntty.c_cflag |= CLOCAL;
38157527Sjoerg		tcsetattr(line, TCSANOW, &ntty);
38257527Sjoerg		lflags = fcntl(line, F_GETFL);
38357527Sjoerg		lflags &= ~O_NONBLOCK;
38457527Sjoerg		fcntl(line, F_SETFL, &lflags);
38557527Sjoerg		ioctl(line, TIOCMGET, &lflags);
38657527Sjoerg		lflags &= ~TIOCM_RTS;
38757527Sjoerg		olflags = lflags;
38857527Sjoerg		ioctl(line, TIOCMSET, &lflags);
38957527Sjoerg		(void)signal(SIGHUP, sighandler);
39057527Sjoerg		(void)signal(SIGINT, sighandler);
39157527Sjoerg		(void)signal(SIGQUIT, sighandler);
39257527Sjoerg		(void)signal(SIGTERM, sighandler);
39357527Sjoerg	}
39457527Sjoerg	if (pflag || device) {
39510352Sjoerg		dot_clock = wpm / 2.4;		/* dots/sec */
39610352Sjoerg		dot_clock = 1 / dot_clock;	/* duration of a dot */
39710352Sjoerg		dot_clock = dot_clock / 2;	/* dot_clock runs at twice */
39810352Sjoerg						/* the dot rate */
39910352Sjoerg		dot_clock = dot_clock * 100;	/* scale for ioctl */
400147110Sjoerg
401147110Sjoerg		cdot_clock = cpm / 2.4;		/* dots/sec */
402147110Sjoerg		cdot_clock = 1 / cdot_clock;	/* duration of a dot */
403147110Sjoerg		cdot_clock = cdot_clock / 2;	/* dot_clock runs at twice */
404147110Sjoerg						/* the dot rate */
405147110Sjoerg		cdot_clock = cdot_clock * 100;	/* scale for ioctl */
40610352Sjoerg	}
40757527Sjoerg
4082490Sjkh	argc -= optind;
4092490Sjkh	argv += optind;
4102490Sjkh
41178793Sache	if (setlocale(LC_CTYPE, "") != NULL &&
41278793Sache	    *(codeset = nl_langinfo(CODESET)) != '\0') {
41378793Sache		if (strcmp(codeset, "KOI8-R") == 0)
41410352Sjoerg			hightab = koi8rtab;
41578793Sache		else if (strcmp(codeset, "ISO8859-1") == 0 ||
41678793Sache			 strcmp(codeset, "ISO8859-15") == 0)
417129114Sdds			hightab = iso8859_1tab;
418129114Sdds		else if (strcmp(codeset, "ISO8859-7") == 0)
419129114Sdds			hightab = iso8859_7tab;
42010352Sjoerg	}
42110352Sjoerg
422121945Sphk	if (lflag)
423121945Sphk		printf("m");
42410352Sjoerg	if (*argv) {
4252490Sjkh		do {
42610352Sjoerg			for (p = *argv; *p; ++p) {
42757527Sjoerg				if (eflag)
42857527Sjoerg					putchar(*p);
42929018Sache				morse(*p);
43010352Sjoerg			}
43157527Sjoerg			if (eflag)
43257527Sjoerg				putchar(' ');
43329018Sache			morse(' ');
4342490Sjkh		} while (*++argv);
43510352Sjoerg	} else {
43657527Sjoerg		while ((ch = getchar()) != EOF) {
43757527Sjoerg			if (eflag)
43857527Sjoerg				putchar(ch);
43910352Sjoerg			morse(ch);
44057527Sjoerg		}
44110352Sjoerg	}
44257527Sjoerg	if (device)
44357527Sjoerg		tcsetattr(line, TCSANOW, &otty);
44410352Sjoerg	exit(0);
4452490Sjkh}
4462490Sjkh
447249840Seadlerstatic void
44810352Sjoergmorse(char c)
4492490Sjkh{
45054622Sbillf	const struct morsetab *m;
45110352Sjoerg
45229018Sache	if (isalpha((unsigned char)c))
45329018Sache		c = tolower((unsigned char)c);
45410352Sjoerg	if ((c == '\r') || (c == '\n'))
45510352Sjoerg		c = ' ';
45610352Sjoerg	if (c == ' ') {
457121945Sphk		if (pflag)
45810352Sjoerg			play(" ");
459121945Sphk		else if (device)
46057527Sjoerg			ttyout(" ");
461121945Sphk		else if (lflag)
462121945Sphk			printf("\n");
463121945Sphk		else
46410352Sjoerg			show("");
465121945Sphk		return;
46610352Sjoerg	}
46710352Sjoerg	for (m = ((unsigned char)c < 0x80? mtab: hightab);
46878793Sache	     m != NULL && m->inchar != '\0';
46910352Sjoerg	     m++) {
47010352Sjoerg		if (m->inchar == c) {
47110352Sjoerg			if (pflag) {
47210352Sjoerg				play(m->morse);
47357527Sjoerg			} else if (device) {
47457527Sjoerg				ttyout(m->morse);
47510352Sjoerg			} else
47610352Sjoerg				show(m->morse);
47710352Sjoerg		}
47810352Sjoerg	}
4792490Sjkh}
4802490Sjkh
481249840Seadlerstatic void
48210352Sjoergshow(const char *s)
4832490Sjkh{
484121945Sphk	if (lflag) {
485121945Sphk		printf("%s ", s);
486121945Sphk	} else if (sflag) {
487121945Sphk		printf(" %s\n", s);
488121945Sphk	} else {
48910352Sjoerg		for (; *s; ++s)
490179654Sscf			printf(" %s", *s == '.' ? *(s + 1) == '\0' ? "dit" :
491179654Sscf			    "di" : "dah");
492121945Sphk		printf("\n");
493121945Sphk	}
4942490Sjkh}
49510352Sjoerg
496249840Seadlerstatic void
49710352Sjoergplay(const char *s)
49810352Sjoerg{
49910352Sjoerg#ifdef SPEAKER
50010352Sjoerg	const char *c;
50110352Sjoerg
50210352Sjoerg	for (c = s; *c != '\0'; c++) {
50329018Sache		switch (*c) {
50410352Sjoerg		case '.':
50510352Sjoerg			sound.frequency = freq;
50610352Sjoerg			sound.duration = dot_clock;
50710352Sjoerg			break;
50810352Sjoerg		case '-':
50910352Sjoerg			sound.frequency = freq;
51010352Sjoerg			sound.duration = dot_clock * DASH_LEN;
51110352Sjoerg			break;
51210352Sjoerg		case ' ':
51310352Sjoerg			sound.frequency = 0;
514147110Sjoerg			sound.duration = cdot_clock * WORD_SPACE;
51510352Sjoerg			break;
51610352Sjoerg		default:
51710352Sjoerg			sound.duration = 0;
51810352Sjoerg		}
51910352Sjoerg		if (sound.duration) {
52010352Sjoerg			if (ioctl(spkr, SPKRTONE, &sound) == -1) {
52110352Sjoerg				perror("ioctl play");
52210352Sjoerg				exit(1);
52310352Sjoerg			}
52410352Sjoerg		}
52510352Sjoerg		sound.frequency = 0;
52610352Sjoerg		sound.duration = dot_clock;
52710352Sjoerg		if (ioctl(spkr, SPKRTONE, &sound) == -1) {
52810352Sjoerg			perror("ioctl rest");
52910352Sjoerg			exit(1);
53010352Sjoerg		}
53110352Sjoerg	}
53210352Sjoerg	sound.frequency = 0;
533147110Sjoerg	sound.duration = cdot_clock * CHAR_SPACE;
53410352Sjoerg	ioctl(spkr, SPKRTONE, &sound);
53510352Sjoerg#endif
53610352Sjoerg}
53757527Sjoerg
538249840Seadlerstatic void
53957527Sjoergttyout(const char *s)
54057527Sjoerg{
54157527Sjoerg	const char *c;
54257527Sjoerg	int duration, on, lflags;
54357527Sjoerg
54457527Sjoerg	for (c = s; *c != '\0'; c++) {
54557527Sjoerg		switch (*c) {
54657527Sjoerg		case '.':
54757527Sjoerg			on = 1;
54857527Sjoerg			duration = dot_clock;
54957527Sjoerg			break;
55057527Sjoerg		case '-':
55157527Sjoerg			on = 1;
55257527Sjoerg			duration = dot_clock * DASH_LEN;
55357527Sjoerg			break;
55457527Sjoerg		case ' ':
55557527Sjoerg			on = 0;
556147110Sjoerg			duration = cdot_clock * WORD_SPACE;
55757527Sjoerg			break;
55857527Sjoerg		default:
55957527Sjoerg			on = 0;
56057527Sjoerg			duration = 0;
56157527Sjoerg		}
56257527Sjoerg		if (on) {
56357527Sjoerg			ioctl(line, TIOCMGET, &lflags);
56457527Sjoerg			lflags |= TIOCM_RTS;
56557527Sjoerg			ioctl(line, TIOCMSET, &lflags);
56657527Sjoerg		}
56757527Sjoerg		duration *= 10000;
56857527Sjoerg		if (duration)
56957527Sjoerg			usleep(duration);
57057527Sjoerg		ioctl(line, TIOCMGET, &lflags);
57157527Sjoerg		lflags &= ~TIOCM_RTS;
57257527Sjoerg		ioctl(line, TIOCMSET, &lflags);
57357527Sjoerg		duration = dot_clock * 10000;
57457527Sjoerg		usleep(duration);
57557527Sjoerg	}
576147110Sjoerg	duration = cdot_clock * CHAR_SPACE * 10000;
57757527Sjoerg	usleep(duration);
57857527Sjoerg}
57957527Sjoerg
580249840Seadlerstatic void
58157527Sjoergsighandler(int signo)
58257527Sjoerg{
58357527Sjoerg
58457527Sjoerg	ioctl(line, TIOCMSET, &olflags);
58557527Sjoerg	tcsetattr(line, TCSANOW, &otty);
58657527Sjoerg
58757527Sjoerg	signal(signo, SIG_DFL);
58857527Sjoerg	(void)kill(getpid(), signo);
58957527Sjoerg}
590