aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/morse
diff options
context:
space:
mode:
authorColin Percival <cperciva@FreeBSD.org>2015-10-02 10:08:11 +0000
committerColin Percival <cperciva@FreeBSD.org>2015-10-02 10:08:11 +0000
commit6ae1554a5d9b318f8ad53ccc39fa5a961403da73 (patch)
tree0bbcb3f392def57bae56978c0da09362f7d6b426 /usr.bin/morse
parentd58b610faa4552666982078efafd542171304865 (diff)
Notes
Diffstat (limited to 'usr.bin/morse')
-rw-r--r--usr.bin/morse/Makefile7
-rw-r--r--usr.bin/morse/Makefile.depend18
-rw-r--r--usr.bin/morse/morse.6197
-rw-r--r--usr.bin/morse/morse.c589
4 files changed, 811 insertions, 0 deletions
diff --git a/usr.bin/morse/Makefile b/usr.bin/morse/Makefile
new file mode 100644
index 000000000000..443542293777
--- /dev/null
+++ b/usr.bin/morse/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 5/31/93
+# $FreeBSD$
+
+PROG= morse
+MAN= morse.6
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/morse/Makefile.depend b/usr.bin/morse/Makefile.depend
new file mode 100644
index 000000000000..3646e2e2b1af
--- /dev/null
+++ b/usr.bin/morse/Makefile.depend
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.bin/morse/morse.6 b/usr.bin/morse/morse.6
new file mode 100644
index 000000000000..94645bbf5c7f
--- /dev/null
+++ b/usr.bin/morse/morse.6
@@ -0,0 +1,197 @@
+.\" Copyright (c) 2000 Alexey Zelkin. All rights reserved.
+.\" Copyright (c) 1988, 1991, 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. 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.
+.\"
+.\" @(#)bcd.6 8.1 (Berkeley) 5/31/93
+.\" $FreeBSD$
+.\"
+.Dd June 7, 2005
+.Dt MORSE 6
+.Os
+.Sh NAME
+.Nm morse
+.Nd reformat input as morse code
+.Sh SYNOPSIS
+.Nm
+.Op Fl elps
+.Op Fl d Ar device
+.Op Fl w Ar speed
+.Op Fl c Ar speed
+.Op Fl f Ar frequency
+.Op Ar string ...
+.Sh DESCRIPTION
+The
+.Nm
+command reads the given input and reformats it in the form of morse code.
+Acceptable input are command line arguments or the standard input.
+.Pp
+Available options:
+.Bl -tag -width indent
+.It Fl l
+The
+.Fl l
+option produces output suitable for
+.Xr led 4
+devices.
+.It Fl s
+The
+.Fl s
+option produces dots and dashes rather than words.
+.It Fl p
+Send morse the real way.
+This only works if your system has
+.Xr speaker 4
+support.
+.It Fl w Ar speed
+Set the sending speed in words per minute.
+If not specified, the default
+speed of 20 WPM is used.
+.It Fl c Ar speed
+Farnsworth support.
+Set the spacing between characters in words per minute.
+This is independent of the speed
+that the individual characters are sent.
+If not specified, defaults to the effective value of the
+.Fl w
+option.
+.It Fl f Ar frequency
+Set the sidetone frequency to something other than the default 600 Hz.
+.It Fl d Ar device
+Similar to
+.Fl p ,
+but use the RTS line of
+.Ar device
+(which must by a TTY device)
+in order to emit the morse code.
+.It Fl e
+Echo each character before it is sent, used together with either
+.Fl p
+or
+.Fl d .
+.El
+.Pp
+The
+.Fl w , c
+and
+.Fl f
+flags only work in conjunction with either the
+.Fl p
+or the
+.Fl d
+flag.
+.Pp
+Not all prosigns have corresponding characters.
+Use
+.Ql #
+for
+.Em AS ,
+.Ql &
+for
+.Em SK ,
+.Ql *
+for
+.Em VE
+and
+.Ql %
+for
+.Em BK .
+The more common prosigns are
+.Ql =
+for
+.Em BT ,
+.Ql \&(
+for
+.Em KN
+and
+.Ql +
+for
+.Em AR .
+.Pp
+Using the
+.Fl d
+flag,
+it is possible to key an external device, like a sidetone generator with
+a headset for training purposes, or even your ham radio transceiver.
+For
+the latter, simply connect an NPN transistor to the serial port
+.Ar device ,
+emitter connected to ground, base connected through a resistor
+(few kiloohms) to RTS, collector to the key line of your transceiver
+(assuming the transceiver has a positive key supply voltage and is keyed
+by grounding the key input line).
+A capacitor (some nanofarads) between
+base and ground is advisable to keep stray RF away,
+and to suppress the
+minor glitch that is generated during program startup.
+.Sh ENVIRONMENT
+Your
+.Ev LC_CTYPE
+locale codeset determines how
+characters with the high-order bit set
+are interpreted.
+.Pp
+.Bl -tag -width ".Li ISO8859-15" -compact
+.It Li ISO8859-1
+.It Li ISO8859-15
+Interpret characters with the high-order bit set as Western European characters.
+.Pp
+.It Li KOI8-R
+Interpret characters with the high-order bit set as Cyrillic characters.
+.Pp
+.It Li ISO8859-7
+Interpret characters with the high-order bit set as Greek characters.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /dev/speaker" -compact
+.It Pa /dev/speaker
+.Xr speaker 4
+device file
+.El
+.Sh SEE ALSO
+.Xr speaker 4
+.Sh HISTORY
+Sound support for
+.Nm
+added by
+.An Lyndon Nerenberg (VE6BBM) Aq Mt lyndon@orthanc.ca .
+.Pp
+Ability to key an external device added by
+.An J\(:org Wunsch
+(DL8DTL).
+.Pp
+Farnsworth support for
+.Nm
+added by
+.An Stephen Cravey (N5UUU).
+.Sh BUGS
+Only understands a few European characters
+(German and French),
+no Asian characters,
+and no continental landline code.
+.Pp
+Sends a bit slower than it should due to system overhead.
+Some people would call this a feature.
diff --git a/usr.bin/morse/morse.c b/usr.bin/morse/morse.c
new file mode 100644
index 000000000000..03a09a6cb530
--- /dev/null
+++ b/usr.bin/morse/morse.c
@@ -0,0 +1,589 @@
+/*
+ * 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. 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 (VE6BBM)
+ * <lyndon@orthanc.ca>
+ */
+
+#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 <sys/time.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* Always use the speaker, let the open fail if -p is selected */
+#define SPEAKER "/dev/speaker"
+
+#ifdef SPEAKER
+#include <dev/speaker/speaker.h>
+#endif
+
+struct morsetab {
+ const char inchar;
+ const 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 */
+ {'@', ".--.-."}, /* AC */
+
+ /* prosigns without already assigned values */
+
+ {'#', ".-..."}, /* AS */
+ {'&', "...-.-"}, /* SK */
+ {'*', "...-."}, /* VE */
+ {'%', "-...-.-"}, /* BK */
+
+ {'\0', ""}
+};
+
+/*
+ * Code-points for some Latin1 chars in ISO-8859-1 encoding.
+ * UTF-8 encoded chars in the comments.
+ */
+static const struct morsetab iso8859_1tab[] = {
+ {'\340', ".--.-"}, /* à */
+ {'\341', ".--.-"}, /* á */
+ {'\342', ".--.-"}, /* â */
+ {'\344', ".-.-"}, /* ä */
+ {'\347', "-.-.."}, /* ç */
+ {'\350', "..-.."}, /* è */
+ {'\351', "..-.."}, /* é */
+ {'\352', "-..-."}, /* ê */
+ {'\366', "---."}, /* ö */
+ {'\374', "..--"}, /* ü */
+
+ {'\0', ""}
+};
+
+/*
+ * Code-points for some Greek chars in ISO-8859-7 encoding.
+ * UTF-8 encoded chars in the comments.
+ */
+static const struct morsetab iso8859_7tab[] = {
+ /*
+ * This table does not implement:
+ * - the special sequences for the seven diphthongs,
+ * - the punctuation differences.
+ * Implementing these features would introduce too many
+ * special-cases in the program's main loop.
+ * The diphthong sequences are:
+ * alpha iota .-.-
+ * alpha upsilon ..--
+ * epsilon upsilon ---.
+ * eta upsilon ...-
+ * omicron iota ---..
+ * omicron upsilon ..-
+ * upsilon iota .---
+ * The different punctuation symbols are:
+ * ; ..-.-
+ * ! --..--
+ */
+ {'\341', ".-"}, /* α, alpha */
+ {'\334', ".-"}, /* ά, alpha with acute */
+ {'\342', "-..."}, /* β, beta */
+ {'\343', "--."}, /* γ, gamma */
+ {'\344', "-.."}, /* δ, delta */
+ {'\345', "."}, /* ε, epsilon */
+ {'\335', "."}, /* έ, epsilon with acute */
+ {'\346', "--.."}, /* ζ, zeta */
+ {'\347', "...."}, /* η, eta */
+ {'\336', "...."}, /* ή, eta with acute */
+ {'\350', "-.-."}, /* θ, theta */
+ {'\351', ".."}, /* ι, iota */
+ {'\337', ".."}, /* ί, iota with acute */
+ {'\372', ".."}, /* ϊ, iota with diaeresis */
+ {'\300', ".."}, /* ΐ, iota with acute and diaeresis */
+ {'\352', "-.-"}, /* κ, kappa */
+ {'\353', ".-.."}, /* λ, lambda */
+ {'\354', "--"}, /* μ, mu */
+ {'\355', "-."}, /* ν, nu */
+ {'\356', "-..-"}, /* ξ, xi */
+ {'\357', "---"}, /* ο, omicron */
+ {'\374', "---"}, /* ό, omicron with acute */
+ {'\360', ".--."}, /* π, pi */
+ {'\361', ".-."}, /* ρ, rho */
+ {'\363', "..."}, /* σ, sigma */
+ {'\362', "..."}, /* ς, final sigma */
+ {'\364', "-"}, /* τ, tau */
+ {'\365', "-.--"}, /* υ, upsilon */
+ {'\375', "-.--"}, /* ύ, upsilon with acute */
+ {'\373', "-.--"}, /* ϋ, upsilon and diaeresis */
+ {'\340', "-.--"}, /* ΰ, upsilon with acute and diaeresis */
+ {'\366', "..-."}, /* φ, phi */
+ {'\367', "----"}, /* χ, chi */
+ {'\370', "--.-"}, /* ψ, psi */
+ {'\371', ".--"}, /* ω, omega */
+ {'\376', ".--"}, /* ώ, omega with acute */
+
+ {'\0', ""}
+};
+
+/*
+ * Code-points for the Cyrillic alphabet in KOI8-R encoding.
+ * UTF-8 encoded chars in the comments.
+ */
+static const struct morsetab koi8rtab[] = {
+ {'\301', ".-"}, /* а, a */
+ {'\302', "-..."}, /* б, be */
+ {'\327', ".--"}, /* в, ve */
+ {'\307', "--."}, /* г, ge */
+ {'\304', "-.."}, /* д, de */
+ {'\305', "."}, /* е, ye */
+ {'\243', "."}, /* ё, yo, the same as ye */
+ {'\326', "...-"}, /* ж, she */
+ {'\332', "--.."}, /* з, ze */
+ {'\311', ".."}, /* и, i */
+ {'\312', ".---"}, /* й, i kratkoye */
+ {'\313', "-.-"}, /* к, ka */
+ {'\314', ".-.."}, /* л, el */
+ {'\315', "--"}, /* м, em */
+ {'\316', "-."}, /* н, en */
+ {'\317', "---"}, /* о, o */
+ {'\320', ".--."}, /* п, pe */
+ {'\322', ".-."}, /* р, er */
+ {'\323', "..."}, /* с, es */
+ {'\324', "-"}, /* т, te */
+ {'\325', "..-"}, /* у, u */
+ {'\306', "..-."}, /* ф, ef */
+ {'\310', "...."}, /* х, kha */
+ {'\303', "-.-."}, /* ц, ce */
+ {'\336', "---."}, /* ч, che */
+ {'\333', "----"}, /* ш, sha */
+ {'\335', "--.-"}, /* щ, shcha */
+ {'\331', "-.--"}, /* ы, yi */
+ {'\330', "-..-"}, /* ь, myakhkij znak */
+ {'\334', "..-.."}, /* э, ae */
+ {'\300', "..--"}, /* ю, yu */
+ {'\321', ".-.-"}, /* я, ya */
+
+ {'\0', ""}
+};
+
+static void show(const char *), play(const char *), morse(char);
+static void ttyout(const char *);
+static void sighandler(int);
+
+#define GETOPTOPTS "c:d:ef:lsw:"
+#define USAGE \
+"usage: morse [-els] [-d device] [-w speed] [-c speed] [-f frequency] [string ...]\n"
+
+static int pflag, lflag, sflag, eflag;
+static int wpm = 20; /* effective words per minute */
+static int cpm; /* effective words per minute between
+ * characters */
+#define FREQUENCY 600
+static int freq = FREQUENCY;
+static char *device; /* for tty-controlled generator */
+
+#define DASH_LEN 3
+#define CHAR_SPACE 3
+#define WORD_SPACE (7 - CHAR_SPACE - 1)
+static float dot_clock;
+static float cdot_clock;
+static int spkr, line;
+static struct termios otty, ntty;
+static int olflags;
+
+#ifdef SPEAKER
+static tone_t sound;
+#undef GETOPTOPTS
+#define GETOPTOPTS "c:d:ef:lpsw:"
+#undef USAGE
+#define USAGE \
+"usage: morse [-elps] [-d device] [-w speed] [-c speed] [-f frequency] [string ...]\n"
+#endif
+
+static const struct morsetab *hightab;
+
+int
+main(int argc, char **argv)
+{
+ int ch, lflags;
+ char *p, *codeset;
+
+ while ((ch = getopt(argc, argv, GETOPTOPTS)) != -1)
+ switch ((char) ch) {
+ case 'c':
+ cpm = atoi(optarg);
+ break;
+ case 'd':
+ device = optarg;
+ break;
+ case 'e':
+ eflag = 1;
+ setvbuf(stdout, 0, _IONBF, 0);
+ break;
+ case 'f':
+ freq = atoi(optarg);
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+#ifdef SPEAKER
+ case 'p':
+ pflag = 1;
+ break;
+#endif
+ case 's':
+ sflag = 1;
+ break;
+ case 'w':
+ wpm = atoi(optarg);
+ break;
+ case '?':
+ default:
+ fputs(USAGE, stderr);
+ exit(1);
+ }
+ if (sflag && lflag) {
+ fputs("morse: only one of -l and -s allowed\n", stderr);
+ exit(1);
+ }
+ if ((pflag || device) && (sflag || lflag)) {
+ fputs("morse: only one of -p, -d and -l, -s allowed\n", stderr);
+ exit(1);
+ }
+ if (cpm == 0)
+ cpm = wpm;
+ if ((pflag || device) && ((wpm < 1) || (wpm > 60) || (cpm < 1) || (cpm > 60))) {
+ fputs("morse: insane speed\n", stderr);
+ exit(1);
+ }
+ if ((pflag || device) && (freq == 0))
+ freq = FREQUENCY;
+
+#ifdef SPEAKER
+ if (pflag) {
+ if ((spkr = open(SPEAKER, O_WRONLY, 0)) == -1) {
+ perror(SPEAKER);
+ exit(1);
+ }
+ } else
+#endif
+ if (device) {
+ if ((line = open(device, O_WRONLY | O_NONBLOCK)) == -1) {
+ perror("open tty line");
+ exit(1);
+ }
+ if (tcgetattr(line, &otty) == -1) {
+ perror("tcgetattr() failed");
+ exit(1);
+ }
+ ntty = otty;
+ ntty.c_cflag |= CLOCAL;
+ tcsetattr(line, TCSANOW, &ntty);
+ lflags = fcntl(line, F_GETFL);
+ lflags &= ~O_NONBLOCK;
+ fcntl(line, F_SETFL, &lflags);
+ ioctl(line, TIOCMGET, &lflags);
+ lflags &= ~TIOCM_RTS;
+ olflags = lflags;
+ ioctl(line, TIOCMSET, &lflags);
+ (void)signal(SIGHUP, sighandler);
+ (void)signal(SIGINT, sighandler);
+ (void)signal(SIGQUIT, sighandler);
+ (void)signal(SIGTERM, sighandler);
+ }
+ if (pflag || device) {
+ 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 */
+
+ cdot_clock = cpm / 2.4; /* dots/sec */
+ cdot_clock = 1 / cdot_clock; /* duration of a dot */
+ cdot_clock = cdot_clock / 2; /* dot_clock runs at twice */
+ /* the dot rate */
+ cdot_clock = cdot_clock * 100; /* scale for ioctl */
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (setlocale(LC_CTYPE, "") != NULL &&
+ *(codeset = nl_langinfo(CODESET)) != '\0') {
+ if (strcmp(codeset, "KOI8-R") == 0)
+ hightab = koi8rtab;
+ else if (strcmp(codeset, "ISO8859-1") == 0 ||
+ strcmp(codeset, "ISO8859-15") == 0)
+ hightab = iso8859_1tab;
+ else if (strcmp(codeset, "ISO8859-7") == 0)
+ hightab = iso8859_7tab;
+ }
+
+ if (lflag)
+ printf("m");
+ if (*argv) {
+ do {
+ for (p = *argv; *p; ++p) {
+ if (eflag)
+ putchar(*p);
+ morse(*p);
+ }
+ if (eflag)
+ putchar(' ');
+ morse(' ');
+ } while (*++argv);
+ } else {
+ while ((ch = getchar()) != EOF) {
+ if (eflag)
+ putchar(ch);
+ morse(ch);
+ }
+ }
+ if (device)
+ tcsetattr(line, TCSANOW, &otty);
+ exit(0);
+}
+
+static 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(" ");
+ else if (device)
+ ttyout(" ");
+ else if (lflag)
+ printf("\n");
+ else
+ show("");
+ return;
+ }
+ for (m = ((unsigned char)c < 0x80? mtab: hightab);
+ m != NULL && m->inchar != '\0';
+ m++) {
+ if (m->inchar == c) {
+ if (pflag) {
+ play(m->morse);
+ } else if (device) {
+ ttyout(m->morse);
+ } else
+ show(m->morse);
+ }
+ }
+}
+
+static void
+show(const char *s)
+{
+ if (lflag) {
+ printf("%s ", s);
+ } else if (sflag) {
+ printf(" %s\n", s);
+ } else {
+ for (; *s; ++s)
+ printf(" %s", *s == '.' ? *(s + 1) == '\0' ? "dit" :
+ "di" : "dah");
+ printf("\n");
+ }
+}
+
+static 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 = cdot_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 = cdot_clock * CHAR_SPACE;
+ ioctl(spkr, SPKRTONE, &sound);
+#endif
+}
+
+static void
+ttyout(const char *s)
+{
+ const char *c;
+ int duration, on, lflags;
+
+ for (c = s; *c != '\0'; c++) {
+ switch (*c) {
+ case '.':
+ on = 1;
+ duration = dot_clock;
+ break;
+ case '-':
+ on = 1;
+ duration = dot_clock * DASH_LEN;
+ break;
+ case ' ':
+ on = 0;
+ duration = cdot_clock * WORD_SPACE;
+ break;
+ default:
+ on = 0;
+ duration = 0;
+ }
+ if (on) {
+ ioctl(line, TIOCMGET, &lflags);
+ lflags |= TIOCM_RTS;
+ ioctl(line, TIOCMSET, &lflags);
+ }
+ duration *= 10000;
+ if (duration)
+ usleep(duration);
+ ioctl(line, TIOCMGET, &lflags);
+ lflags &= ~TIOCM_RTS;
+ ioctl(line, TIOCMSET, &lflags);
+ duration = dot_clock * 10000;
+ usleep(duration);
+ }
+ duration = cdot_clock * CHAR_SPACE * 10000;
+ usleep(duration);
+}
+
+static void
+sighandler(int signo)
+{
+
+ ioctl(line, TIOCMSET, &olflags);
+ tcsetattr(line, TCSANOW, &otty);
+
+ signal(signo, SIG_DFL);
+ (void)kill(getpid(), signo);
+}