freebsd-dev/games/morse/morse.c
1999-12-15 04:28:10 +00:00

371 lines
7.9 KiB
C
Raw Blame History

/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Taught to send *real* morse by Lyndon Nerenberg (VE7TCP/VE6BBM)
* <lyndon@orthanc.com>
*/
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)morse.c 8.1 (Berkeley) 5/31/93";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef SPEAKER
#include <machine/speaker.h>
#include <fcntl.h>
#endif
struct morsetab {
char inchar;
char *morse;
};
static const struct morsetab mtab[] = {
/* letters */
{'a', ".-"},
{'b', "-..."},
{'c', "-.-."},
{'d', "-.."},
{'e', "."},
{'f', "..-."},
{'g', "--."},
{'h', "...."},
{'i', ".."},
{'j', ".---"},
{'k', "-.-"},
{'l', ".-.."},
{'m', "--"},
{'n', "-."},
{'o', "---"},
{'p', ".--."},
{'q', "--.-"},
{'r', ".-."},
{'s', "..."},
{'t', "-"},
{'u', "..-"},
{'v', "...-"},
{'w', ".--"},
{'x', "-..-"},
{'y', "-.--"},
{'z', "--.."},
/* digits */
{'0', "-----"},
{'1', ".----"},
{'2', "..---"},
{'3', "...--"},
{'4', "....-"},
{'5', "....."},
{'6', "-...."},
{'7', "--..."},
{'8', "---.."},
{'9', "----."},
/* punctuation */
{',', "--..--"},
{'.', ".-.-.-"},
{'?', "..--.."},
{'/', "-..-."},
{'-', "-....-"},
{'=', "-...-"}, /* BT */
{':', "---..."},
{';', "-.-.-."},
{'(', "-.--."}, /* KN */
{')', "-.--.-"},
{'$', "...-..-"},
{'+', ".-.-."}, /* AR */
/* prosigns without already assigned values */
{'#', ".-..."}, /* AS */
{'@', "...-.-"}, /* SK */
{'*', "...-."}, /* VE */
{'%', "-...-.-"}, /* BK */
{'\0', ""}
};
static const struct morsetab iso8859tab[] = {
{'<EFBFBD>', ".--.-"},
{'<EFBFBD>', ".--.-"},
{'<EFBFBD>', ".--.-"},
{'<EFBFBD>', ".-.-"},
{'<EFBFBD>', "-.-.."},
{'<EFBFBD>', "..-.."},
{'<EFBFBD>', "..-.."},
{'<EFBFBD>', "-..-."},
{'<EFBFBD>', "---."},
{'<EFBFBD>', "..--"},
{'\0', ""}
};
static const struct morsetab koi8rtab[] = {
/*
* the cyrillic alphabet; you'll need a KOI8R font in order
* to see the actual characters
*/
{'<EFBFBD>', ".-"}, /* a */
{'<EFBFBD>', "-..."}, /* be */
{'<EFBFBD>', ".--"}, /* ve */
{'<EFBFBD>', "--."}, /* ge */
{'<EFBFBD>', "-.."}, /* de */
{'<EFBFBD>', "."}, /* ye */
{'<EFBFBD>', "."}, /* yo, the same as ye */
{'<EFBFBD>', "...-"}, /* she */
{'<EFBFBD>', "--.."}, /* ze */
{'<EFBFBD>', ".."}, /* i */
{'<EFBFBD>', ".---"}, /* i kratkoye */
{'<EFBFBD>', "-.-"}, /* ka */
{'<EFBFBD>', ".-.."}, /* el */
{'<EFBFBD>', "--"}, /* em */
{'<EFBFBD>', "-."}, /* en */
{'<EFBFBD>', "---"}, /* o */
{'<EFBFBD>', ".--."}, /* pe */
{'<EFBFBD>', ".-."}, /* er */
{'<EFBFBD>', "..."}, /* es */
{'<EFBFBD>', "-"}, /* te */
{'<EFBFBD>', "..-"}, /* u */
{'<EFBFBD>', "..-."}, /* ef */
{'<EFBFBD>', "...."}, /* kha */
{'<EFBFBD>', "-.-."}, /* ce */
{'<EFBFBD>', "---."}, /* che */
{'<EFBFBD>', "----"}, /* sha */
{'<EFBFBD>', "--.-"}, /* shcha */
{'<EFBFBD>', "-.--"}, /* yi */
{'<EFBFBD>', "-..-"}, /* myakhkij znak */
{'<EFBFBD>', "..-.."}, /* ae */
{'<EFBFBD>', "..--"}, /* yu */
{'<EFBFBD>', ".-.-"}, /* ya */
{'\0', ""}
};
void show(const char *), play(const char *), morse(char);
static int pflag, sflag;
static int wpm = 20; /* words per minute */
#define FREQUENCY 600
static int freq = FREQUENCY;
#ifdef SPEAKER
#define DASH_LEN 3
#define CHAR_SPACE 3
#define WORD_SPACE (7 - CHAR_SPACE - 1)
static float dot_clock;
int spkr;
tone_t sound;
#endif
static const struct morsetab *hightab = iso8859tab;
int
main(int argc, char **argv)
{
int ch;
char *p;
while ((ch = getopt(argc, argv, "spw:f:")) != -1)
switch ((char) ch) {
case 'f':
freq = atoi(optarg);
break;
case 'p':
pflag = 1;
break;
case 's':
sflag = 1;
break;
case 'w':
wpm = atoi(optarg);
break;
case '?':
default:
fputs("usage: morse [-s] [-p] [-w speed] [-f frequency] [string ...]\n", stderr);
exit(1);
}
if (pflag && sflag) {
fputs("morse: only one of -p and -s allowed\n", stderr);
exit(1);
}
if (pflag && ((wpm < 1) || (wpm > 60))) {
fputs("morse: insane speed\n", stderr);
exit(1);
}
if (pflag && (freq == 0))
freq = FREQUENCY;
#ifdef SPEAKER
if (pflag) {
if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
perror(SPEAKER);
exit(1);
}
dot_clock = wpm / 2.4; /* dots/sec */
dot_clock = 1 / dot_clock; /* duration of a dot */
dot_clock = dot_clock / 2; /* dot_clock runs at twice */
/* the dot rate */
dot_clock = dot_clock * 100; /* scale for ioctl */
}
#endif
argc -= optind;
argv += optind;
if((p = getenv("LC_CTYPE")) ||
(p = getenv("LC_ALL")) ||
(p = getenv("LANG"))) {
if(strlen(p) >= sizeof(".KOI8-R") &&
strcasecmp(&p[strlen(p) + 1 - sizeof(".KOI8-R")], ".KOI8-R") == 0)
hightab = koi8rtab;
}
(void) setlocale(LC_CTYPE, "");
if (*argv) {
do {
for (p = *argv; *p; ++p) {
morse(*p);
}
morse(' ');
} while (*++argv);
} else {
while ((ch = getchar()) != EOF)
morse(ch);
}
exit(0);
}
void
morse(char c)
{
const struct morsetab *m;
if (isalpha((unsigned char)c))
c = tolower((unsigned char)c);
if ((c == '\r') || (c == '\n'))
c = ' ';
if (c == ' ') {
if (pflag) {
play(" ");
return;
} else {
show("");
return;
}
}
for (m = ((unsigned char)c < 0x80? mtab: hightab);
m->inchar != '\0';
m++) {
if (m->inchar == c) {
if (pflag) {
play(m->morse);
} else
show(m->morse);
}
}
}
void
show(const char *s)
{
if (sflag)
printf(" %s", s);
else
for (; *s; ++s)
printf(" %s", *s == '.' ? "dit" : "dah");
printf("\n");
}
void
play(const char *s)
{
#ifdef SPEAKER
const char *c;
for (c = s; *c != '\0'; c++) {
switch (*c) {
case '.':
sound.frequency = freq;
sound.duration = dot_clock;
break;
case '-':
sound.frequency = freq;
sound.duration = dot_clock * DASH_LEN;
break;
case ' ':
sound.frequency = 0;
sound.duration = dot_clock * WORD_SPACE;
break;
default:
sound.duration = 0;
}
if (sound.duration) {
if (ioctl(spkr, SPKRTONE, &sound) == -1) {
perror("ioctl play");
exit(1);
}
}
sound.frequency = 0;
sound.duration = dot_clock;
if (ioctl(spkr, SPKRTONE, &sound) == -1) {
perror("ioctl rest");
exit(1);
}
}
sound.frequency = 0;
sound.duration = dot_clock * CHAR_SPACE;
ioctl(spkr, SPKRTONE, &sound);
#endif
}