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