morse.c revision 10352
1/*
2 * Copyright (c) 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
36 * <lyndon@orthanc.com>
37 */
38
39#ifndef lint
40static char copyright[] =
41"@(#) Copyright (c) 1988, 1993\n\
42	The Regents of the University of California.  All rights reserved.\n";
43#endif /* not lint */
44
45#ifndef lint
46static char sccsid[] = "@(#)morse.c	8.1 (Berkeley) 5/31/93";
47#endif /* not lint */
48
49#include <stdio.h>
50#include <ctype.h>
51#include <locale.h>
52#include <stdlib.h>
53
54#ifdef SPEAKER
55#include <machine/speaker.h>
56#include <fcntl.h>
57#endif
58
59struct morsetab {
60	char            inchar;
61	char           *morse;
62};
63
64static struct morsetab mtab[] = {
65
66	/* letters */
67
68	'a', ".-",
69	'b', "-...",
70	'c', "-.-.",
71	'd', "-..",
72	'e', ".",
73	'f', "..-.",
74	'g', "--.",
75	'h', "....",
76	'i', "..",
77	'j', ".---",
78	'k', "-.-",
79	'l', ".-..",
80	'm', "--",
81	'n', "-.",
82	'o', "---",
83	'p', ".--.",
84	'q', "--.-",
85	'r', ".-.",
86	's', "...",
87	't', "-",
88	'u', "..-",
89	'v', "...-",
90	'w', ".--",
91	'x', "-..-",
92	'y', "-.--",
93	'z', "--..",
94
95	/* digits */
96
97	'0', "-----",
98	'1', ".----",
99	'2', "..---",
100	'3', "...--",
101	'4', "....-",
102	'5', ".....",
103	'6', "-....",
104	'7', "--...",
105	'8', "---..",
106	'9', "----.",
107
108	/* punctuation */
109
110	',', "--..--",
111	'.', ".-.-.-",
112	'?', "..--..",
113	'/', "-..-.",
114	'-', "-....-",
115	'=', "-...-",		/* BT */
116	':', "---...",
117	';', "-.-.-.",
118	'(', "-.--.",		/* KN */
119	')', "-.--.-",
120	'$', "...-..-",
121	'+', ".-.-.",		/* AR */
122
123	/* prosigns without already assigned values */
124
125	'#', ".-...",		/* AS */
126	'@', "...-.-",		/* SK */
127	'*', "...-.",		/* VE */
128	'%', "-...-.-",		/* BK */
129
130	'\0', ""
131};
132
133
134static struct morsetab iso8859tab[] = {
135	'�', ".--.-",
136	'�', ".--.-",
137	'�', ".--.-",
138	'�', ".-.-",
139	'�', "-.-..",
140	'�', "..-..",
141	'�', "..-..",
142	'�', "-..-.",
143	'�', "---.",
144	'�', "..--",
145
146	'\0', ""
147};
148
149static struct morsetab koi8rtab[] = {
150	/*
151	 * the cyrillic alphabet; you'll need a KOI8R font in order
152	 * to see the actual characters
153	 */
154	'�', ".-",		/* a */
155	'�', "-...",		/* be */
156	'�', ".--",		/* ve */
157	'�', "--.",		/* ge */
158	'�', "-..",		/* de */
159	'�', ".",		/* ye */
160	'�', "...-",		/* she */
161	'�', "--..",		/* ze */
162	'�', "..",		/* i */
163	'�', ".---",		/* i kratkoye */
164	'�', "-.-",		/* ka */
165	'�', ".-..",		/* el */
166	'�', "--",		/* em */
167	'�', "-.",		/* en */
168	'�', "---",		/* o */
169	'�', ".--.",		/* pe */
170	'�', ".-.",		/* er */
171	'�', "...",		/* es */
172	'�', "-",		/* te */
173	'�', "..-",		/* u */
174	'�', "..-.",		/* ef */
175	'�', "....",		/* kha */
176	'�', "-.-.",		/* ce */
177	'�', "---.",		/* che */
178	'�', "----",		/* sha */
179	'�', "--.-",		/* shcha */
180	'�', "-.--",		/* yi */
181	'�', "-..-",		/* myakhkij znak */
182	'�', "..-..",		/* ae */
183	'�', "..--",		/* yu */
184	'�', ".-.-",		/* ya */
185
186	'\0', ""
187};
188
189void            show(const char *), play(const char *), morse(char);
190
191static int      pflag, sflag;
192static int      wpm = 20;	/* words per minute */
193#define FREQUENCY 600
194static int      freq = FREQUENCY;
195
196#ifdef SPEAKER
197#define DASH_LEN 3
198#define CHAR_SPACE 3
199#define WORD_SPACE (7 - CHAR_SPACE - 1)
200static float    dot_clock;
201int             spkr;
202tone_t          sound;
203#endif
204
205static struct morsetab *hightab = iso8859tab;
206
207int
208main(int argc, char **argv)
209{
210	extern char    *optarg;
211	extern int      optind;
212	register int    ch;
213	register char  *p;
214
215	while ((ch = getopt(argc, argv, "spw:f:")) != EOF)
216		switch ((char) ch) {
217		case 'f':
218			freq = atoi(optarg);
219			break;
220		case 'p':
221			pflag = 1;
222			break;
223		case 's':
224			sflag = 1;
225			break;
226		case 'w':
227			wpm = atoi(optarg);
228			break;
229		case '?':
230		default:
231			fputs("usage: morse [-s] [-p] [-w speed] [-f frequency] [string ...]\n", stderr);
232			exit(1);
233		}
234	if (pflag && sflag) {
235		fputs("morse: only one of -p and -s allowed\n", stderr);
236		exit(1);
237	}
238	if (pflag && ((wpm < 1) || (wpm > 60))) {
239		fputs("morse: insane speed\n", stderr);
240		exit(1);
241	}
242	if (pflag && (freq == 0))
243		freq = FREQUENCY;
244
245	(void)setuid(getuid());
246#ifdef SPEAKER
247	if (pflag) {
248		if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
249			perror(SPEAKER);
250			exit(1);
251		}
252		dot_clock = wpm / 2.4;		/* dots/sec */
253		dot_clock = 1 / dot_clock;	/* duration of a dot */
254		dot_clock = dot_clock / 2;	/* dot_clock runs at twice */
255						/* the dot rate */
256		dot_clock = dot_clock * 100;	/* scale for ioctl */
257	}
258#endif
259	argc -= optind;
260	argv += optind;
261
262	if((p = getenv("LC_CTYPE")) || (p = getenv("LANG"))) {
263		if(strlen(p) >= strlen("KOI8-R") &&
264		   strcasecmp(&p[strlen(p) - strlen("KOI8-R")], "KOI8-R") == 0)
265			hightab = koi8rtab;
266		setlocale(LC_CTYPE, p);
267	} else {
268		setlocale(LC_CTYPE, "");
269	}
270
271	if (*argv) {
272		do {
273			for (p = *argv; *p; ++p) {
274				morse((int) *p);
275			}
276			morse((int) ' ');
277		} while (*++argv);
278	} else {
279		while ((ch = getchar()) != EOF)
280			morse(ch);
281	}
282	exit(0);
283}
284
285void
286morse(char c)
287{
288	struct morsetab *m;
289
290	if (isalpha(c))
291		c = tolower(c);
292	if ((c == '\r') || (c == '\n'))
293		c = ' ';
294	if (c == ' ') {
295		if (pflag) {
296			play(" ");
297			return;
298		} else {
299			show("");
300			return;
301		}
302	}
303	for (m = ((unsigned char)c < 0x80? mtab: hightab);
304	     m->inchar != '\0';
305	     m++) {
306		if (m->inchar == c) {
307			if (pflag) {
308				play(m->morse);
309			} else
310				show(m->morse);
311		}
312	}
313}
314
315void
316show(const char *s)
317{
318	if (sflag)
319		printf(" %s", s);
320	else
321		for (; *s; ++s)
322			printf(" %s", *s == '.' ? "dit" : "dah");
323	printf("\n");
324}
325
326void
327play(const char *s)
328{
329#ifdef SPEAKER
330	const char *c;
331
332	for (c = s; *c != '\0'; c++) {
333		switch ((int) *c) {
334		case '.':
335			sound.frequency = freq;
336			sound.duration = dot_clock;
337			break;
338		case '-':
339			sound.frequency = freq;
340			sound.duration = dot_clock * DASH_LEN;
341			break;
342		case ' ':
343			sound.frequency = 0;
344			sound.duration = dot_clock * WORD_SPACE;
345			break;
346		default:
347			sound.duration = 0;
348		}
349		if (sound.duration) {
350			if (ioctl(spkr, SPKRTONE, &sound) == -1) {
351				perror("ioctl play");
352				exit(1);
353			}
354		}
355		sound.frequency = 0;
356		sound.duration = dot_clock;
357		if (ioctl(spkr, SPKRTONE, &sound) == -1) {
358			perror("ioctl rest");
359			exit(1);
360		}
361	}
362	sound.frequency = 0;
363	sound.duration = dot_clock * CHAR_SPACE;
364	ioctl(spkr, SPKRTONE, &sound);
365#endif
366}
367