morse.c revision 29018
1156230Smux/*
2156230Smux * Copyright (c) 1988, 1993
3156230Smux *	The Regents of the University of California.  All rights reserved.
4156230Smux *
5156230Smux * Redistribution and use in source and binary forms, with or without
6156230Smux * modification, are permitted provided that the following conditions
7156230Smux * are met:
8156230Smux * 1. Redistributions of source code must retain the above copyright
9156230Smux *    notice, this list of conditions and the following disclaimer.
10156230Smux * 2. Redistributions in binary form must reproduce the above copyright
11156230Smux *    notice, this list of conditions and the following disclaimer in the
12156230Smux *    documentation and/or other materials provided with the distribution.
13156230Smux * 3. All advertising materials mentioning features or use of this software
14156230Smux *    must display the following acknowledgement:
15156230Smux *	This product includes software developed by the University of
16156230Smux *	California, Berkeley and its contributors.
17156230Smux * 4. Neither the name of the University nor the names of its contributors
18156230Smux *    may be used to endorse or promote products derived from this software
19156230Smux *    without specific prior written permission.
20156230Smux *
21156230Smux * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22156230Smux * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23156230Smux * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24156230Smux * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25156230Smux * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26156230Smux * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27156230Smux * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28156230Smux * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29156230Smux * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30156230Smux * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31156230Smux * SUCH DAMAGE.
32216370Sjoel */
33216370Sjoel
34156230Smux/*
35156230Smux * Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
36156230Smux * <lyndon@orthanc.com>
37156230Smux */
38156230Smux
39156230Smux#ifndef lint
40156230Smuxstatic char copyright[] =
41156230Smux"@(#) Copyright (c) 1988, 1993\n\
42156230Smux	The Regents of the University of California.  All rights reserved.\n";
43156230Smux#endif /* not lint */
44156230Smux
45156230Smux#ifndef lint
46156230Smuxstatic char sccsid[] = "@(#)morse.c	8.1 (Berkeley) 5/31/93";
47156230Smux#endif /* not lint */
48156230Smux
49156230Smux#include <stdio.h>
50156230Smux#include <ctype.h>
51156230Smux#include <locale.h>
52156230Smux#include <stdlib.h>
53156230Smux
54156230Smux#ifdef SPEAKER
55156230Smux#include <machine/speaker.h>
56156230Smux#include <fcntl.h>
57156230Smux#endif
58156230Smux
59156230Smuxstruct morsetab {
60156230Smux	char            inchar;
61156230Smux	char           *morse;
62156230Smux};
63156230Smux
64156230Smuxstatic struct morsetab mtab[] = {
65156230Smux
66156230Smux	/* letters */
67156230Smux
68156230Smux	'a', ".-",
69156230Smux	'b', "-...",
70156230Smux	'c', "-.-.",
71156230Smux	'd', "-..",
72156230Smux	'e', ".",
73156230Smux	'f', "..-.",
74156230Smux	'g', "--.",
75156230Smux	'h', "....",
76156230Smux	'i', "..",
77156230Smux	'j', ".---",
78156230Smux	'k', "-.-",
79156230Smux	'l', ".-..",
80156230Smux	'm', "--",
81156230Smux	'n', "-.",
82156230Smux	'o', "---",
83156230Smux	'p', ".--.",
84156230Smux	'q', "--.-",
85156230Smux	'r', ".-.",
86156230Smux	's', "...",
87156230Smux	't', "-",
88156230Smux	'u', "..-",
89156230Smux	'v', "...-",
90156230Smux	'w', ".--",
91156230Smux	'x', "-..-",
92156230Smux	'y', "-.--",
93156230Smux	'z', "--..",
94156230Smux
95156230Smux	/* digits */
96156230Smux
97156230Smux	'0', "-----",
98156230Smux	'1', ".----",
99156230Smux	'2', "..---",
100156230Smux	'3', "...--",
101156230Smux	'4', "....-",
102156230Smux	'5', ".....",
103156230Smux	'6', "-....",
104156230Smux	'7', "--...",
105156230Smux	'8', "---..",
106156230Smux	'9', "----.",
107156230Smux
108156230Smux	/* punctuation */
109156230Smux
110156230Smux	',', "--..--",
111156230Smux	'.', ".-.-.-",
112156230Smux	'?', "..--..",
113156230Smux	'/', "-..-.",
114156230Smux	'-', "-....-",
115156230Smux	'=', "-...-",		/* BT */
116156230Smux	':', "---...",
117156230Smux	';', "-.-.-.",
118156230Smux	'(', "-.--.",		/* KN */
119156230Smux	')', "-.--.-",
120156230Smux	'$', "...-..-",
121156230Smux	'+', ".-.-.",		/* AR */
122156230Smux
123156230Smux	/* prosigns without already assigned values */
124156230Smux
125156230Smux	'#', ".-...",		/* AS */
126156230Smux	'@', "...-.-",		/* SK */
127156230Smux	'*', "...-.",		/* VE */
128156230Smux	'%', "-...-.-",		/* BK */
129156230Smux
130156230Smux	'\0', ""
131156230Smux};
132156230Smux
133156230Smux
134156230Smuxstatic struct morsetab iso8859tab[] = {
135156230Smux	'�', ".--.-",
136156230Smux	'�', ".--.-",
137156230Smux	'�', ".--.-",
138156230Smux	'�', ".-.-",
139156230Smux	'�', "-.-..",
140156230Smux	'�', "..-..",
141156230Smux	'�', "..-..",
142156230Smux	'�', "-..-.",
143156230Smux	'�', "---.",
144156230Smux	'�', "..--",
145156230Smux
146156230Smux	'\0', ""
147156230Smux};
148156230Smux
149156230Smuxstatic struct morsetab koi8rtab[] = {
150156230Smux	/*
151156230Smux	 * the cyrillic alphabet; you'll need a KOI8R font in order
152156230Smux	 * to see the actual characters
153156230Smux	 */
154156230Smux	'�', ".-",		/* a */
155156230Smux	'�', "-...",		/* be */
156156230Smux	'�', ".--",		/* ve */
157156230Smux	'�', "--.",		/* ge */
158156230Smux	'�', "-..",		/* de */
159156230Smux	'�', ".",		/* ye */
160156230Smux	'�', ".",               /* yo, the same as ye */
161156230Smux	'�', "...-",		/* she */
162156230Smux	'�', "--..",		/* ze */
163156230Smux	'�', "..",		/* i */
164156230Smux	'�', ".---",		/* i kratkoye */
165156230Smux	'�', "-.-",		/* ka */
166156230Smux	'�', ".-..",		/* el */
167156230Smux	'�', "--",		/* em */
168156230Smux	'�', "-.",		/* en */
169156230Smux	'�', "---",		/* o */
170156230Smux	'�', ".--.",		/* pe */
171156230Smux	'�', ".-.",		/* er */
172156230Smux	'�', "...",		/* es */
173156230Smux	'�', "-",		/* te */
174156230Smux	'�', "..-",		/* u */
175156230Smux	'�', "..-.",		/* ef */
176156230Smux	'�', "....",		/* kha */
177156230Smux	'�', "-.-.",		/* ce */
178156230Smux	'�', "---.",		/* che */
179156230Smux	'�', "----",		/* sha */
180156230Smux	'�', "--.-",		/* shcha */
181156230Smux	'�', "-.--",		/* yi */
182156230Smux	'�', "-..-",		/* myakhkij znak */
183156230Smux	'�', "..-..",		/* ae */
184156230Smux	'�', "..--",		/* yu */
185156230Smux	'�', ".-.-",		/* ya */
186156230Smux
187156230Smux	'\0', ""
188156230Smux};
189156230Smux
190156230Smuxvoid            show(const char *), play(const char *), morse(char);
191156230Smux
192156230Smuxstatic int      pflag, sflag;
193156230Smuxstatic int      wpm = 20;	/* words per minute */
194156230Smux#define FREQUENCY 600
195156230Smuxstatic int      freq = FREQUENCY;
196156230Smux
197156230Smux#ifdef SPEAKER
198#define DASH_LEN 3
199#define CHAR_SPACE 3
200#define WORD_SPACE (7 - CHAR_SPACE - 1)
201static float    dot_clock;
202int             spkr;
203tone_t          sound;
204#endif
205
206static struct morsetab *hightab = iso8859tab;
207
208int
209main(int argc, char **argv)
210{
211	extern char    *optarg;
212	extern int      optind;
213	register int    ch;
214	register char  *p;
215
216	while ((ch = getopt(argc, argv, "spw:f:")) != EOF)
217		switch ((char) ch) {
218		case 'f':
219			freq = atoi(optarg);
220			break;
221		case 'p':
222			pflag = 1;
223			break;
224		case 's':
225			sflag = 1;
226			break;
227		case 'w':
228			wpm = atoi(optarg);
229			break;
230		case '?':
231		default:
232			fputs("usage: morse [-s] [-p] [-w speed] [-f frequency] [string ...]\n", stderr);
233			exit(1);
234		}
235	if (pflag && sflag) {
236		fputs("morse: only one of -p and -s allowed\n", stderr);
237		exit(1);
238	}
239	if (pflag && ((wpm < 1) || (wpm > 60))) {
240		fputs("morse: insane speed\n", stderr);
241		exit(1);
242	}
243	if (pflag && (freq == 0))
244		freq = FREQUENCY;
245
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")) ||
263	   (p = getenv("LC_ALL")) ||
264	   (p = getenv("LANG"))) {
265		if(strlen(p) >= sizeof(".KOI8-R") &&
266		   strcasecmp(&p[strlen(p) + 1 - sizeof(".KOI8-R")], ".KOI8-R") == 0)
267			hightab = koi8rtab;
268	}
269	(void) setlocale(LC_CTYPE, "");
270
271	if (*argv) {
272		do {
273			for (p = *argv; *p; ++p) {
274				morse(*p);
275			}
276			morse(' ');
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((unsigned char)c))
291		c = tolower((unsigned char)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 (*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