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