morse.c revision 53210
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 * $FreeBSD: head/games/morse/morse.c 53210 1999-11-16 02:58:06Z billf $
34 */
35
36/*
37 * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
38 * <lyndon@orthanc.com>
39 */
40
41#ifndef lint
42static char copyright[] =
43"@(#) Copyright (c) 1988, 1993\n\
44	The Regents of the University of California.  All rights reserved.\n";
45#endif /* not lint */
46
47#ifndef lint
48static char sccsid[] = "@(#)morse.c	8.1 (Berkeley) 5/31/93";
49#endif /* not lint */
50
51#include <stdio.h>
52#include <ctype.h>
53#include <locale.h>
54#include <stdlib.h>
55#include <string.h>
56
57#ifdef SPEAKER
58#include <machine/speaker.h>
59#include <fcntl.h>
60#endif
61
62struct morsetab {
63	char            inchar;
64	char           *morse;
65};
66
67static struct morsetab mtab[] = {
68
69	/* letters */
70
71	'a', ".-",
72	'b', "-...",
73	'c', "-.-.",
74	'd', "-..",
75	'e', ".",
76	'f', "..-.",
77	'g', "--.",
78	'h', "....",
79	'i', "..",
80	'j', ".---",
81	'k', "-.-",
82	'l', ".-..",
83	'm', "--",
84	'n', "-.",
85	'o', "---",
86	'p', ".--.",
87	'q', "--.-",
88	'r', ".-.",
89	's', "...",
90	't', "-",
91	'u', "..-",
92	'v', "...-",
93	'w', ".--",
94	'x', "-..-",
95	'y', "-.--",
96	'z', "--..",
97
98	/* digits */
99
100	'0', "-----",
101	'1', ".----",
102	'2', "..---",
103	'3', "...--",
104	'4', "....-",
105	'5', ".....",
106	'6', "-....",
107	'7', "--...",
108	'8', "---..",
109	'9', "----.",
110
111	/* punctuation */
112
113	',', "--..--",
114	'.', ".-.-.-",
115	'?', "..--..",
116	'/', "-..-.",
117	'-', "-....-",
118	'=', "-...-",		/* BT */
119	':', "---...",
120	';', "-.-.-.",
121	'(', "-.--.",		/* KN */
122	')', "-.--.-",
123	'$', "...-..-",
124	'+', ".-.-.",		/* AR */
125
126	/* prosigns without already assigned values */
127
128	'#', ".-...",		/* AS */
129	'@', "...-.-",		/* SK */
130	'*', "...-.",		/* VE */
131	'%', "-...-.-",		/* BK */
132
133	'\0', ""
134};
135
136
137static struct morsetab iso8859tab[] = {
138	'�', ".--.-",
139	'�', ".--.-",
140	'�', ".--.-",
141	'�', ".-.-",
142	'�', "-.-..",
143	'�', "..-..",
144	'�', "..-..",
145	'�', "-..-.",
146	'�', "---.",
147	'�', "..--",
148
149	'\0', ""
150};
151
152static struct morsetab koi8rtab[] = {
153	/*
154	 * the cyrillic alphabet; you'll need a KOI8R font in order
155	 * to see the actual characters
156	 */
157	'�', ".-",		/* a */
158	'�', "-...",		/* be */
159	'�', ".--",		/* ve */
160	'�', "--.",		/* ge */
161	'�', "-..",		/* de */
162	'�', ".",		/* ye */
163	'�', ".",               /* yo, the same as ye */
164	'�', "...-",		/* she */
165	'�', "--..",		/* ze */
166	'�', "..",		/* i */
167	'�', ".---",		/* i kratkoye */
168	'�', "-.-",		/* ka */
169	'�', ".-..",		/* el */
170	'�', "--",		/* em */
171	'�', "-.",		/* en */
172	'�', "---",		/* o */
173	'�', ".--.",		/* pe */
174	'�', ".-.",		/* er */
175	'�', "...",		/* es */
176	'�', "-",		/* te */
177	'�', "..-",		/* u */
178	'�', "..-.",		/* ef */
179	'�', "....",		/* kha */
180	'�', "-.-.",		/* ce */
181	'�', "---.",		/* che */
182	'�', "----",		/* sha */
183	'�', "--.-",		/* shcha */
184	'�', "-.--",		/* yi */
185	'�', "-..-",		/* myakhkij znak */
186	'�', "..-..",		/* ae */
187	'�', "..--",		/* yu */
188	'�', ".-.-",		/* ya */
189
190	'\0', ""
191};
192
193void            show(const char *), play(const char *), morse(char);
194
195static int      pflag, sflag;
196static int      wpm = 20;	/* words per minute */
197#define FREQUENCY 600
198static int      freq = FREQUENCY;
199
200#ifdef SPEAKER
201#define DASH_LEN 3
202#define CHAR_SPACE 3
203#define WORD_SPACE (7 - CHAR_SPACE - 1)
204static float    dot_clock;
205int             spkr;
206tone_t          sound;
207#endif
208
209static struct morsetab *hightab = iso8859tab;
210
211int
212main(int argc, char **argv)
213{
214	extern char    *optarg;
215	extern int      optind;
216	int    ch;
217	char  *p;
218
219	while ((ch = getopt(argc, argv, "spw:f:")) != -1)
220		switch ((char) ch) {
221		case 'f':
222			freq = atoi(optarg);
223			break;
224		case 'p':
225			pflag = 1;
226			break;
227		case 's':
228			sflag = 1;
229			break;
230		case 'w':
231			wpm = atoi(optarg);
232			break;
233		case '?':
234		default:
235			fputs("usage: morse [-s] [-p] [-w speed] [-f frequency] [string ...]\n", stderr);
236			exit(1);
237		}
238	if (pflag && sflag) {
239		fputs("morse: only one of -p and -s allowed\n", stderr);
240		exit(1);
241	}
242	if (pflag && ((wpm < 1) || (wpm > 60))) {
243		fputs("morse: insane speed\n", stderr);
244		exit(1);
245	}
246	if (pflag && (freq == 0))
247		freq = FREQUENCY;
248
249#ifdef SPEAKER
250	if (pflag) {
251		if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
252			perror(SPEAKER);
253			exit(1);
254		}
255		dot_clock = wpm / 2.4;		/* dots/sec */
256		dot_clock = 1 / dot_clock;	/* duration of a dot */
257		dot_clock = dot_clock / 2;	/* dot_clock runs at twice */
258						/* the dot rate */
259		dot_clock = dot_clock * 100;	/* scale for ioctl */
260	}
261#endif
262	argc -= optind;
263	argv += optind;
264
265	if((p = getenv("LC_CTYPE")) ||
266	   (p = getenv("LC_ALL")) ||
267	   (p = getenv("LANG"))) {
268		if(strlen(p) >= sizeof(".KOI8-R") &&
269		   strcasecmp(&p[strlen(p) + 1 - sizeof(".KOI8-R")], ".KOI8-R") == 0)
270			hightab = koi8rtab;
271	}
272	(void) setlocale(LC_CTYPE, "");
273
274	if (*argv) {
275		do {
276			for (p = *argv; *p; ++p) {
277				morse(*p);
278			}
279			morse(' ');
280		} while (*++argv);
281	} else {
282		while ((ch = getchar()) != EOF)
283			morse(ch);
284	}
285	exit(0);
286}
287
288void
289morse(char c)
290{
291	struct morsetab *m;
292
293	if (isalpha((unsigned char)c))
294		c = tolower((unsigned char)c);
295	if ((c == '\r') || (c == '\n'))
296		c = ' ';
297	if (c == ' ') {
298		if (pflag) {
299			play(" ");
300			return;
301		} else {
302			show("");
303			return;
304		}
305	}
306	for (m = ((unsigned char)c < 0x80? mtab: hightab);
307	     m->inchar != '\0';
308	     m++) {
309		if (m->inchar == c) {
310			if (pflag) {
311				play(m->morse);
312			} else
313				show(m->morse);
314		}
315	}
316}
317
318void
319show(const char *s)
320{
321	if (sflag)
322		printf(" %s", s);
323	else
324		for (; *s; ++s)
325			printf(" %s", *s == '.' ? "dit" : "dah");
326	printf("\n");
327}
328
329void
330play(const char *s)
331{
332#ifdef SPEAKER
333	const char *c;
334
335	for (c = s; *c != '\0'; c++) {
336		switch (*c) {
337		case '.':
338			sound.frequency = freq;
339			sound.duration = dot_clock;
340			break;
341		case '-':
342			sound.frequency = freq;
343			sound.duration = dot_clock * DASH_LEN;
344			break;
345		case ' ':
346			sound.frequency = 0;
347			sound.duration = dot_clock * WORD_SPACE;
348			break;
349		default:
350			sound.duration = 0;
351		}
352		if (sound.duration) {
353			if (ioctl(spkr, SPKRTONE, &sound) == -1) {
354				perror("ioctl play");
355				exit(1);
356			}
357		}
358		sound.frequency = 0;
359		sound.duration = dot_clock;
360		if (ioctl(spkr, SPKRTONE, &sound) == -1) {
361			perror("ioctl rest");
362			exit(1);
363		}
364	}
365	sound.frequency = 0;
366	sound.duration = dot_clock * CHAR_SPACE;
367	ioctl(spkr, SPKRTONE, &sound);
368#endif
369}
370