aboutsummaryrefslogtreecommitdiff
path: root/tap
diff options
context:
space:
mode:
authorJon duSaint2022-04-30 16:16:25 -0700
committerJon duSaint2022-04-30 16:16:25 -0700
commit3160d814a1a088cfbcbd3c48c02d36273fd56383 (patch)
treeee703f562c870ee7ea675b8b682a48da2750ecfa /tap
parent659f12ede69726f46487d6e44aa79f48c2bd2aae (diff)

Commit a bunch of old software

Diffstat (limited to 'tap')
-rwxr-xr-xtap/BUGS0
-rwxr-xr-xtap/INSTALL0
-rwxr-xr-xtap/Makefile69
-rwxr-xr-xtap/NEWS0
-rwxr-xr-xtap/README8
-rwxr-xr-xtap/command_struct.h122
-rwxr-xr-xtap/commands/Makefile18
-rwxr-xr-xtap/commands/alias.c185
-rwxr-xr-xtap/commands/commands.h30
-rwxr-xr-xtap/commands/serial.c110
-rwxr-xr-xtap/commands/set.c315
-rwxr-xr-xtap/commands/translate.c431
-rwxr-xr-xtap/commands/user.c378
-rwxr-xr-xtap/memmgr.c257
-rwxr-xr-xtap/readline/Makefile38
-rwxr-xr-xtap/readline/history.c244
-rwxr-xr-xtap/readline/line.c340
-rwxr-xr-xtap/readline/readline.h243
-rwxr-xr-xtap/readline/ring.c114
-rwxr-xr-xtap/readline/tab.c530
-rwxr-xr-xtap/readline/text.c354
-rwxr-xr-xtap/serial.c87
-rwxr-xr-xtap/tap.c274
-rwxr-xr-xtap/tap.h370
-rwxr-xr-xtap/tap.texinfo826
-rwxr-xr-xtap/ui.c369
-rwxr-xr-xtap/version.h1
27 files changed, 5713 insertions, 0 deletions
diff --git a/tap/BUGS b/tap/BUGS
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/tap/BUGS
diff --git a/tap/INSTALL b/tap/INSTALL
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/tap/INSTALL
diff --git a/tap/Makefile b/tap/Makefile
new file mode 100755
index 0000000..4f993f3
--- /dev/null
+++ b/tap/Makefile
@@ -0,0 +1,69 @@
+# Makefile for Tap
+
+CC = gcc
+CFLAGS = -O2 -g -Wall
+LIBS = -lncurses
+
+TAP = tap
+
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+INFODIR = $(PREFIX)/info
+MANDIR = $(PREFIX)/man/man1
+DOCDIR = $(PREFIX)/doc/tap
+INSTALL-INFO = /sbin/install-info
+
+SRCFILES = memmgr.c serial.c tap.c ui.c
+HDRFILES = tap.h version.h command_struct.h
+OBJFILES = $(SRCFILES:%.c=%.o)
+
+READLINE = readline/readline.o
+READLINESRC = readline/*.c
+
+COMMANDS = commands/commands.o
+COMMANDSSRC = commands/*.c
+
+DOCEXTRAS = tap.cp tap.fn tap.ky tap.pg tap.tp tap.vr \
+ tap.aux tap.log tap.cps tap.toc
+DOCFILES = tap.dvi tap.ps tap.html tap.info
+
+
+.PHONY : all doc ps dvi info html install clean
+
+
+all : $(TAP)
+
+$(TAP) : $(READLINE) $(COMMANDS) $(SERIAL) $(OBJFILES) $(HDRFILES)
+ $(CC) $(CFLAGS) $(LIBS) -o $@ $(OBJFILES) $(READLINE) $(COMMANDS)
+
+$(READLINE) : $(READLINESRC)
+ make -C readline
+
+$(COMMANDS) : $(COMMANDSSRC)
+ make -C commands
+
+
+doc : tap.ps tap.html tap.info tap.texinfo
+
+ps : tap.ps
+dvi : tap.dvi
+info : tap.info
+html : tap.html
+
+tap.ps : tap.dvi tap.texinfo
+ dvips tap.dvi -o tap.ps
+tap.dvi : tap.texinfo
+ texi2dvi tap.texinfo
+tap.info : tap.texinfo
+ makeinfo tap.texinfo
+tap.html : tap.texinfo
+ makeinfo --html tap.texinfo
+
+
+install : tap info html
+
+
+clean :
+ make -C readline clean
+ make -C commands clean
+ rm -f $(OBJFILES) $(TAP) $(DOCFILES) $(DOCEXTRAS) core *~
diff --git a/tap/NEWS b/tap/NEWS
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/tap/NEWS
diff --git a/tap/README b/tap/README
new file mode 100755
index 0000000..6d9a9a8
--- /dev/null
+++ b/tap/README
@@ -0,0 +1,8 @@
+tap - a serial line tapper
+
+Started sometime around 17 July 1999.
+
+This is not an official release. Some sections of code aren't yet
+complete, and a lot hasn't been thoroughly tested. Also, although it
+should be totally portable (among Linuxes), it has only been tested on
+Linux/Alpha, so there might be some 64-bit-isms (though not likely).
diff --git a/tap/command_struct.h b/tap/command_struct.h
new file mode 100755
index 0000000..db9e0a6
--- /dev/null
+++ b/tap/command_struct.h
@@ -0,0 +1,122 @@
+/* command_struct.h
+ * This file contains all of the external commands for Tap.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+struct command commands[] = {
+ /* help */
+ { "help", help,
+ "unalias,set,quit,print,out,open,help,close,clear,capture,alias",
+ "print help for a function",
+ "help [function]\n \
+print a summary of functions or help for a specific function\n" },
+
+ /* set */
+ { "set", set, "of{ascii-cooked,ascii-raw,hex,oct,bin},"
+ "if{ascii-cooked,ascii-raw,hex,oct,bin},regsize{\\d},"
+ "mode{passive,active},echo{off,on},baud{\\d}",
+ "set various properties",
+ "set <properties> [values]\n \
+where properties are\n \
+if <bin|oct|hex|ascii-raw|ascii-cooked> - data entry format\n \
+In ascii-cooked mode, certain escapes are recognized:\n \
+\\a - 0x07 alert\n \
+\\b - 0x08 backspace\n \
+\\f - 0x0C form feed\n \
+\\n - 0x0A new line\n \
+\\r - 0x0D carriage return\n \
+\\v - 0x0B vertical tab\n \
+\\\\ - literal backslash\n \
+\\num - the character whose ASCII code is NUM (octal).\n \
+of <bin|oct|hex|ascii-raw|ascii-cooked> - data output format\n \
+The difference between ascii-raw and ascii-cooked is that cooked\n \
+mode converts non-printing characters to hexidecimal escape codes.\n \
+regsize <value> - the default register size in bytes\n \
+baud <value> - the speed of the port\n \
+echo <on|off> - whether or not terminal echo is on\n \
+mode <active|passive>\n \
+Active mode is default. In passive mode, more space is devoted\n \
+to the output window.\n" },
+
+ /* out */
+ { "out", out, "\\m",
+ "write data out to the serial port",
+ "out <data>\n \
+write data with the input format controlled by <set if> to the\n \
+serial port\n \
+see also <set> for a summary of input formats\n" },
+
+ /* quit */
+ { "quit", quit, "",
+ "quit the program",
+ "quit\n \
+quit the program\n" },
+
+ /* capture */
+ { "capture", capture, "register{\\m},file{\\f}",
+ "capture data from the serial port",
+ "capture <file|register> [file_name|register_number|off]\n \
+capture data from the serial port to a file, and continue\n \
+until the program is closed or <capture off> is entered\n \
+or to a register 1-64, and only capture <set regsize> bytes\n" },
+
+ /* open */
+ { "open", open_p, "\\f",
+ "open a serial device",
+ "open <serial port>\n \
+open a serial connection with <serial port>" },
+
+ /* close */
+ { "close", close_p, "",
+ "close a serial device",
+ "close\n \
+close the currently open serial connection\n" },
+
+ /* clear */
+ { "clear", clear_scr, "",
+ "clear the screen",
+ "clear\n \
+clear the screen\n" },
+
+ /* print */
+ { "print", print, "register{\\m{\\m}},file{\\f{\\m}}",
+ "print contents of a register or file",
+ "print <file|register> [file name|register number] [number of bytes]\n \
+print the contents of a file or a register\n \
+if n_bytes is specified print that many bytes\n" },
+
+ /* alias */
+ { "alias", make_alias, "\\m{\\c}",
+ "specify another name to use for a command",
+ "alias <new name> <command name>\n \
+assign an alias to <command name>\n" },
+
+ /* unalias */
+ { "unalias", unalias, "\\m",
+ "remove an alias",
+ "unalias <alias>\n \
+remove an alias from the alias list.\n" },
+
+ /* the end */
+ { NULL, NULL, NULL, NULL, NULL }
+};
diff --git a/tap/commands/Makefile b/tap/commands/Makefile
new file mode 100755
index 0000000..e265a19
--- /dev/null
+++ b/tap/commands/Makefile
@@ -0,0 +1,18 @@
+# makefile for commands
+
+CC = gcc
+CFLAGS = -Wall -g -O2 -I..
+
+SRCFILES = serial.c set.c user.c translate.c alias.c
+OBJFILES = $(SRCFILES:%.c=%.o)
+INCLUDEFILES = commands.h
+
+.PHONY : all clean
+
+all : commands.o
+
+commands.o : $(OBJFILES) $(INCLUDEFILES)
+ ld -r -o commands.o $(OBJFILES)
+
+clean :
+ rm -f commands.o $(OBJFILES) *~ core
diff --git a/tap/commands/alias.c b/tap/commands/alias.c
new file mode 100755
index 0000000..55d82ea
--- /dev/null
+++ b/tap/commands/alias.c
@@ -0,0 +1,185 @@
+/* commands/alias.c
+ * Implementation of the alias command.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "commands.h"
+
+struct alias_ {
+
+ /* the actual command name */
+ char *command;
+
+ /* the alias for the command */
+ char *alias;
+
+ /* the alias list is linked */
+ struct alias_ *next;
+};
+
+
+/* the alias list -- these are stored alphabetically
+ * as determined by strcmp ()
+ */
+struct alias_ *alias_list = NULL;
+
+
+/* If NAME is on the alias list, return the command to which it
+ * was aliased, otherwise just return NAME.
+ */
+char *
+resolve_alias (char *name)
+{
+ char *copy;
+ struct alias_ *current = alias_list;
+
+ while (current != NULL)
+ {
+ if (!strcmp (name, current->alias))
+ {
+ copy = xmalloc (strlen (current->command) + 1);
+ strcpy (copy, current->command);
+
+ return (copy);
+ }
+
+ current = current->next;
+ }
+
+ /* NAME isn't on the list */
+ return (name);
+}
+
+/* This command has three forms:
+ * alias
+ * will print all of the aliases
+ * alias foo
+ * will print what foo is the alias for
+ * alias foo bar
+ * will asign the name foo to the command bar
+ */
+int
+make_alias (char *line)
+{
+ char *alias, *command;
+ int len, next;
+ struct alias_ *current = alias_list, *prev = NULL;
+
+ alias = get_token (line, &next, &len);
+ command = get_token_only (line + next);
+
+ if (alias[0] == 0 && command[0] == 0)
+ { /* first form */
+ page_init ();
+
+ while (current != NULL)
+ {
+ wprintw (input_window, "%s -> %s\n",
+ current->alias, current->command);
+ current = current->next;
+
+ if (page_line_printed ()) break;
+ }
+ }
+ else if (command[0] == 0)
+ { /* second form */
+ command = resolve_alias (alias);
+
+ if (strcmp (alias, command))
+ { /* if alias != command */
+ wprintw (input_window, "%s -> %s\n", alias, command);
+ wrefresh (input_window);
+ }
+ }
+ else
+ {
+ /* search for the insertion point */
+ for (;;)
+ {
+ /* pointing at the end of the list */
+ if (current == NULL) break;
+
+ /* pointing to the insertion point */
+ if (strcmp (current->alias, alias) > 0) break;
+
+ /* the alias already exists */
+ if (strcmp (current->alias, alias) == 0)
+ {
+ inp_error ("alias already exists");
+ return (0);
+ }
+
+ prev = current;
+ current = current->next;
+ }
+
+ if (prev != NULL)
+ {
+ prev->next = xmalloc (sizeof (struct alias_));
+ prev->next->next = current;
+ prev->next->alias = alias;
+ prev->next->command = command;
+ }
+ else
+ { /* at the start of the list */
+ alias_list = xmalloc (sizeof (struct alias_));
+ alias_list->next = current;
+ alias_list->alias = alias;
+ alias_list->command = command;
+ }
+ }
+
+ return (0);
+}
+
+/* Remove an alias from the alias list. */
+int
+unalias (char *line)
+{
+ char *alias;
+ struct alias_ *current = alias_list, *prev = NULL;
+
+ alias = get_token_only (line);
+
+ while (current != NULL)
+ {
+ if (!strcmp (alias, current->alias))
+ {
+ if (prev == NULL) alias_list = current->next;
+ else prev->next = current->next;
+
+ xfree (current->alias);
+ xfree (current->command);
+ xfree (current);
+
+ return (0);
+ }
+
+ prev = current;
+ current = current->next;
+ }
+
+ inp_error ("alias not on list");
+
+ return (0);
+}
diff --git a/tap/commands/commands.h b/tap/commands/commands.h
new file mode 100755
index 0000000..653833d
--- /dev/null
+++ b/tap/commands/commands.h
@@ -0,0 +1,30 @@
+/* commands.h
+ * This is the main header file for the Commands modules of Tap. Which
+ * contains all of the user level commmands.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tap.h"
+
+/* needed by serial.c */
+#include <termios.h>
diff --git a/tap/commands/serial.c b/tap/commands/serial.c
new file mode 100755
index 0000000..15aaf3e
--- /dev/null
+++ b/tap/commands/serial.c
@@ -0,0 +1,110 @@
+/* serial.c
+ * functions specifically for the serial port
+ */
+
+#include "commands.h"
+
+/* global variables */
+
+/* file identifier for the serial port */
+
+int serial_port_fd;
+
+/* incoming serial data */
+
+char *serial_buffer = NULL;
+
+/* the size of the serial buffer */
+int serial_buffer_size = DEFAULT_MAXIMUM_ONE_TIME_SERIAL_DATA;
+
+/* Sends everything on the command line out to the serial port
+ * (if one is open) after any necessary translation.
+ */
+int
+out (char *line)
+{
+ char *outb = NULL;
+
+ if (port == NULL)
+ {
+ inp_error ("no serial port open");
+ return (0);
+ }
+
+ switch (input_format)
+ {
+ case BIN:
+ outb = translate_from_bin (line);
+ break;
+ case OCT:
+ outb = translate_from_oct (line);
+ break;
+ case HEX:
+ outb = translate_from_hex (line);
+ break;
+ case ASCII_RAW:
+ outb = translate_from_ascii_raw (line);
+ break;
+ case ASCII_COOKED:
+ outb = translate_from_ascii_cooked (line);
+ break;
+ }
+
+ if (outb == NULL) return (0);
+
+ /* write the whole line at once */
+ write (serial_port_fd, outb, strlen (outb));
+
+ xfree (outb);
+
+ return (0);
+}
+
+/* This opens a serial port for reading/writing. */
+int
+open_p (char *line)
+{
+ char *n_port;
+ struct termios tio;
+
+ if (port != NULL) {
+ inp_error("serial port already open");
+ return(0);
+ }
+
+ n_port = get_token_only (line);
+
+ serial_port_fd = open (n_port, O_RDWR | O_NONBLOCK | O_NOCTTY);
+ if (serial_port_fd == -1)
+ {
+ inp_error ("unable to open serial device");
+ return (0);
+ }
+
+ /* set to non-canonical and turn off echo */
+ tcgetattr (serial_port_fd, &tio);
+ tio.c_lflag &= ~ (ICANON | ECHO);
+ tcflush (serial_port_fd, TCIFLUSH);
+ tcsetattr (serial_port_fd, TCSANOW, &tio);
+
+ port = xmalloc (strlen (n_port)+1);
+ strcpy (port, n_port);
+
+ /* make sure that the serial buffer exists */
+ if (serial_buffer == NULL) serial_buffer = xmalloc (serial_buffer_size);
+
+ return (0);
+}
+
+/* This closes a serial port. */
+int
+close_p (char *line)
+{
+ if (port == NULL) return (0);
+
+ close (serial_port_fd);
+ xfree (port);
+ port = NULL;
+
+ return (0);
+}
diff --git a/tap/commands/set.c b/tap/commands/set.c
new file mode 100755
index 0000000..e4a3516
--- /dev/null
+++ b/tap/commands/set.c
@@ -0,0 +1,315 @@
+/* set.c
+ * set () and its helper functions
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "commands.h"
+
+/* control of active or passive mode */
+
+enum winmode { ACTIVE, PASSIVE } wmode = ACTIVE;
+
+/* the array of valid baud rates */
+
+struct baud_rates_ {
+ speed_t rate;
+ long speed;
+} baud_rates[] = {
+ { 0, -1 },
+ { B0, 0, }, /* this actually is not allowec */
+ { B50, 50 },
+ { B75, 75 },
+ { B110, 110 },
+ { B134, 134 },
+ { B150, 150 },
+ { B200, 200 },
+ { B300, 300 },
+ { B600, 600 },
+ { B1200, 1200 },
+ { B1800, 1800 },
+ { B2400, 2400 },
+ { B4800, 4800 },
+ { B9600, 9600 },
+ { B19200, 19200 },
+ { B38400, 38400 },
+ { B57600, 57600 },
+ { B115200, 115200 },
+ { B230400, 230400 },
+ { B460800, 460800 },
+ { B500000, 500000 },
+ { B576000, 576000 },
+ { B921600, 921600 },
+ { B1000000, 1000000 },
+ { B1152000, 1152000 },
+ { B1500000, 1500000 },
+ { B2000000, 2000000 },
+ { B2500000, 2500000 },
+ { B3000000, 3000000 },
+ { B3500000, 3500000 },
+ { B4000000, 4000000 },
+ { B4000000, 4000000 },
+ { 0, -1 }
+};
+
+/* This tests the validity of a baud rate and
+ * returns an index into the baud_rates array.
+ */
+int
+valid_baud_rate (long rate)
+{
+ int index;
+
+ for (index = 1; baud_rates[index].speed != -1; index++)
+ if (baud_rates[index].speed == rate) return (index);
+
+ /* invalid baud rate */
+ return (0);
+}
+
+/* This converts an internal representation of the baud rate (B??)
+ * into an actual number which can be printed out.
+ */
+long
+get_baud_rate (speed_t rate)
+{
+ struct baud_rates_ *ptr = baud_rates;
+
+ while ((++ptr)->speed != -1)
+ if (ptr->rate == rate) return (ptr->speed);
+
+ /* this should never be reached */
+ return (0);
+}
+
+/* These functions change modes. */
+
+void
+switch_to_active_mode (void)
+{
+ if (wmode == ACTIVE) return;
+
+ wmode = ACTIVE;
+ ui_expand_input_window ();
+}
+
+void
+switch_to_passive_mode (void)
+{
+ if (wmode == PASSIVE) return;
+
+ wmode = PASSIVE;
+ ui_shrink_input_window ();
+}
+
+/* The set command itself */
+int
+set (char *line)
+{
+ char *tok, *val;
+ int nxt = 0, cmd_len, pr_info = 0;
+
+ if (strlen (line) == 0)
+ {
+ inp_error ("nothing specified");
+ return (0);
+ }
+
+ tok = get_token (line, &nxt, &cmd_len);
+ val = get_token (line+nxt, &nxt, &cmd_len);
+
+ if (strlen (val) == 0) pr_info = 1;
+
+ if (!strcmp (tok, "if") || !strcmp (tok, "of"))
+ {
+ enum io_format tformat = (!strcmp (tok, "if"))
+ ? input_format : output_format;
+
+ if (pr_info)
+ {
+ switch (tformat)
+ {
+ case BIN:
+ val = "bin";
+ break;
+ case OCT:
+ val = "oct";
+ break;
+ case HEX:
+ val = "hex";
+ break;
+ case ASCII_RAW:
+ val = "ascii-raw";
+ break;
+ case ASCII_COOKED:
+ val = "ascii-cooked";
+ break;
+ }
+ }
+ else
+ {
+ if (!strcmp (val, "bin"))
+ tformat = BIN;
+ else if (!strcmp (val, "oct"))
+ tformat = OCT;
+ else if (!strcmp (val, "hex"))
+ tformat = HEX;
+ else if (!strcmp (val, "ascii-raw"))
+ tformat = ASCII_RAW;
+ else if (!strcmp (val, "ascii-cooked"))
+ tformat = ASCII_COOKED;
+ else
+ {
+ inp_error ("invalid value");
+ return (0);
+ }
+
+ if (!strcmp (tok, "if"))
+ input_format = tformat;
+ else
+ output_format = tformat;
+ }
+ }
+ else if (!strcmp (tok, "regsize"))
+ {
+ if (pr_info)
+ {
+ val = xmalloc (11);
+ sprintf (val, "%d", register_size);
+ }
+ else
+ {
+ long tval;
+
+ tval = strtol (val, NULL, 0);
+
+ if (tval < 1)
+ inp_error ("invalid value");
+ else
+ register_size = tval;
+ }
+ }
+ else if (!strcmp (tok, "echo"))
+ {
+ struct termios tio;
+
+ if (port == NULL)
+ {
+ inp_error ("no serial port open");
+ return (0);
+ }
+
+ tcdrain (serial_port_fd);
+ tcgetattr (serial_port_fd, &tio);
+
+ if (val[0] == 0)
+ {
+ pr_info = 1;
+ val = (tio.c_lflag & ECHO) ? "on" : "off";
+ }
+ else
+ {
+ if (!strcmp (val, "on"))
+ tio.c_lflag |= ECHO;
+ else if (!strcmp (val, "off"))
+ tio.c_lflag &= ~ECHO;
+ else
+ {
+ inp_error ("echo can only be on or off");
+ return (0);
+ }
+ tcsetattr (serial_port_fd, TCSANOW, &tio);
+ }
+ }
+ else if (!strcmp (tok, "baud"))
+ {
+ speed_t baud_rate;
+ struct termios tio;
+ long rate;
+
+ if (port == NULL)
+ {
+ inp_error ("no serial port open");
+ return (0);
+ }
+
+ tcdrain (serial_port_fd);
+ tcgetattr (serial_port_fd, &tio);
+
+ if (val[0] == 0)
+ {
+ xfree (val);
+ val = xmalloc (8); /* largest baud rate is 4000000 */
+
+ baud_rate = cfgetispeed (&tio);
+ rate = get_baud_rate (baud_rate);
+ if (rate != 134) /* the rate is actually 134.5 */
+ sprintf (val, "%ld", rate);
+ else
+ sprintf (val, "%4.1f", 134.5);
+ }
+ else
+ {
+ baud_rate = baud_rates[valid_baud_rate (strtol (val, NULL, 0))].rate;
+
+ if (!baud_rate || baud_rate == B0)
+ {
+ inp_error ("invalid baud rate");
+ return (0);
+ }
+
+ cfsetispeed (&tio, baud_rate);
+ cfsetospeed (&tio, baud_rate);
+ tcsetattr (serial_port_fd, TCSANOW, &tio);
+ }
+ }
+ else if (!strcmp (tok, "mode"))
+ {
+ if (val[0] == 0)
+ {
+ pr_info = 1;
+ val = (wmode == ACTIVE) ? "active" : "passive";
+ }
+ else if (!strcmp (val, "active"))
+ switch_to_active_mode ();
+ else if (!strcmp (val, "passive"))
+ switch_to_passive_mode ();
+ else
+ {
+ inp_error ("unknown mode");
+ return (0);
+ }
+ }
+ else
+ {
+ inp_error ("unknown property");
+ return (0);
+ }
+
+ if (pr_info)
+ wprintw (input_window, "%s = %s\n", tok, val);
+
+ xfree (tok);
+ if (!pr_info) xfree (val);
+
+ return (0);
+}
diff --git a/tap/commands/translate.c b/tap/commands/translate.c
new file mode 100755
index 0000000..34dc993
--- /dev/null
+++ b/tap/commands/translate.c
@@ -0,0 +1,431 @@
+/* translate.c
+ * functions which translate a string from one format into another
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* !!! WARNING !!!
+ * The contents of this file should not be viewed less than an
+ * hour after eating or in the presence of small children.
+ */
+
+#include "commands.h"
+
+#define TOUP(ch) (isalpha (ch) ? toupper (ch) : (ch))
+
+/* Check that a user-entered string is valid for the given mode. If
+ * STRING has characters which aren't in VALID, returns 1.
+ */
+int
+check_validity (char *string, char *valid)
+{
+ char *tptr;
+
+ string--;
+ while (*(++string))
+ {
+ tptr = valid - 1;
+ while (*(++tptr)) if (*string == *tptr) goto NO_ERROR;
+ return (1);
+ NO_ERROR:
+ ;
+ }
+
+ return (0);
+}
+
+/* translate_from_?? translates user input from ?? into usable format
+ * to be written out of the serial port.
+ */
+
+char *
+translate_from_bin (char *input)
+{
+ unsigned char *output;
+ long byte, bit, length = strlen (input)/8, diff;
+
+ if (check_validity (input, "01"))
+ {
+ inp_error ("invalid_character");
+ return (NULL);
+ }
+
+ output = xmalloc (length + 2);
+ memset (output, 0, length + 2);
+
+ for (byte = 0; byte < length; byte++)
+ {
+ for (bit = 0; bit < 8; bit++)
+ {
+ output[byte] ^=
+ ((unsigned char) ((input[byte*8 + bit] == '1') ? 1 : 0)) << (7 - bit);
+ }
+ }
+
+ diff = strlen (input) - length*8;
+
+ if (diff)
+ {
+ for (bit = 0; bit < diff; bit++)
+ {
+ output[byte] ^=
+ ((unsigned char)((input[byte*8 + bit] == '1') ? 1 : 0)) << (7 - bit);
+ }
+ }
+
+ return (output);
+}
+
+char *
+translate_from_oct (char *input)
+{
+ unsigned char *output = NULL;
+ int length = (strlen (input) * 3) / 8 + 1, k;
+
+ if (check_validity (input, "01234567"))
+ {
+ inp_error ("invalid_character");
+ return (NULL);
+ }
+
+ output = xmalloc (length + 1);
+ memset (output, 0, length + 1);
+
+ for (k = 0; k < strlen (input) / 8; k++)
+ {
+ output[k*3] = ((input[k*8] << 5) & 0xE0)
+ | ((input[k*8+1] << 2) & 0x1C)
+ | ((input[k*8+2] >> 1) & 0x03);
+ output[k*3+1] = ((input[k*8+2] << 7) & 0x80)
+ | ((input[k*8+3] << 4) & 0x70)
+ | ((input[k*8+4] << 1) & 0x0E)
+ | ((input[k*8+5] >> 2) & 0x01);
+ output[k*3+2] = ((input[k*8+5] << 6) & 0xC0)
+ | ((input[k*8+6] << 3) & 0x38)
+ | (input[k+8+7] & 0x07);
+ }
+
+ /* take care of trailers */
+ switch (strlen (input) % 8)
+ {
+ case 7:
+ output[k*3+2] = (input[k*8+6] << 3) & 0x38;
+ case 6:
+ output[k*3+2] |= (input[k*8+5] << 6) & 0xC0;
+ output[k*3+1] = (input[k*8+5] >> 2) & 0x01;
+ case 5:
+ output[k*3+1] |= (input[k*8+4] << 1) & 0x0E;
+ case 4:
+ output[k*3+1] |= (input[k*8+3] << 4) & 0x70;
+ case 3:
+ output[k*3+1] |= (input[k*8+2] << 7) & 0x80;
+ output[k*3] = (input[k*8+2] >> 1) & 0x03;
+ case 2:
+ output[k*3] |= (input[k*8+1] << 2) & 0x1C;
+ case 1:
+ output[k*3] |= (input[k*8] << 5) & 0xE0;
+ default:
+ }
+
+ return (output);
+}
+
+char *
+translate_from_hex (char *input)
+{
+ unsigned char *output = NULL;
+ int length = strlen (input) / 2, k;
+ char translate_table[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* placeholders */
+ 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+ };
+
+ if (check_validity (input, "0123456789ABCDEFabcdef"))
+ {
+ inp_error ("invalid_character");
+ return (NULL);
+ }
+
+ output = xmalloc (length + 1);
+ memset (output, 0, length + 1);
+
+ for (k = 0; k < length; k++)
+ {
+ output[k] = (translate_table[TOUP (input[k*2]) - '0'] << 4)
+ | translate_table[TOUP (input[k*2+1]) - '0'];
+ }
+
+ return (output);
+}
+
+char *
+translate_from_ascii_raw (char *input)
+{
+ char *output;
+
+ output = xmalloc (strlen (input) + 1);
+ memcpy (output, input, strlen (input) + 1);
+
+ return (output);
+}
+
+char *
+translate_from_ascii_cooked (char *input)
+{
+ char *output;
+ int amt = 0;
+
+ output = xmalloc (strlen (input) + 1);
+ memset (output, 0, strlen (input) + 1);
+
+ for (--input; * (++input); amt++)
+ {
+ if (*input == '\\')
+ {
+ switch (* (++input))
+ {
+ case 'a':
+ output[amt] = 0x07;
+ break;
+ case 'b':
+ output[amt] = 0x08;
+ break;
+ case 'f':
+ output[amt] = 0x0C;
+ break;
+ case 'n':
+ output[amt] = 0x0A;
+ break;
+ case 'r':
+ output[amt] = 0x0D;
+ break;
+ case 'v':
+ output[amt] = 0x0B;
+ break;
+ case '\\':
+ output[amt] = '\\';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ unsigned char val = 0;
+
+ val = *input & 0x07;
+ input++;
+ if (*input <= '7' && *input >= '0')
+ {
+ val <<= 3;
+ val |= *input & 0x07;
+
+ input++;
+ if (*input <= '7' && *input >= '0')
+ {
+ val <<= 3;
+ val |= *input & 0x07;
+ }
+ else
+ input--;
+ }
+ else
+ input--;
+
+ output[amt] = val;
+ }
+ break;
+ default:
+ inp_error ("invalid escape code");
+ xfree (output);
+ return (NULL);
+ }
+ }
+ else
+ {
+ output[amt] = *input;
+ }
+ }
+
+ return (output);
+}
+
+/* translate_to_?? () takes input from the serial port and translates
+ * it into the format ?? for display in OUTPUT_WINDOW.
+ */
+
+char *
+translate_to_bin (char *input)
+{
+ char *output;
+ int current, offset;
+
+ output = xmalloc (8 * strlen (input) + 1);
+
+ for (current = 0; current < strlen (input); current++)
+ {
+ for (offset = 0; offset < 8; offset++)
+ output[8 * current + offset] =
+ (input[current] & (0x01 << (7 - offset))) ? '1' : '0';
+ }
+
+ output[8 * strlen (input)] = '\0';
+
+ return (output);
+}
+
+char *
+translate_to_oct (char *input)
+{
+ char *output = NULL;
+ int length = (strlen (input) * 8) / 3 + 1, k;
+ char translate_table[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7'
+ };
+
+ output = xmalloc (length + 1);
+
+ memset (output, 0, length + 1);
+
+ /* convert 3 bytes of input at a time */
+ for (k = 0; k < strlen (input) / 3; k++)
+ {
+ output[k*8] = translate_table[ (input[k*3] & 0xE0) >> 5];
+ output[k*8+1] = translate_table[ (input[k*3] & 0x1C) >> 2];
+ output[k*8+2] = translate_table[ ((input[k*3] & 0x03) << 1) | ((input[k*3+1] & 0x80) >> 7)];
+ output[k*8+3] = translate_table[ (input[k*3+1] & 0x70) >> 4];
+ output[k*8+4] = translate_table[ (input[k*3+1] & 0x0E) >> 1];
+ output[k*8+5] = translate_table[ ((input[k*3+1] & 0x01) << 2) | ((input[k*3+2] & 0xC0) >> 6)];
+ output[k*8+6] = translate_table[ (input[k*3+2] & 0x38) >> 3];
+ output[k*8+7] = translate_table[input[k*3+2] & 0x07];
+ }
+
+ /* handle any trailers -- ugly, yeah, but it works... */
+ switch (strlen (input) % 3)
+ {
+ case 2: /* 6 additional */
+ output[k*8+3] = translate_table[ (input[k*3+1] & 0x70) >> 4];
+ output[k*8+4] = translate_table[ (input[k*3+1] & 0x0E) >> 1];
+ output[k*8+5] = translate_table[ ((input[k*3+1] & 0x01) << 2)
+ | ((input[k*3+2] & 0xC0) >> 6)];
+ /* fall through */
+ case 1: /* 3 additional */
+ output[k*8] = translate_table[ (input[k*3] & 0xE0) >> 5];
+ output[k*8+1] = translate_table[ (input[k*3] & 0x1C) >> 2];
+ output[k*8+2] = translate_table[ ((input[k*3] & 0x03) << 1)
+ | ((input[k*3+1] & 0x80) >> 7)];
+ }
+
+ return (output);
+}
+
+char *
+translate_to_hex (char *input)
+{
+ char *output;
+ char hex_table[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ long k, length = strlen (input)*2;
+
+ output = xmalloc (length + 1);
+ memset (output, 0, length + 1);
+
+ for (k = 0; k < length/2; k++)
+ {
+ output[2 * k] = hex_table[ (input[k] >> 4) & 0x0F];
+ output[2 * k + 1] = hex_table[input[k] & 0x0F];
+ }
+
+ return (output);
+}
+
+char *
+translate_to_ascii_raw (char *input)
+{
+ char *output;
+
+ output = xmalloc (strlen (input) + 1);
+ memcpy (output, input, strlen (input) + 1);
+
+ return (output);
+}
+
+/* This is a helper function for translate_to_ascii_cooked(). */
+void
+add_character (char **pstring, char ch)
+{
+ static int buffer_size = 0, chars_in_buffer = 0;
+
+ if (pstring == NULL)
+ {
+ buffer_size = chars_in_buffer = 0;
+ return;
+ }
+
+ if (chars_in_buffer == buffer_size)
+ {
+ char *temp;
+
+ buffer_size += GROW_SIZE;
+ temp = xrealloc (*pstring, buffer_size);
+
+ *pstring = temp;
+ }
+
+ (*pstring)[chars_in_buffer] = ch;
+ chars_in_buffer++;
+}
+
+#define not_escaped(ch) (isalnum (ch) || ispunct (ch) || isspace (ch))
+
+char *
+translate_to_ascii_cooked (char *input)
+{
+ char *output, hex_table[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ /* initialize */
+ add_character (NULL, 0);
+ output = xmalloc (0);
+
+ for (--input; *(++input);)
+ {
+ if (not_escaped (*input)) add_character (&output, *input);
+ else
+ {
+ add_character (&output, '<');
+ add_character (&output, hex_table[(*input >> 4) & 0x0F]);
+ add_character (&output, hex_table[*input & 0x0F]);
+ add_character (&output, '>');
+ }
+ }
+
+ add_character (&output, '\0');
+
+ return (output);
+}
diff --git a/tap/commands/user.c b/tap/commands/user.c
new file mode 100755
index 0000000..14a6969
--- /dev/null
+++ b/tap/commands/user.c
@@ -0,0 +1,378 @@
+/* commands/user.c
+ * User support functions
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "commands.h"
+
+/* the current register number */
+
+int capture_register = 0;
+
+/* the file to capture to */
+
+FILE *capture_fid = NULL;
+
+/* the name of that file */
+
+char *capture_fname = NULL;
+
+
+/* Get help on a command. */
+int
+help (char *line)
+{
+ char *cmd;
+ int current = 0;
+
+ page_init ();
+
+ if (strlen (line) == 0)
+ {
+ /* print help on all of the topics */
+ while (commands[current].name != NULL)
+ {
+ wprintw (input_window, "%-*s: %s\n", MAXIMUM_COMMAND_SIZE,
+ commands[current].name, commands[current].blurb_help);
+ current++;
+
+ if (page_line_printed ()) break;
+ }
+ }
+ else
+ {
+ /* help on a selected topic */
+ cmd = get_token_only (line);
+ if (cmd == NULL) return (0);
+
+ while (commands[current].name != NULL)
+ {
+ if (!strcmp (commands[current].name, cmd))
+ {
+ wprintstr (input_window, commands[current].full_help);
+ return (0);
+ }
+ current++;
+ }
+
+ inp_error ("unknown command");
+ }
+
+ return (0);
+}
+
+/* Quit the program. */
+int
+quit (char *line)
+{
+ return (1);
+}
+
+/* Write incoming data to a register without translating. */
+void
+write_to_capture_register (int how_much)
+{
+ if (capture_register == 0) return;
+
+ if (how_much > registers[capture_register].size
+ - registers[capture_register].offset)
+ how_much = registers[capture_register].size
+ - registers[capture_register].offset;
+
+ memcpy (registers[capture_register].data
+ + registers[capture_register].offset, serial_buffer, how_much);
+ registers[capture_register].offset += how_much;
+
+ /* if the register is full, stop capturing */
+ if (registers[capture_register].offset == registers[capture_register].size)
+ capture_register = 0;
+}
+
+/* Write incoming data to a file without translating. */
+void
+write_to_capture_file (int how_much)
+{
+ if (capture_fid == NULL) return;
+
+ fwrite (serial_buffer, how_much, sizeof (char), capture_fid);
+}
+
+/* This function turns capturing on and off for registers and
+ * files.
+ */
+int
+capture (char *line)
+{
+ char *where, *name;
+ int next, len;
+
+ where = get_token (line, &next, &len);
+ name = get_token_only (line + next);
+
+ if (!strcmp (where, "file"))
+ {
+ if (name[0] == 0)
+ {
+ if (capture_fname != NULL)
+ wprintw (input_window, "%s\n", capture_fname);
+ return (0);
+ }
+
+ if (!strcmp (name, "off"))
+ {
+ if (capture_fid != NULL)
+ {
+ fclose (capture_fid);
+ capture_fid = NULL;
+
+ xfree (capture_fname);
+ capture_fname = NULL;
+ }
+ return (0);
+ }
+
+ if (capture_fid != NULL)
+ {
+ inp_error ("already capturing to a file");
+ return (0);
+ }
+
+ name = tilde_expand (name);
+
+ capture_fid = fopen (name, "a+b");
+
+ if (capture_fid == NULL)
+ {
+ xfree (name);
+
+ inp_error ("unable to open file for capture");
+ return (0);
+ }
+
+ capture_fname = name;
+
+ }
+ else if (!strcmp (where, "register"))
+ {
+ if (name[0] == 0)
+ {
+ if (capture_register != 0)
+ wprintw (input_window, "%d\n", capture_register);
+ return (0);
+ }
+
+ if (!strcmp (name, "off"))
+ {
+ registers[capture_register].size
+ = registers[capture_register].offset;
+ registers[capture_register].offset = 0;
+
+ capture_register = 0;
+ return (0);
+ }
+
+ /* if one is already in use, close it */
+ if (capture_register != 0)
+ {
+ registers[capture_register].size
+ = registers[capture_register].offset;
+ registers[capture_register].offset = 0;
+ }
+
+ capture_register = strtol (name, NULL, 0);
+
+ if (capture_register < 1 || capture_register > MAX_REGISTERS)
+ {
+ inp_error ("invalid register number");
+ capture_register = 0;
+ return (0);
+ }
+
+ if (registers[capture_register].data != (void *)0)
+ xfree (registers[capture_register].data);
+
+ registers[capture_register].size = register_size;
+ registers[capture_register].offset = 0;
+ registers[capture_register].data = xmalloc (register_size);
+
+ }
+ else
+ inp_error ("invalid capture location");
+
+ return (0);
+}
+
+/* This function prints the contents of a file with
+ * translation. Use is made of the serial buffer.
+ */
+void
+print_file (FILE *fid, long data_printed)
+{
+ long amount_read = 0;
+ long amount_to_read = serial_buffer_size;
+
+ if (serial_buffer == NULL) serial_buffer = xmalloc (serial_buffer_size);
+
+ if (data_printed != -1)
+ amount_to_read = MIN (serial_buffer_size, data_printed);
+
+ for (;;)
+ {
+ amount_read = fread (serial_buffer, amount_to_read, sizeof (char), fid);
+
+ if (amount_read == 0) break;
+
+ write_to_output_window (amount_to_read);
+
+ if (data_printed != -1)
+ {
+ data_printed -= amount_to_read;
+ amount_to_read = MIN (serial_buffer_size, data_printed);
+
+ if (amount_to_read == 0) break;
+ }
+ }
+}
+
+/* This function prints the contents of a file
+ * or a register.
+ */
+int
+print (char *line)
+{
+ int next, len, pr_register;
+ long amount, printed = 0, amount_to_print;
+ char *what, *where, *size;
+ FILE *fid;
+
+ what = get_token (line, &next, &len);
+ line += next;
+ where = get_token (line, &next, &len);
+ size = get_token_only (line+next);
+
+ if (size[0] == 0)
+ amount = -1;
+ else
+ {
+ amount = strtol (size, NULL, 0);
+ if (amount == 0)
+ amount = -1;
+ }
+
+ if (!strcmp (what, "file"))
+ {
+ if (where[0] == 0)
+ {
+ if (capture_fname == NULL)
+ inp_error ("no open capture file");
+ else
+ {
+ rewind (capture_fid);
+ print_file (capture_fid, -1);
+ fseek (capture_fid, 0, SEEK_END);
+ }
+
+ return (0);
+ }
+
+ if (capture_fname != NULL)
+ {
+ if (!strcmp (where, "current") || !strcmp (where, capture_fname))
+ {
+ rewind (capture_fid);
+ print_file (capture_fid, amount);
+ fseek (capture_fid, 0, SEEK_END);
+
+ return (0);
+ }
+ }
+
+ fid = fopen (where, "rb");
+ if (fid == NULL)
+ {
+ inp_error ("unable to open file");
+ return (0);
+ }
+
+ print_file (fid, amount);
+
+ fclose (fid);
+
+ }
+ else if (!strcmp (what, "register"))
+ {
+ if (where[0] == 0)
+ {
+ if (capture_register == 0)
+ {
+ inp_error ("no register specified");
+ return (0);
+ }
+ pr_register = capture_register;
+ }
+ else
+ {
+ pr_register = strtol (where, NULL, 0);
+
+ if (pr_register < 1 || pr_register > MAX_REGISTERS)
+ {
+ inp_error ("invalid register");
+ return (0);
+ }
+ }
+
+ /* if the register is empty */
+ if (registers[pr_register].data == (void *)0) return (0);
+
+ /* print until there is no more data */
+ if (amount == -1) amount = registers[pr_register].size;
+
+ for (;;)
+ {
+ amount_to_print = MIN (serial_buffer_size, amount);
+
+ memcpy (serial_buffer, registers[pr_register].data+printed,
+ amount_to_print);
+
+ write_to_output_window (amount_to_print);
+
+ printed += amount_to_print;
+ if (printed >= amount) break;
+ }
+ }
+ else
+ inp_error ("nothing specified");
+
+ return (0);
+}
+
+/* Clear the input window. */
+int
+clear_scr (char *line)
+{
+ werase (input_window);
+ wmove (input_window, 0, 0);
+ wrefresh (input_window);
+
+ return (0);
+}
diff --git a/tap/memmgr.c b/tap/memmgr.c
new file mode 100755
index 0000000..04b0e49
--- /dev/null
+++ b/tap/memmgr.c
@@ -0,0 +1,257 @@
+/* memmgr.c
+ * This is the memory manager for Tap. The visible functions are
+ * xmalloc - allocate a block of memory
+ * xrealloc - change the size of a block of memory
+ * xfree - free a block of memory
+ * free_alloc_list - called at exit to free all memory
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tap.h"
+
+/* minimum size block to allocate */
+
+#define MIN_ALLOC 8
+
+
+/* the alloc / free list */
+
+struct memory_block *alloc_list = NULL;
+
+/* the total available slots (the size of the alloc list) */
+
+long number_of_blocks = 0;
+
+/* the number of blocks that have been filled */
+
+long block_pointers_allocated = 0;
+
+
+/* This is called if malloc or realloc return NULL
+ *
+ * Give the user a choice to continue (and possibly
+ * close other memory-intensive applications) or to
+ * just exit. If this gets called more than
+ * MAX_TIMES_OUT_OF_MEMORY then just abort.
+ */
+void
+out_of_memory (void)
+{
+ char key;
+ static int times_out_of_memory = 0;
+
+ if (times_out_of_memory > MAX_TIMES_OUT_OF_MEMORY)
+ {
+ fprintf (stderr, "%s: virtual memory exhausted\n", pname);
+ abort ();
+ }
+
+ waddstr (input_window, "!! out of virtual memory !!\n\
+press <c> to attempt to continue (and possibly close other applications)\n\
+or any other key to abort: ");
+
+ /* don't use sgetch () here */
+ key = wgetch (input_window);
+
+ if (tolower (key) == 'c')
+ {
+ times_out_of_memory++;
+ longjmp (start_of_input_loop, 1);
+ }
+
+ abort ();
+}
+
+/* This is passed a pointer to memory (the same as passed to xrealloc
+ * or xfree). If it isn't found on the alloc list (using the mark)
+ * then abort is called.
+ */
+long
+get_block_index (void *mem)
+{
+ long mark;
+
+ /* in other words, mark = (long) mem[-MARK_SIZE] */
+ mark = ((long)* ((long *) ((mem) - MARK_SIZE)));
+
+ /* just check that it's somewhere on the list */
+ if (mark < block_pointers_allocated) return (mark);
+
+ /* this should never be reached */
+ fprintf (stderr,
+ "\n\r%s: tried to free or realloc block not on alloc list\n\r\
+block index %ld\n\r", pname, mark);
+ abort ();
+
+}
+
+/* Search for an unused block of memory with
+ * size >= min_size. If nothing is found return -1 otherwise
+ * return the index of a suitable block.
+ */
+long
+find_free_block (size_t min_size)
+{
+ long index;
+
+ /* scan through the whole list */
+ for (index = 0; index < block_pointers_allocated; index++)
+ {
+ if (alloc_list[index].in_use == FREE)
+ {
+ if (alloc_list[index].size >= min_size) return (index); /* got one */
+ }
+ }
+
+ /* nothing */
+ return (-1);
+}
+
+/* This function acts just like malloc except for using the
+ * alloc list to keep track of used and unused memory and
+ * checking for errors.
+ */
+void *
+xmalloc (size_t how_much)
+{
+ long block_index;
+
+ /* try to find a suitable block */
+ block_index = find_free_block (how_much);
+
+ if (block_index == -1)
+ { /* nothing found */
+
+ /* if the alloc list needs to be expanded */
+ if (block_pointers_allocated == number_of_blocks)
+ {
+ struct memory_block *temp;
+
+ temp = realloc (alloc_list, sizeof (struct memory_block)
+ * (number_of_blocks + GROW_SIZE));
+
+ if (temp == NULL) out_of_memory ();
+
+ alloc_list = temp;
+ number_of_blocks += GROW_SIZE;
+ }
+
+ /* now allocate a new block */
+
+ block_index = block_pointers_allocated;
+
+ block_pointers_allocated++;
+
+ alloc_list[block_index].memory = malloc ((how_much < MIN_ALLOC
+ ? MIN_ALLOC : how_much)
+ + MARK_SIZE);
+ if (alloc_list[block_index].memory == NULL) out_of_memory ();
+
+ alloc_list[block_index].size = (how_much < MIN_ALLOC)
+ ? MIN_ALLOC : how_much;
+
+ /* mark the block with the index */
+ * ((long *)alloc_list[block_index].memory) = block_index;
+ }
+
+ alloc_list[block_index].in_use = USED;
+ alloc_list[block_index].size_used = how_much;
+
+ return (alloc_list[block_index].memory + MARK_SIZE);
+}
+
+/* This function is just like realloc except that it uses the
+ * alloc list and checks the validity of realloc'ed memory.
+ */
+void *
+xrealloc (void *mem, size_t how_much)
+{
+ long index, orig_index;
+ void *new;
+
+ orig_index = get_block_index (mem);
+
+ /* first check if the block is already big enough */
+ if (alloc_list[orig_index].size >= how_much)
+ {
+ alloc_list[orig_index].size_used = how_much;
+ return (mem);
+ }
+
+ /* not big enough - try to find another one */
+
+ /* scan the alloc list */
+ for (index = 0; index < block_pointers_allocated; index++)
+ {
+ if (alloc_list[index].in_use == FREE)
+ {
+ if (alloc_list[index].size >= how_much)
+ {
+ /* found suitable block */
+ memcpy (alloc_list[index].memory + MARK_SIZE,
+ alloc_list[orig_index].memory + MARK_SIZE,
+ alloc_list[orig_index].size_used);
+
+ alloc_list[index].in_use = USED;
+ alloc_list[orig_index].in_use = FREE;
+
+ return (alloc_list[index].memory + MARK_SIZE);
+ }
+ }
+ }
+
+ /* have to actually realloc */
+ new = realloc (alloc_list[orig_index].memory, how_much + MARK_SIZE);
+
+ if (new == NULL) out_of_memory ();
+
+ alloc_list[orig_index].memory = new;
+
+ alloc_list[orig_index].size = how_much;
+ alloc_list[orig_index].size_used = how_much;
+
+ return (alloc_list[orig_index].memory + MARK_SIZE);
+}
+
+/* This function acts just like free except that it uses the alloc list. */
+void
+xfree (void *mem)
+{
+ long index;
+
+ index = get_block_index (mem);
+
+ alloc_list[index].in_use = FREE;
+}
+
+/* This is called at exit and it frees every block of memory allocated. */
+void
+free_alloc_list (void)
+{
+ long index;
+
+ for (index = 0; index < block_pointers_allocated; index++)
+ free (alloc_list[index].memory);
+
+ free (alloc_list);
+}
diff --git a/tap/readline/Makefile b/tap/readline/Makefile
new file mode 100755
index 0000000..a83987c
--- /dev/null
+++ b/tap/readline/Makefile
@@ -0,0 +1,38 @@
+# makefile for the Readline module of Tap.
+# Copyright (C) 1999 Jonathan duSaint
+#
+# This file is part of Tap, an interactive program for reading and
+# writing data to the serial port to facilitate the reverse
+# engineering of communication protocols.
+#
+# Tap is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# Tap is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+# License for more details.
+#
+# The GNU General Public License is generally kept in a file called
+# COPYING or LICENSE. If you do not have a copy of the license, write
+# to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+CC = gcc
+CFLAGS = -Wall -g -O2 -I..
+
+SRCFILES = history.c line.c ring.c tab.c text.c
+OBJFILES = $(SRCFILES:%.c=%.o)
+INCLUDEFILES = readline.h
+
+.PHONY : all clean
+
+all : readline.o
+
+readline.o : $(OBJFILES) $(INCLUDEFILES)
+ ld -r -o readline.o $(OBJFILES)
+
+clean :
+ rm -f readline.o $(OBJFILES) *~ core
diff --git a/tap/readline/history.c b/tap/readline/history.c
new file mode 100755
index 0000000..a833e1a
--- /dev/null
+++ b/tap/readline/history.c
@@ -0,0 +1,244 @@
+/* history.c
+ * Part of the Readline module for Tap. This is a simpler
+ * implementation of the GNU History library.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "readline.h"
+
+/* the history list itself
+ * The first node is not dynamically allocated. That way, no
+ * initialization function needs to be called.
+ */
+
+struct history_node the_history_list = { NULL, NULL, NULL, NULL };
+
+
+/* pointers into the history list */
+
+/* the last item in the history list */
+
+struct history_node *last_history = &the_history_list;
+
+/* the current item when the list is being traversed */
+
+struct history_node *current_history = &the_history_list;
+
+
+/* the most current line (which isn't itself on the history list) */
+
+char *saved_line = NULL;
+
+
+/* Get the next entry on the history list. If there isn't another node,
+ * return the saved line, or if that is the current line, return NULL.
+ */
+char *
+next_history (void)
+{
+ char *line_to_return;
+
+ /* already at the last entry */
+ if (current_history == last_history)
+ line_to_return = NULL;
+ else
+ {
+ current_history = current_history->next;
+
+ /* at the last entry, but still not on the most current line */
+ if (current_history == last_history)
+ {
+ line_to_return = saved_line;
+ saved_line = NULL;
+ }
+ else
+ {
+ /* (re)allocate scratch area if necessary */
+ if (current_history->saved_data == NULL)
+ {
+ current_history->saved_data =
+ xmalloc (ROUND_UP_SIZE (strlen (current_history->data)));
+
+ strcpy (current_history->saved_data, current_history->data);
+ }
+
+ line_to_return = current_history->saved_data;
+ }
+ }
+
+ return (line_to_return);
+}
+
+/* Get the previous line on the history list. If the current node is
+ * the first one, return NULL.
+ */
+char *
+prev_history (void)
+{
+ char *line_to_return;
+
+ /* at the oldest entry already */
+ if (current_history == &the_history_list)
+ line_to_return = NULL;
+ else
+ {
+ /* about to start traversing the list proper --
+ * need to save the most recent line
+ */
+ if (current_history == last_history)
+ saved_line = current_line;
+
+ current_history = current_history->prev;
+
+ /* (re)allocate scratch area if necessary */
+ if (current_history->saved_data == NULL)
+ {
+ current_history->saved_data =
+ xmalloc (ROUND_UP_SIZE (strlen (current_history->data)));
+
+ strcpy (current_history->saved_data, current_history->data);
+ }
+
+ line_to_return = current_history->saved_data;
+ }
+
+ return (line_to_return);
+}
+
+/* Add an entry into the history list. Don't save empty lines or
+ * lines that are exactly the same as the line immediately above.
+ */
+void
+add_history (char *line)
+{
+ /* don't save empty lines */
+ if (strlen (line) == 0) return;
+
+ /* if this is a modification of an earlier line, restore the original */
+ if (current_history != last_history) current_history->saved_data = NULL;
+
+ if (last_history->prev != NULL)
+ {
+ /* don't save copies */
+ if (!strcmp (last_history->prev->data, line))
+ {
+ current_history = last_history;
+ return;
+ }
+ }
+
+ /* save the line in the list */
+ last_history->data = xmalloc (ROUND_UP_SIZE (strlen (line)));
+ strcpy (last_history->data, line);
+
+ /* create a new node ... */
+ last_history->next = xmalloc (sizeof (struct history_node));
+
+ /* ... and fill it in */
+ last_history->next->data = NULL;
+ last_history->next->saved_data = NULL;
+ last_history->next->prev = last_history;
+ last_history->next->next = NULL;
+
+ /* update all pointers */
+ last_history = last_history->next;
+ current_history = last_history;
+}
+
+/* Expand a path if it contains a tilde */
+char *
+tilde_expand (char *file)
+{
+ char *expansion, *home;
+
+ home = getenv ("HOME");
+
+ if (file[0] == '~' && home != NULL)
+ {
+ expansion = xmalloc (strlen(file) + strlen(home));
+
+ sprintf (expansion, "%s%s", home, file + 1);
+ }
+ else
+ {
+ /* If there is no HOME or ~ is not in the string, just
+ * return a pointer which can be freed.
+ */
+ expansion = xmalloc (strlen(file) + 1);
+ strcpy (expansion, file);
+ }
+
+ return (expansion);
+}
+
+/* save the history list to a file -- usually ~/.tap_history */
+void
+save_history_to_file (char *file)
+{
+ char *path;
+ FILE *fd;
+
+ path = tilde_expand (file);
+
+ fd = fopen (path, "wt");
+ if (fd == NULL) return;
+
+ current_history = &the_history_list;
+
+ while (current_history != last_history)
+ {
+ fprintf (fd, "%s\n", current_history->data);
+
+ current_history = current_history->next;
+ }
+
+ fclose (fd);
+ xfree (path);
+}
+
+#define MAX_LINE_SIZE 1024
+
+void
+read_history_from_file (char *file)
+{
+ FILE *fd;
+ char *line, *path;
+
+ line = xmalloc (MAX_LINE_SIZE);
+
+ path = tilde_expand (file);
+
+ fd = fopen (path, "rt");
+ if (fd == NULL) return;
+
+ while (fgets (line, MAX_LINE_SIZE, fd) != NULL)
+ {
+ if (line[strlen (line) - 1] == '\n') line[strlen (line) - 1] = '\0';
+
+ add_history (line);
+ }
+
+ fclose (fd);
+ xfree (line);
+ xfree (path);
+}
diff --git a/tap/readline/line.c b/tap/readline/line.c
new file mode 100755
index 0000000..55ac482
--- /dev/null
+++ b/tap/readline/line.c
@@ -0,0 +1,340 @@
+/* line.c
+ * Part of the Readline module for Tap. This is the main file.
+ * The readline module was designed in a similar spirit as the GNU
+ * Readline module, but to work with ncurses, and, more specifically,
+ * with Tap. The functionality is similar, and the bindings are the
+ * same as in Emacs, however it is not as complete as in GNU Readline.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "readline.h"
+
+/* global variables which are important to the readline module */
+
+/* prompt to use */
+
+char *prompt;
+
+/* the line under construction */
+
+char *current_line;
+
+/* its actual size */
+
+long line_size;
+
+/* number of characters active */
+
+long chars_in_line;
+
+/* where the point is */
+
+long current_position;
+
+/* for when C-<spc> is pressed
+ * -1 means mark not set
+ */
+
+long mark_start;
+
+/* start position of the cursor */
+
+int start_y;
+
+/* repeat value from C-U */
+
+int repeat_value = 1;
+
+/* the kill ring */
+
+struct kill_ring *the_kill_ring = NULL;
+
+/* Clear the screen and reprint the current line */
+void
+clear_screen (void)
+{
+ clear_scr (NULL);
+
+ start_y = 0;
+
+ wprintw (input_window, "%s%s", prompt, current_line);
+}
+
+/* readchar () returns either an ASCII character, or a control
+ * code, which is a value >0xFF. All values are defined in readline.h.
+ */
+int
+readchar (void)
+{
+ int ch;
+
+ /* sgetch() is in serial/char.c */
+ ch = sgetch ();
+ /*ch = wgetch (input_window);*/
+
+ if (((char)ch) == '\n') return (ECQUIT);
+
+ if (isgraph (ch) || ch == ' ') return (ch);
+
+ switch (ch)
+ {
+ case RCUP:
+ return (ECUP);
+ case RCDOWN:
+ return (ECDOWN);
+ case RCLEFT:
+ return (ECLEFT);
+ case RCRIGHT:
+ return (ECRIGHT);
+ case RCSTART:
+ return (ECSTART);
+ case RCEND:
+ return (ECEND);
+ case RCDEL:
+ case RCDELK:
+ return (ECDEL);
+ case RCERASE:
+ return (ECERASE);
+ case RCMARK:
+ return (ECMARK);
+ case RCKILLL:
+ return (ECKILLL);
+ case RCKILLR:
+ return (ECKILLR);
+ case RCYANK:
+ return (ECYANK);
+ case RCTRANS:
+ return (ECTRANS);
+ case RCCLEAR:
+ return (ECCLEAR);
+ case RCCOUNT:
+ return (ECCOUNT);
+ case RCTAB:
+ return (ECTAB);
+ case RCESC:
+ ch = wgetch (input_window);
+
+ if (ch == EARROW)
+ {
+ int tch;
+
+ tch = wgetch (input_window);
+
+ switch (tch)
+ {
+ case AUP:
+ return (ECUP);
+ case ADOWN:
+ return (ECDOWN);
+ case ALEFT:
+ return (ECLEFT);
+ case ARIGHT:
+ return (ECRIGHT);
+ }
+
+ ungetch (tch);
+ }
+ /* fall through if one of the arrow keys wasn't recieved */
+ }
+
+ return (ECUNKNOWN);
+}
+
+/* If a control code was returned by readchar (), this function
+ * is called.
+ */
+void
+dispatch_special (int code)
+{
+ switch (code)
+ {
+ case ECLEFT:
+ move_cursor_left ();
+ break;
+ case ECRIGHT:
+ move_cursor_right ();
+ break;
+ case ECSTART:
+ move_cursor_to_start ();
+ break;
+ case ECEND:
+ move_cursor_to_end ();
+ break;
+ case ECDEL:
+ delete_char (RIGHT);
+ break;
+ case ECERASE:
+ delete_char (LEFT);
+ break;
+ case ECMARK:
+ mark_start = current_position;
+ break;
+ case ECKILLR:
+ kill_region ();
+ break;
+ case ECKILLL:
+ kill_to_eol ();
+ break;
+ case ECYANK:
+ yank_text ();
+ break;
+ case ECTRANS:
+ transpose_chars ();
+ break;
+ case ECCOUNT:
+ do_count ();
+ break;
+ case ECTAB:
+ do_tab_completion ();
+ break;
+ case ECUP:
+ {
+ char *line;
+
+ line = prev_history ();
+
+ if (line == NULL) warning_beep ();
+ else
+ {
+ move_cursor_to_start ();
+
+ current_line = line;
+ chars_in_line = strlen (line);
+ line_size = ROUND_UP_SIZE (chars_in_line);
+
+ move_cursor_to_end ();
+
+ mark_start = -1;
+ repeat_value = 1;
+ }
+ break;
+ }
+ case ECDOWN:
+ {
+ char *line;
+
+ line = next_history ();
+
+ if (line == NULL) warning_beep ();
+ else
+ {
+ move_cursor_to_start ();
+
+ current_line = line;
+ chars_in_line = strlen (line);
+ line_size = ROUND_UP_SIZE (chars_in_line);
+
+ move_cursor_to_end ();
+
+ mark_start = -1;
+ repeat_value = 1;
+ }
+
+ break;
+ }
+ case ECCLEAR:
+ {
+ int y_offset = input_window->_cury - start_y;
+ int x_pos = input_window->_curx;
+
+ clear_screen ();
+
+ input_window->_curx = x_pos;
+ input_window->_cury = y_offset;
+
+ break;
+ }
+ default:
+ warning_beep ();
+ }
+}
+
+/* Make sure that the screen is clear of junk after it has been
+ * modified (i.e. from inserting/removing a character).
+ */
+void
+refresh_screen (void)
+{
+ int x, y;
+
+ x = input_window->_curx;
+ y = input_window->_cury;
+
+ input_window->_cury = start_y;
+ input_window->_curx = 0;
+
+ wclrtobot (input_window);
+
+ wprintw (input_window, "%s%s", prompt, current_line);
+
+ input_window->_curx = x;
+ input_window->_cury = y;
+
+ wrefresh (input_window);
+}
+
+/* Given the prompt P, read a line of text in a user friendly manner. */
+char *
+readline (char *p)
+{
+ int ch;
+
+ /* initialize the kill ring if needed */
+ if (the_kill_ring == NULL) ring_init ();
+
+ /* initialize globals */
+ prompt = p;
+ chars_in_line = 0;
+ current_position = 0;
+ mark_start = -1;
+
+ start_y = input_window->_cury;
+
+ current_line = xmalloc (GROW_SIZE);
+ line_size = GROW_SIZE;
+
+ current_line[0] = 0;
+
+ waddstr (input_window, prompt);
+
+ while (1)
+ {
+ ch = readchar ();
+
+ if (ch == ECQUIT) break;
+
+ if (ch > 0xFF)
+ dispatch_special (ch);
+ else
+ insert_char (ch);
+
+ refresh_screen ();
+ }
+
+ add_history (current_line);
+
+ move_cursor_to_end ();
+ waddch (input_window, '\n');
+
+ return (current_line);
+}
diff --git a/tap/readline/readline.h b/tap/readline/readline.h
new file mode 100755
index 0000000..5a4cd69
--- /dev/null
+++ b/tap/readline/readline.h
@@ -0,0 +1,243 @@
+/* readline.h
+ * This is the header file for the Readline module for Tap.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tap.h"
+
+/* extended character codes returned by readchar() */
+
+#define ECQUIT 0x100 /* \n */
+
+#define ECUP 0x101 /* ^P */
+#define ECDOWN 0x102 /* ^N */
+#define ECLEFT 0x103 /* ^B */
+#define ECRIGHT 0x104 /* ^F */
+#define ECSTART 0x105 /* ^A */
+#define ECEND 0x106 /* ^E */
+
+#define ECDEL 0x107 /* ^D */
+#define ECERASE 0x108 /* ^H */
+
+#define ECMARK 0x109 /* ^<spc> */
+#define ECKILLR 0x10A /* ^W */
+#define ECKILLL 0x10B /* ^K */
+#define ECYANK 0x10C /* ^Y */
+#define ECTRANS 0x10D /* ^T */
+#define ECCLEAR 0x10E /* ^L */
+
+#define ECCOUNT 0x10F /* ^U */
+
+#define ECTAB 0x110 /* \t */
+
+#define ECUNKNOWN 0xFFF /* unrecognized control code */
+
+
+/* raw character codes */
+
+#define RCUP 0x10
+#define RCDOWN 0x0E
+#define RCLEFT 0x02
+#define RCRIGHT 0x06
+#define RCSTART 0x01
+#define RCEND 0x05
+
+#define RCDEL 0x04
+#define RCDELK 0x7F
+#define RCERASE 0x08
+
+#define RCMARK 0x00
+#define RCKILLR 0x17
+#define RCKILLL 0x0B
+#define RCYANK 0x19
+#define RCTRANS 0x14
+#define RCCLEAR 0x0C
+
+#define RCCOUNT 0x15
+
+#define RCTAB '\t'
+
+/* arrow key escape sequence */
+
+#define RCESC 0x1B
+
+#define EARROW 0x4F
+
+#define AUP 0x41
+#define ADOWN 0x42
+#define ARIGHT 0x43
+#define ALEFT 0x44
+
+/* used by do_tab_completion () when creating internal structures */
+
+#define INCR_VALUE 8
+
+/* the default number of entries in the kill ring */
+
+#define DEFAULT_KILL_RING_SIZE 32
+
+/* the minimum amount of padding to use when printing partial matches */
+
+#define PADDING 2
+
+
+/* used for determing the actual amount of memory used by a line of text */
+
+#define ROUND_UP_SIZE(nom) (((nom + 1) / GROW_SIZE) * GROW_SIZE + GROW_SIZE)
+
+
+/* specifies to delete_char() whether to delete the
+ * character to the left or the right of the point
+ */
+
+enum direction
+{
+ LEFT, RIGHT
+};
+
+
+/* kill ring entries */
+
+struct kill_ring
+{
+ long length; /* the length of TEXT */
+ char *text; /* the actual text in the ring */
+
+ struct kill_ring *prev; /* the previous entry in the kill ring */
+ struct kill_ring *next; /* the next entry in the kill ring */
+};
+
+/* history list entries */
+
+struct history_node
+{
+ char *data; /* the actual history entry */
+ char *saved_data; /* temporary entry used for when an
+ earlier line is being edited */
+ struct history_node *prev; /* the previous entry in the history list */
+ struct history_node *next; /* the next entry in the history list */
+};
+
+
+/* global variables */
+
+/* prompt to use */
+
+extern char *prompt;
+
+/* the line under construction */
+
+extern char *current_line;
+
+/* its actual size */
+
+extern long line_size;
+
+/* number of characters active */
+
+extern long chars_in_line;
+
+/* where the point is */
+
+extern long current_position;
+
+/* for when C-<spc> is pressed */
+
+extern long mark_start;
+
+/* start position of the cursor */
+
+extern int start_y;
+
+/* cursor position after the prompt has been printed */
+
+extern int start_x;
+
+/* the last repeat value -- should be 1 unless C-U has just been typed */
+
+extern int repeat_value;
+
+/* the kill ring */
+
+extern struct kill_ring *the_kill_ring;
+
+/* a zero length string */
+
+extern char zero_length_string[];
+
+
+/* function prototypes */
+
+/* the main function -- read a line of text */
+
+extern char *readline (char *);
+
+/* character functions used by readline () */
+
+extern int readchar (void);
+
+extern void dispatch_special (int);
+
+/* keystroke functions */
+
+extern void kill_region (void);
+
+extern void kill_to_eol (void);
+
+extern void insert_char (char);
+
+extern void delete_char (enum direction);
+
+extern void move_cursor_left (void);
+
+extern void move_cursor_right (void);
+
+extern void move_cursor_to_start (void);
+
+extern void move_cursor_to_end (void);
+
+extern void transpose_chars (void);
+
+extern void yank_text (void);
+
+extern void do_count (void);
+
+/* functions for the kill ring */
+
+extern void kill_to_ring (int, int);
+
+extern char *get_ring_entry (int);
+
+extern void ring_init (void);
+
+/* tab completion */
+
+extern void do_tab_completion (void);
+
+/* history functions */
+
+extern void add_history(char *);
+
+extern char *next_history (void);
+
+extern char *prev_history (void);
diff --git a/tap/readline/ring.c b/tap/readline/ring.c
new file mode 100755
index 0000000..474cc27
--- /dev/null
+++ b/tap/readline/ring.c
@@ -0,0 +1,114 @@
+/* ring.c
+ * Part of the Readline module for Tap. This is the implementation
+ * of the kill ring.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "readline.h"
+
+/* If the requested entry in the kill ring is NULL,
+ * this is returned instead.
+ */
+char zero_length_string[] = "";
+
+/* Returns text previously yanked, with the most recent
+ * having an index of 1. If the entry is NULL, returns
+ * a pointer to a zero length string. Memory returned by
+ * this call should never be freed
+ */
+char *
+get_ring_entry (int which)
+{
+ struct kill_ring *current;
+ int k;
+
+ which--;
+ current = the_kill_ring;
+
+ for (k = 0; k < which; k++) current = current->prev;
+
+ if (current->text == NULL) return (zero_length_string);
+
+ return (current->text);
+}
+
+/* Add TEXT to the kill ring and advance the ring. The
+ * memory passed to this function should never be freed.
+ */
+void
+add_ring_entry (char *text)
+{
+ the_kill_ring = the_kill_ring->next;
+
+ if (the_kill_ring->text != NULL) xfree (the_kill_ring->text);
+
+ the_kill_ring->text = text;
+ the_kill_ring->length = strlen (text);
+}
+
+/* Copy text from START to FINISH to a new block
+ * and add block to kill ring
+ */
+void
+kill_to_ring (int start, int finish)
+{
+ char *text;
+
+ text = xmalloc (finish - start + 1);
+
+ strncpy (text, current_line + start, finish - start);
+ text[finish - start] = 0;
+
+ add_ring_entry (text);
+}
+
+/* Initialize the kill ring.
+ */
+void
+ring_init (void)
+{
+ int k;
+ struct kill_ring *current;
+
+ /* allocate first separately */
+ the_kill_ring = xmalloc (sizeof (struct kill_ring));
+ the_kill_ring->length = 0;
+ the_kill_ring->text = NULL;
+
+ current = the_kill_ring;
+
+ for (k = 0; k < DEFAULT_KILL_RING_SIZE - 2; k++)
+ {
+ current->next = xmalloc (sizeof (struct kill_ring));
+
+ current->next->length = 0;
+ current->next->text = NULL;
+ current->next->prev = current;
+
+ current = current->next;
+ }
+
+ /* complete the ring */
+ current->next = the_kill_ring;
+ the_kill_ring->prev = current;
+}
diff --git a/tap/readline/tab.c b/tap/readline/tab.c
new file mode 100755
index 0000000..dea8e15
--- /dev/null
+++ b/tap/readline/tab.c
@@ -0,0 +1,530 @@
+/* tab.c
+ * Part of the Readline module for Tap. This is where command line
+ * completion is implemented.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "readline.h"
+#include <glob.h>
+
+/* returned to do_tab_completion () when a successful match hasn't been made */
+char *null_match[] = { NULL, NULL };
+
+/* find the number of matching characters in the two strings */
+int
+strmatch (char *first, char *second)
+{
+ int highest;
+
+ for (highest = 0; highest < MAX (strlen (first), strlen (second)); highest++)
+ if (first[highest] != second[highest]) break;
+
+ return (highest);
+}
+
+/* Scan an array of strings looking for the largest
+ * number of matching characters. For the array
+ *
+ * "dobri"
+ * "dyen"
+ * "dinamacheskiye"
+ * "dudayevtsi"
+ *
+ * the result would be 1.
+ */
+int
+find_matching_chars (char *matches[])
+{
+ int current_match, max_match = INT_MAX, index, last = 0;
+
+ while (matches[last + 1] != NULL) last++;
+
+ if (!last) return (strlen (matches[0])); /* one item in array */
+
+ for (index = 1; index <= last; index++)
+ {
+ current_match = strmatch (matches[index - 1], matches[index]);
+
+ max_match = MIN (max_match, current_match);
+ }
+
+ return (max_match);
+}
+
+/* Return an array of strings containing the main command names */
+char **
+command_names (void)
+{
+ static char **names = NULL;
+ int index = 0, max_commands;
+
+ if (names != NULL) return (names);
+
+ names = xmalloc (sizeof (char *) * INCR_VALUE);
+ max_commands = INCR_VALUE;
+
+ while (commands[index].name != NULL)
+ {
+ if (index == max_commands - 1)
+ {
+ names = xrealloc (names, sizeof (char *)*(max_commands+INCR_VALUE));
+ max_commands += INCR_VALUE;
+ }
+
+ names[index] = commands[index].name;
+ index++;
+ }
+
+ names[index] = NULL;
+
+ return (names);
+}
+
+/* Return the `number' of the current token */
+int
+find_current_token_number (void)
+{
+ int token_number = 1, pos = current_position + 1;
+
+ while (pos--)
+ { /* scan backward counting whitespace regions */
+
+ if (current_line[pos] == ' ') /* found one */
+ {
+ token_number++;
+
+ /* skip the rest of the region */
+ while (current_line[pos] == ' ' && pos) pos--;
+
+ /* if the first char is ' ' */
+ if (!pos && current_line[pos] == ' ') token_number--;
+ }
+ }
+
+ return (token_number);
+}
+
+/* move the point to the end of the current token */
+void
+move_to_token_end (void)
+{
+ while (current_line[current_position] != ' '
+ && current_position != chars_in_line) move_cursor_right ();
+}
+
+/* If a match string for a command is \f, this function is
+ * called. Uses the POSIX.2 function glob() to match files
+ * and returns all files matched by SEARCH with a '*' tacked
+ * onto the end.
+ */
+char **
+match_file_esc (char *search)
+{
+ glob_t file_list;
+ int k;
+ char **ret_list, *pattern;
+
+ pattern = xmalloc (strlen (search) + 2);
+ sprintf (pattern, "%s*", search);
+
+ if (glob (pattern, GLOB_MARK, NULL, &file_list)) return (null_match);
+
+ ret_list = xmalloc ((file_list.gl_pathc + 1) * sizeof (char *));
+
+ for (k = 0; k < file_list.gl_pathc; k++)
+ {
+ ret_list[k] = xmalloc (strlen (file_list.gl_pathv[k]) + 1);
+ strcpy (ret_list[k], file_list.gl_pathv[k]);
+ }
+
+ ret_list[file_list.gl_pathc] = NULL;
+
+ xfree (pattern);
+ return (ret_list);
+}
+
+/* Returns an array of strings which match the escape. Valid
+ * escapes are \f - a filename, \c - a command name, and \m - anything.
+ */
+char **
+find_esc_matches (char *search, char *esc_code)
+{
+ switch (esc_code[1])
+ {
+ case 'f':
+ return (match_file_esc (search));
+
+ /* this will be made functional later -- it isn't
+ * used for anything now anyways */
+ case 'c':
+
+ case 'm': /* this doesn't match anything specific */
+ return (null_match);
+ }
+
+ return (null_match);
+}
+
+/* Given a search string and an array of strings, returns an
+ * array of strings which match
+ */
+char **
+find_matches (char *search, char **potential_matches)
+{
+ char **actual_matches;
+ int possible_completions, length = strlen (search), last_completion = -1, k;
+
+ /* count the entries in potential_matches */
+ for (possible_completions = 0;
+ potential_matches[possible_completions] != NULL;
+ possible_completions++);
+
+ /* check for escapes */
+ if (possible_completions == 1 && potential_matches[0][0] == '\\')
+ return (find_esc_matches (search, potential_matches[0]));
+
+ actual_matches = xmalloc ((possible_completions + 1) * sizeof (char *));
+
+ /* zero out the output array */
+ for (k = 0; k < possible_completions + 1; k++) actual_matches[k] = NULL;
+
+ /* loop backward looking for matches */
+ while (possible_completions--)
+ {
+ /* found a match */
+ if (!strncmp (search, potential_matches[possible_completions], length))
+ {
+ /* add to match list */
+ actual_matches[++last_completion] =
+ potential_matches[possible_completions];
+ }
+ }
+
+ return (actual_matches);
+}
+
+/* Expands a token to the maximum possible size using
+ * partial matches. Assumes that the point is at the end of the token
+ * to be expanded, that token contains the partial token, and
+ * that matches is a NULL terminated array with strings that
+ * are matched by token.
+ */
+void
+expand_text (char *token, char *matches[])
+{
+ int match_length, tok_length, match_pos;
+
+ match_pos = tok_length = strlen (token);
+
+ match_length = find_matching_chars (matches) - tok_length;
+
+ if (match_length < 1) return;
+
+ while (match_length--) insert_char (matches[0][match_pos++]);
+
+ if (current_line[current_position] != ' '
+ && matches[1] == NULL
+ && current_line[current_position - 1] != '/')
+ insert_char (' ');
+}
+
+/* Retrieves the match string for COMMAND. In other words
+ * returns commands[n].tab_completion when
+ * strcmp (command, commands[n].name) == 0
+ */
+char *
+get_match_string (char *command)
+{
+ int index = -1, tok_len = strlen (command);
+
+ while (commands[++index].name != NULL)
+ {
+ if (!strncmp (command, commands[index].name, tok_len))
+ return (commands[index].tab_completion);
+ }
+
+ /* this should never be reached */
+ return (zero_length_string);
+}
+
+/* print all of the strings in MATCHES */
+void
+print_partial_matches (char *matches[])
+{
+ int index, command_width = 0, commands_per_line;
+ int x_pos = input_window->_curx, y, y_offset;
+
+ y = input_window->_cury;
+ move_cursor_to_end ();
+ y_offset = input_window->_cury - y;
+
+ waddch (input_window, '\n');
+
+ /* find longest string */
+ index = -1;
+ while (matches[++index] != NULL)
+ command_width = MAX (command_width, strlen (matches[index]));
+
+ command_width += PADDING;
+
+ commands_per_line = window_width / command_width;
+
+ /* print strings */
+ index = -1;
+ while (matches[++index] != NULL)
+ {
+ wprintw (input_window, "%-*s", command_width, matches[index]);
+ if (!((index + 1) % commands_per_line)) waddch (input_window, '\n');
+ }
+
+ if (input_window->_curx) waddch (input_window, '\n');
+
+ start_y = input_window->_cury;
+
+ wprintw (input_window, "%s%s", prompt, current_line);
+
+ input_window->_curx = x_pos;
+ input_window->_cury -= y_offset;
+}
+
+/* Returns the NUMBERth token in current_line */
+char *
+get_token_by_number (int number)
+{
+ int pos = 0;
+
+ while (number--)
+ {
+ if (number)
+ while (current_line[pos] != ' ' && pos < chars_in_line) pos++;
+
+ while (current_line[pos] == ' ' && pos < chars_in_line) pos++;
+ }
+
+ return (get_token_only (current_line + pos));
+}
+
+/* Returns the position of the next level one match_string
+ */
+int
+next_level_one (char *match_string, int pos)
+{
+ int depth = 0;
+
+ pos--;
+
+ while (match_string[++pos] != '\0')
+ {
+ switch (match_string[pos])
+ {
+ case '{':
+ depth++;
+ break;
+ case '}':
+ depth--;
+ break;
+ case ',':
+ if (!depth)
+ return (pos + 1);
+ }
+ }
+
+ return (-1);
+}
+
+/* Returns the sub-match_string for TOKEN. If TOKEN isn't in
+ * MATCH_STRING, returns ""
+ */
+char *
+get_sublist (char *token, char *match_string)
+{
+ int pos = 0, len;
+ char *sublist;
+
+ while (1)
+ {
+ /* got a match */
+ if (!strncmp (token, match_string + pos, strlen (token))) break;
+
+ pos = next_level_one (match_string, pos);
+
+ if (pos == -1) return (zero_length_string);
+ }
+
+ /* skip to end of token */
+ while ((match_string[pos] != ',') && (match_string[pos] != '{')
+ && (match_string[pos] != '\0')) pos++;
+
+ if (match_string[pos] != '{') return (zero_length_string);
+
+ /* find substring */
+ len = next_level_one (match_string, pos);
+
+ if (len == -1)
+ len = strlen (match_string) - pos + 1;
+ else
+ len -= pos;
+
+ len -= 3;
+
+ /* extract */
+ sublist = xmalloc (len + 1);
+ strncpy (sublist, match_string + pos + 1, len);
+ sublist[len] = '\0';
+
+ return (sublist);
+}
+
+/* Returns an array with the top level entries in SEARCH_TEXT */
+char **
+get_search_strings (char *search_text)
+{
+ char **search_strings = NULL;
+ int offset, pos = 0, current = 0, max_str;
+
+ search_strings = xmalloc (INCR_VALUE * sizeof (char *));
+ max_str = INCR_VALUE;
+
+ while (1)
+ {
+ offset = 0;
+ while ((search_text[pos + offset] != ',')
+ && (search_text[pos + offset] != '{')
+ && (search_text[pos + offset] != '\0')) offset++;
+
+ if (offset == 0) break;
+
+ if (current == max_str - 1)
+ {
+ search_strings = xrealloc (search_strings,
+ sizeof (char *) * (max_str + INCR_VALUE));
+ max_str += INCR_VALUE;
+ }
+
+ search_strings[current] = xmalloc (offset + 1);
+ strncpy (search_strings[current], search_text + pos, offset);
+ search_strings[current++][offset] = '\0';
+
+ switch (search_text[pos + offset])
+ {
+ case ',':
+ pos = pos + offset + 1;
+ break;
+ case '{':
+ pos = next_level_one (search_text, pos + offset);
+ break;
+ case '\0':
+ goto END;
+ }
+ }
+
+ END:
+ search_strings[current] = NULL;
+ return (search_strings);
+}
+
+/* Frees the array returned by get_search_strings () */
+void
+free_search_strings (char *search_strings[])
+{
+ int index = -1;
+
+ while (search_strings[++index] != NULL) xfree (search_strings[index]);
+
+ xfree (search_strings);
+}
+
+/* Completes the current token as much as possible */
+void
+do_tab_completion (void)
+{
+ char *first, **matches, **search_strings, *match_string, *token = NULL;
+ int token_number = find_current_token_number (), tok;
+
+ search_strings = command_names ();
+
+ first = get_token_by_number (1);
+
+ matches = find_matches (first, search_strings);
+
+ if (matches[0] == NULL)
+ {
+ warning_beep ();
+ return;
+ }
+
+ if (token_number == 1)
+ {
+ /* just matching the first token */
+ move_to_token_end ();
+ expand_text (first, matches);
+
+ if (matches[1] != NULL) print_partial_matches (matches);
+
+ return;
+ }
+ else if (matches[1] != NULL)
+ {
+ /* trying to match other than the first token w/o a unique
+ * first token -- bad news
+ */
+ warning_beep ();
+ return;
+ }
+
+ /* matching other than the first token */
+ match_string = get_match_string (first);
+
+ /* match all preceding tokens to find out what is trying to be matched */
+ for (tok = 2; tok < token_number; tok++)
+ {
+ token = get_token_by_number (tok);
+ match_string = get_sublist (token, match_string);
+
+ if (strlen (match_string) == 0)
+ {
+ warning_beep ();
+ return;
+ }
+ }
+
+ token = get_token_by_number (token_number);
+
+ /* got a matchlist for this token */
+ search_strings = get_search_strings (match_string);
+
+ matches = find_matches (token, search_strings);
+
+ if (matches[0] == NULL)
+ {
+ warning_beep ();
+ return;
+ }
+
+ move_to_token_end ();
+ expand_text (token, matches);
+
+ if (matches[1] != NULL) print_partial_matches (matches);
+
+ free_search_strings (search_strings);
+}
diff --git a/tap/readline/text.c b/tap/readline/text.c
new file mode 100755
index 0000000..2cb7adf
--- /dev/null
+++ b/tap/readline/text.c
@@ -0,0 +1,354 @@
+/* text.c
+ * Part of the Readline module for Tap. These are functions which
+ * manipulate the text in some way.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "readline.h"
+
+/* Move the cursor one space to the left,
+ * don't perform range check and don't update
+ * position in line
+ */
+void
+cursor_left (void)
+{
+ if (input_window->_curx == 0)
+ {
+ input_window->_cury--;
+ input_window->_curx = window_width - 1;
+ }
+ else
+ input_window->_curx--;
+}
+
+/* Move the cursor one space to the right,
+ * don't perform range check and don't update
+ * position in line
+ */
+void
+cursor_right (void)
+{
+ if (input_window->_curx + 1 == window_width)
+ {
+ input_window->_cury++;
+ input_window->_curx = 0;
+ }
+ else
+ input_window->_curx++;
+}
+
+/* Kill the region from the mark to the point;
+ * bound to C-w
+ */
+void
+kill_region (void)
+{
+ long kstart, kend;
+
+ /* find the region to be killed */
+ if (mark_start == -1)
+ {
+ warning_beep ();
+ return;
+ }
+ else if (mark_start == current_position)
+ {
+ mark_start = -1;
+ return;
+ }
+ else if (mark_start < current_position)
+ {
+ int k;
+
+ kstart = mark_start;
+ kend = current_position;
+
+ for (k = 0; k < kend - kstart; k++) cursor_left ();
+ }
+ else
+ {
+ kstart = current_position;
+ kend = mark_start;
+ }
+
+ kill_to_ring (kstart, kend);
+
+ memmove (current_line + kstart, current_line + kend,
+ chars_in_line - kend + 1);
+
+ chars_in_line -= kend - kstart;
+ mark_start = -1;
+
+ current_position = kstart;
+}
+
+/* Kill from the point to the end of the line;
+ * bound to C-k
+ */
+void
+kill_to_eol (void)
+{
+ kill_to_ring (current_position, chars_in_line);
+
+ current_line[current_position] = 0;
+ chars_in_line = current_position;
+}
+
+/* Move the cursor left, doing range check and
+ * updating position in line;
+ * bound to C-b and the left arrow key
+ */
+void
+move_cursor_left (void)
+{
+ if (current_position == 0)
+ {
+ warning_beep ();
+ return;
+ }
+
+ current_position--;
+
+ cursor_left ();
+}
+
+/* Move the cursor right, doing range check and
+ * updating position in line;
+ * bound to C-f and the right arrow key
+ */
+void
+move_cursor_right (void)
+{
+ if (current_position == chars_in_line)
+ {
+ warning_beep ();
+ return;
+ }
+
+ current_position++;
+
+ cursor_right ();
+}
+
+/* Move the cursor to the start of the line;
+ * bound to C-a
+ */
+void
+move_cursor_to_start (void)
+{
+ int k;
+
+ for (k = 0; k < current_position; k++) cursor_left ();
+
+ current_position = 0;
+}
+
+/* Move the cursor to the end of the line;
+ * bound to C-e
+ */
+void
+move_cursor_to_end (void)
+{
+ int k;
+
+ for (k = 0; k < chars_in_line - current_position; k++) cursor_right ();
+
+ current_position = chars_in_line;
+}
+
+/* Transpose the character under the point with the one
+ * to the left performing range checking;
+ * bound to C-t
+ */
+void
+transpose_chars (void)
+{
+ char ch;
+
+ if (current_position == 0 || current_position == chars_in_line)
+ {
+ warning_beep ();
+ return;
+ }
+
+ ch = current_line[current_position];
+ current_line[current_position] = current_line[current_position - 1];
+ current_line[current_position - 1] = ch;
+
+ move_cursor_right ();
+}
+
+/* Insert CH into the line at CURRENT_POSITION
+ */
+void
+insert_char (char ch)
+{
+ if (chars_in_line + 1 == line_size)
+ {
+ current_line = xrealloc (current_line, line_size + GROW_SIZE);
+ line_size += GROW_SIZE;
+ }
+
+ memmove (current_line + current_position + 1,
+ current_line + current_position,
+ chars_in_line - current_position + 1);
+
+ current_line[current_position] = ch;
+
+ cursor_right ();
+
+ current_position++;
+ chars_in_line++;
+}
+
+/* Delete the character either under the point
+ * or to the left depending on the direction;
+ * bound to C-d and DEL as RIGHT and C-h and
+ * BACKSPACE as LEFT
+ */
+void
+delete_char (enum direction which)
+{
+ /* check if there is a char to delete */
+ if ((which == LEFT && current_position == 0)
+ || (which == RIGHT && current_position == chars_in_line))
+ {
+ warning_beep ();
+ return;
+ }
+
+ if (which == LEFT)
+ {
+ current_position--;
+ cursor_left ();
+ }
+
+ memmove (current_line + current_position,
+ current_line + current_position + 1,
+ chars_in_line - current_position);
+
+ chars_in_line--;
+}
+
+/* Yank text out of the kill ring and insert into the line;
+ * bound to C-y
+ */
+void
+yank_text (void)
+{
+ int k;
+ char *insert_text;
+
+ insert_text = get_ring_entry (repeat_value);
+
+ for (k = 0; k < strlen (insert_text); k++)
+ {
+ insert_char (insert_text[k]);
+ }
+}
+
+/* Read in a number and repeat the following command that
+ * many times, or if the next command is yank, uses the
+ * count as an index into the kill ring;
+ * bound to C-u
+ */
+void
+do_count (void)
+{
+ int k, y_save, ok, ch = 0, x0, y0, line_pos;
+
+ /* save the sojourn */
+ x0 = input_window->_curx;
+ y0 = input_window->_cury;
+ line_pos = current_position;
+
+ move_cursor_to_end ();
+
+ waddstr (input_window, "\nC-u> "); wrefresh (input_window);
+
+ y_save = input_window->_cury;
+
+ repeat_value = 0;
+
+ /* read in a number */
+ while (1)
+ {
+ ch = wgetch (input_window);
+ if (ch >= '0' && ch <= '9')
+ {
+ repeat_value *= 10;
+ repeat_value += ch - '0';
+
+ waddch (input_window, ch); wrefresh (input_window);
+ }
+ else
+ {
+ /* if ok == 1 , the number has been read */
+ ok = (ch == '\n') ? 1 : 0;
+ break;
+ }
+ }
+
+ if (ok) /* got a \n */
+ {
+ waddch (input_window, ' '); wrefresh (input_window);
+ ch = readchar ();
+ }
+
+ /* restore the old positions */
+ input_window->_cury = y_save;
+ input_window->_curx = 0;
+
+ waddnstr (input_window, " ", window_width); wrefresh (input_window);
+
+ input_window->_curx = x0;
+ input_window->_cury = y0;
+ current_position = line_pos;
+
+ if (!ok) /* if a valid number wasn't read, just return */
+ {
+ repeat_value = 1;
+ warning_beep ();
+ return;
+ }
+
+ if (ch == ECYANK)
+ yank_text ();
+ else if (ch == ECQUIT)
+ ungetch ('\n');
+ else if (ch == ECCOUNT)
+ warning_beep ();
+ else
+ {
+ for (k = 0; k < repeat_value; k++)
+ {
+ if (ch > 0xFF)
+ dispatch_special (ch);
+ else
+ insert_char (ch);
+ }
+ }
+
+ repeat_value = 1;
+}
diff --git a/tap/serial.c b/tap/serial.c
new file mode 100755
index 0000000..2963897
--- /dev/null
+++ b/tap/serial.c
@@ -0,0 +1,87 @@
+/* serial.c
+ * This file contains the function sgetch () which reads a
+ * character from stdin while listening to the serial port.
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tap.h"
+
+/* This function reads a fixed number of chars from the serial port
+ * and then writes it to wherever it needs to go. */
+void
+read_serial_data (void)
+{
+ int data_read;
+
+ data_read = read (serial_port_fd, serial_buffer, serial_buffer_size);
+
+ write_to_output_window (data_read);
+ write_to_capture_register (data_read);
+ write_to_capture_file (data_read);
+}
+
+/* This function reads a character from stdin while listening to
+ * the serial port (if one is open).
+ */
+int
+sgetch (void)
+{
+ fd_set readfs;
+ int ret, highest_port = 1, fds;
+
+ for (;;)
+ {
+ /* set focus to input_window */
+ wrefresh (input_window);
+
+ FD_ZERO (&readfs);
+ FD_SET (0, &readfs); /* always listen to stdin */
+
+ if (port != NULL)
+ { /* if a serial port is open */
+ FD_SET (serial_port_fd, &readfs);
+ highest_port = serial_port_fd + 1;
+ }
+
+ fds = select (highest_port, &readfs, NULL, NULL, NULL);
+
+ if (fds < 0)
+ { /* error */
+ /* for now just ignore it */
+ }
+ else if (fds > 0)
+ {
+ if (FD_ISSET (0, &readfs))
+ {
+ ret = wgetch (input_window);
+ return (ret);
+ }
+ else if (FD_ISSET (serial_port_fd, &readfs))
+ {
+ read_serial_data (); /* and reloop */
+ }
+ }
+ }
+
+ return (ret);
+}
diff --git a/tap/tap.c b/tap/tap.c
new file mode 100755
index 0000000..dd55ff7
--- /dev/null
+++ b/tap/tap.c
@@ -0,0 +1,274 @@
+/* tap.c
+ * Main program of Tap.
+ *
+ * Usage:
+ * -p --port <serial port> serial port to open on startup
+ * -s --save_history [<file name>] whether or not to save the command history
+ *
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tap.h"
+#include "version.h"
+#include "command_struct.h"
+
+
+/* global variables */
+
+/* name of the program (argv[0]) */
+
+char *pname;
+
+/* the name of the serial port */
+
+char *port = NULL;
+
+/* the name of the history file */
+
+char *history_file_name;
+
+/* whether or not to save history */
+
+int save_history = 0;
+
+/* the size for the data registers */
+
+int register_size = DEFAULT_REGISTER_SIZE;
+
+/* the registers themselves */
+
+struct data_register registers[MAX_REGISTERS];
+
+/* jmp_buf for recovery from nearly unrecoverable situations */
+
+jmp_buf start_of_input_loop;
+
+/* the format for displaying output and parsing input */
+
+enum io_format input_format = ASCII_COOKED;
+
+enum io_format output_format = ASCII_COOKED;
+
+
+/* Print useful version information. */
+void
+print_version (void)
+{
+ printf ("Tap %s\n\
+Copyright (C) 1999 Jonathan duSaint <jon@mbayweb.com>\n\
+Tap comes with NO WARRANTY,\n\
+to the extent permitted by law.\n\
+You may redistribute copies of Tap\n\
+under the terms of the GNU General Public License.\n\
+For more information about these matters,\n\
+see the file named COPYING.\n", version);
+}
+
+/* Print some usage information. */
+void
+print_help (void)
+{
+ printf ("Tap %s\n\
+Usage: tap [-p <port>][-s [history file name]]\n\
+Report bugs to jon@mbayweb.com after consulting\n\
+the file BUGS\n", version);
+}
+
+/* Returns the first token in line, but does not return any of
+ * the other information provided by get_token.
+ */
+char *
+get_token_only (const char *line)
+{
+ int next, length;
+
+ return (get_token (line, &next, &length));
+}
+
+/* Returns the first token in LINE. The index of the next token is
+ * returned in NEXT and the length of the token is returned in
+ * TOK_LEN. It is assumed that the first char of line is not
+ * a token delimeter, which is the space character.
+ */
+char *
+get_token (const char *line, int *next, int *tok_len)
+{
+ int got_name = 0, nxt = 0, cmd_len = 0;
+ char *cmd = NULL;
+
+ do
+ {
+ switch (line[nxt])
+ {
+ case ' ':
+ case 0:
+ /* found the end of the token */
+ got_name = 1;
+ cmd_len = nxt;
+
+ /* skip to the next token */
+ while (!(isgraph (line[nxt]) || (line[nxt] == 0))) nxt++;
+
+ break;
+ default:
+ if (!isgraph (line[nxt]))
+ {
+ inp_error ("invalid character");
+ return (NULL);
+ }
+ }
+
+ nxt++;
+ }
+ while (!got_name);
+
+ cmd = xmalloc (cmd_len + 1);
+ strncpy (cmd, line, cmd_len);
+ cmd[cmd_len] = 0;
+
+ *next = nxt - 1;
+ *tok_len = cmd_len;
+ return (cmd);
+}
+
+/* This function is responsible for taking the line returned by
+ * readline() and dispatching it off to the proper place. Anything
+ * other than a zero return value indicates to terminate the program.
+ */
+int
+parse_command_line (char *line)
+{
+ char *cmd;
+ int cmd_len, nxt = 0, current = 0;
+
+ /* skip initial whitespace */
+ while (*line == ' ') line++;
+
+ cmd = get_token (line, &nxt, &cmd_len);
+ if (cmd == NULL) return (0);
+
+ cmd = resolve_alias (cmd);
+
+ while (commands[current].function != NULL)
+ {
+ if (!strcmp (commands[current].name, cmd))
+ return (commands[current].function (line + nxt));
+ current++;
+ }
+
+ inp_error ("unknown command");
+ return (0);
+}
+
+
+/* Tap itself */
+int
+main (int argc, char *argv[])
+{
+ int opt, index = 0, have_port = 0;
+ char *line, *t_port = NULL;
+ struct option options[] = {
+ { "port", required_argument, NULL, 'p' },
+ { "save-history", optional_argument, NULL, 's' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { 0, 0, 0, 0 }
+ };
+
+ /* initialize global variables */
+ pname = argv[0];
+ opterr = 0;
+ history_file_name = "~/.tap_history";
+
+ /* parse command line for options */
+ while (1)
+ {
+ opt = getopt_long (argc, argv, "p:s::hv", options, &index);
+
+ if (opt == EOF) break;
+
+ switch (opt)
+ {
+ case 'p':
+ t_port = optarg;
+ have_port = 1;
+ break;
+ case 's':
+ if (optarg) history_file_name = optarg;
+ read_history_from_file (history_file_name);
+ save_history = 1;
+ break;
+ case 'h':
+ print_help ();
+ return (0);
+ case 'v':
+ print_version ();
+ return (0);
+ case ':':
+ exit (1);
+ case '?':
+ fprintf (stderr, "%s: unknown option character `%c'\n",
+ pname, optopt);
+ break;
+ default:
+ fprintf (stderr, "%s: ?? getopt returned character code 0x%x ??\n",
+ pname, opt);
+ }
+ }
+
+ initscr ();
+
+ keypad (stdscr, TRUE);
+ raw ();
+ noecho ();
+
+ init_console_ui ();
+
+ /* --port was passed */
+ if (have_port) open_p (t_port);
+
+ /* prepare for truly horrendous errors (only from the memory manager) */
+ setjmp (start_of_input_loop);
+
+ /* main loop */
+ for (;;)
+ {
+ refresh_console_status_line ();
+
+ line = readline (">> ");
+
+ if (!strlen (line)) continue;
+ if (parse_command_line (line)) break;
+ }
+
+ destroy_console_ui ();
+ endwin ();
+
+ close_p (NULL);
+
+ if (save_history) save_history_to_file (history_file_name);
+
+ free_alloc_list ();
+
+ return (0);
+}
diff --git a/tap/tap.h b/tap/tap.h
new file mode 100755
index 0000000..5cd778b
--- /dev/null
+++ b/tap/tap.h
@@ -0,0 +1,370 @@
+/* tap.h
+ * This is the main header file for Tap. In this file are declarations
+ * of all visible functions and all external datatypes.
+ */
+
+/* all of the includes for all of the source files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <signal.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <getopt.h>
+#include <ncurses.h>
+
+
+/* the default number of user registers */
+
+#define MAX_REGISTERS 64
+
+/* default size of registers, user may reset size with a call to set */
+
+#define DEFAULT_REGISTER_SIZE 64
+
+/* by how much command line buffer grows with each realloc */
+
+#define GROW_SIZE 8
+
+/* the minimum size of an alloc'ed block of memory */
+
+#define MINIMUM_ALLOC_SIZE 8
+
+/* the number of times out_of_memory may be called
+ * any more will cause the program to abort
+ */
+
+#define MAX_TIMES_OUT_OF_MEMORY 5
+
+/* the size of the mark on each alloc'ed block of memory */
+
+#define MARK_SIZE sizeof (long)
+
+/* The default amount of data to try to read from the serial port
+ * at one time. This should not be too large, as the more time
+ * spent reading the serial port, the longer it takes to respond to
+ * user keystrokes.
+ */
+
+#define DEFAULT_MAXIMUM_ONE_TIME_SERIAL_DATA 16
+
+/* This is only used for pretty printing the command names. There
+ * is no maximum command size, but larger than this may make the
+ * output from HELP look strange.
+ */
+
+#define MAXIMUM_COMMAND_SIZE 10
+
+
+/* prototypes for user functions */
+
+#define USER_FUNCTION(fname) extern int fname (char *)
+
+/* max and min macros */
+
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/* indicate whether or not a block of memory is in use */
+enum mem_in_use
+ {
+ USED, FREE
+ };
+
+/* current format for input/output */
+
+enum io_format
+ {
+ BIN, OCT, HEX, ASCII_RAW, ASCII_COOKED
+ };
+
+
+/* data structures */
+
+/* the format for a user command */
+
+struct command
+ {
+
+ /* the user-level name */
+ char *name;
+
+ /* pointer to the actual function */
+ int (*function)(char *);
+
+ /* a string describing how to do command line completion
+ * of the form
+ * option1{suboption1,suboption2{subsuboption1}},option2...
+ * special values are
+ * \f - a filename
+ * \c - a command name
+ * \m - miscellaneous (can't be completed)
+ */
+ char *tab_completion;
+
+ /* a short description of the function */
+ char *blurb_help;
+
+ /* the full help text for the function */
+ char *full_help;
+ };
+
+/* temporary data storage register */
+
+struct data_register
+ {
+
+ /* size of register (default size may be set with "set regsize ???" */
+ long size;
+
+ /* the current write position (active when the register is) */
+ long offset;
+
+ /* the data */
+ char *data;
+ };
+
+/* storage on the alloc list */
+
+struct memory_block
+ {
+
+ /* whether this chunk can be used or not */
+ enum mem_in_use in_use;
+
+ /* the actual chunk size (minus MARK_SIZE) */
+ unsigned long size;
+
+ /* the size requested ( <= size ) */
+ unsigned long size_used;
+
+ /* pointer to the memory
+ * the memory returned is actually &memory[MARK_SIZE] */
+ void *memory;
+ };
+
+
+/* global variables */
+
+/* name of the program (argv[0]) */
+
+extern char *pname;
+
+/* currently open port */
+
+extern char *port;
+
+/* the open port as returned by open() */
+
+extern int serial_port_fd;
+
+/* the number of lines per window */
+
+extern int window_height;
+
+/* the number of columns per window */
+
+extern int window_width;
+
+/* the current size of a storage register */
+
+extern int register_size;
+
+/* the actual storage registers */
+
+extern struct data_register registers[];
+
+/* jmp_buf used by out_of_memory() to recover from near-fatal errors */
+
+extern jmp_buf start_of_input_loop;
+
+/* the data entry format */
+
+extern enum io_format input_format;
+
+/* the data display format */
+
+extern enum io_format output_format;
+
+/* the windows where all of the action takes place */
+
+extern WINDOW *input_window;
+extern WINDOW *output_window;
+
+/* all of the user-level commands, their associated functions and the
+ * helper functions
+ */
+
+extern struct command commands[];
+
+/* the buffer which is used for communication with the serial port */
+
+extern char *serial_buffer;
+
+/* the current size of the buffer */
+
+extern int serial_buffer_size;
+
+
+/* functions */
+
+
+/* read a line in a manner similar to the GNU Readline library */
+
+extern char *readline (char *);
+
+/* read a character from the keyboard */
+
+extern int sgetch (void);
+
+
+/* memory management functions */
+
+/* just like malloc */
+
+extern void *xmalloc (size_t);
+
+/* just like realloc */
+
+extern void *xrealloc (void *, size_t);
+
+/* just like free */
+
+extern void xfree (void *);
+
+/* free everything allocated - called at exit */
+
+extern void free_alloc_list (void);
+
+
+/* user interface functions */
+
+/* just beep */
+
+extern void warning_beep (void);
+
+/* beep and print a message */
+
+extern void inp_error (char *);
+
+/* initialization */
+
+extern void init_console_ui (void);
+
+/* finalization */
+
+extern void destroy_console_ui (void);
+
+/* called periodically to refresh the status bar */
+
+extern void refresh_console_status_line (void);
+
+/* print and paginate a multiline string */
+
+extern void wprintstr (WINDOW *, char *);
+
+/* change the size of the windows when switching from active mode
+ * to passive mode and back
+ */
+
+extern void ui_expand_input_window(void);
+
+extern void ui_shrink_input_window(void);
+
+/* supply pagination for functions which print several functions, one
+ * line at a time
+ */
+
+extern void page_init (void);
+
+extern int page_line_printed (void);
+
+extern void page_finalize (void);
+
+
+/* utility functions */
+
+/* tokenize a string, returning the token length and the position
+ * of the next token
+ */
+
+extern char *get_token (const char *, int *, int *);
+
+/* tokenize a string and return just the token */
+
+extern char *get_token_only (const char *);
+
+/* expand a filename with a tilde in it */
+
+extern char *tilde_expand (char *);
+
+
+/* history functions */
+
+extern void read_history_from_file (char *);
+
+extern void save_history_to_file (char *);
+
+
+/* get the command to which an alias is assigned */
+
+extern char *resolve_alias (char *);
+
+
+/* functions used to write incoming serial port data */
+
+extern void write_to_output_window (int);
+
+extern void write_to_capture_register (int);
+
+extern void write_to_capture_file (int);
+
+
+/* translation functions for input and output */
+
+extern char *translate_to_bin (char *);
+
+extern char *translate_to_oct (char *);
+
+extern char *translate_to_hex (char *);
+
+extern char *translate_to_ascii_raw (char *);
+
+extern char *translate_to_ascii_cooked (char *);
+
+extern char *translate_from_bin (char *);
+
+extern char *translate_from_oct (char *);
+
+extern char *translate_from_hex (char *);
+
+extern char *translate_from_ascii_raw (char *);
+
+extern char *translate_from_ascii_cooked (char *);
+
+
+/* user level functions */
+
+/* the user functions */
+USER_FUNCTION (help);
+USER_FUNCTION (set);
+USER_FUNCTION (out);
+USER_FUNCTION (quit);
+USER_FUNCTION (capture);
+USER_FUNCTION (open_p);
+USER_FUNCTION (close_p);
+USER_FUNCTION (clear_scr);
+USER_FUNCTION (print);
+USER_FUNCTION (make_alias);
+USER_FUNCTION (unalias);
diff --git a/tap/tap.texinfo b/tap/tap.texinfo
new file mode 100755
index 0000000..820e803
--- /dev/null
+++ b/tap/tap.texinfo
@@ -0,0 +1,826 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename tap.info
+@setcontentsaftertitlepage
+@settitle Tap
+@c %**end of header
+
+
+@c information for a proper install
+@dircategory Communication Programs
+@direntry
+* Tap: (tap). A program to communicate with a serial line tap.
+@end direntry
+
+
+@c include commands and keystrokes with the regular index
+@syncodeindex fn cp
+@syncodeindex ky cp
+
+
+@ifinfo
+This file documents Tap, a program to read data from (and write data to)
+a serial port. Amongst other things, it may be used to facilitate the
+reverse engineering of serial communication protocols.
+
+Copyright @copyright{} 1999 Jonathan E duSaint @email{jon@@mbayweb.com}.
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+@end ifinfo
+
+
+@titlepage
+@title Tap 1.0
+@subtitle A program to communicate with a serial line tap.
+@author Jonathan E duSaint <jon@@mbayweb.com>
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1999 Jonathan E duSaint @email{jon@@mbayweb.com}
+
+Permission is granted to make and distribute verbatim copies of this
+manual provided the copyright notice and this permission notice are
+preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``Copying'' and ``GNU General Public License'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation
+approved by the Free Software Foundation.
+@end titlepage
+
+
+@ifnottex
+@node Top, Introduction, , (dir)
+@comment node-name, next, previous, up
+@top Tap
+
+Tap is a program designed to read data from and write data to the serial
+port. As such it has a wide variety of applications. For example, it
+can be used to prototype serial hardware, or to read data from a serial
+line tap, which can facilitate the reverse engineering of serial line
+communication protocols.
+
+This documentation corresponds with version 1.0 of Tap.
+@end ifnottex
+
+@menu
+* Introduction:: An introduction to @code{Tap} and the manual.
+* The Command Line:: The ins and outs of the interface.
+* Command Overview:: A look at the commands.
+* Input and Output:: Communicating with the serial line.
+* The Set Command:: Setting the environment.
+
+* Index:: The command, concept, and keystroke index.
+
+@detailmenu
+--- The Detailed Node Listing ---
+* Conventions:: Document conventions.
+* Invocation:: How to start @code{Tap} and the command line options.
+* Overview:: A brief tour through @code{Tap}.
+
+* History:: How to use the history functionality.
+* Editing:: Command line editing.
+
+* C-B: Moving Left. Moving the cursor to the left.
+* Left Arrow: Moving Left.
+ Moving the cursor to the left.
+* C-F: Moving Right. Moving the cursor to the right.
+* Right Arrow: Moving Right.
+ Moving the cursor to the right.
+* C-A:: Moving the cursor to the start of the line.
+* C-E:: Moving the cursor to the end of the line.
+* C-D:: Deleting the character under the point.
+* C-H:: Deleting the character to the left of the point.
+* C-U:: Entering a numerical argument.
+* C-space: Killing and Yanking Text.
+ Setting the mark position.
+* C-K: Killing and Yanking Text.
+ Killing from the point to the end of the line.
+* C-W: Killing and Yanking Text.
+ Killing in between the mark and the point.
+* C-Y: Killing and Yanking Text.
+ Yanking text from the kill ring.
+* C-T:: Transposing characters.
+* C-L:: Clearing the screen.
+* tab:: Command line completion.
+
+* alias:: Assign a different name to a command.
+* capture:: Capture incoming data to a file or a register.
+* clear:: Clear the input window.
+* close:: Close an open serial port.
+* help:: Get help on a command.
+* open:: Open a serial port.
+* out:: Write format controlled data to the serial port.
+* print:: Print the contents of a file or a register.
+* quit:: Quit the program.
+* set:: Change the behavior of the program.
+* unalias:: Remove an alias.
+
+* Help:: The --help command line option.
+* version:: The --version command line option.
+* port:: The --port command line option.
+* save-history:: The --save-history command line option.
+@end detailmenu
+@end menu
+
+
+@node Introduction, The Command Line, Top, Top
+@comment node-name, next, previous, up
+@chapter Introduction
+
+This chapter serves as an introduction to the manual as well as to
+@code{Tap}, and documents the command line options.
+
+@menu
+* Conventions:: Document conventions.
+* Invocation:: How to start @code{Tap} and the command line options.
+* Overview:: A brief tour through @code{Tap}.
+@end menu
+
+
+@node Conventions, Invocation, Introduction, Introduction
+@comment node-name, next, previous, up
+@section Conventions
+@cindex Document, How to Read
+@cindex Explanation of the C-? Syntax
+@cindex C-? Syntax, Explanation of
+
+The syntax @dfn{C-whatever} means to press the @kbd{Control} key and to
+simultaneously press the @kbd{whatever} key. For example, @kbd{C-P}
+means to hold down the @kbd{Control} key, and then hit the @kbd{P} key.
+
+When the command definitions are presented, the command usage is put
+first. Then follows a description of the function. If there is more
+than one way to use a function, then each invocation is shown with an
+explanation after it.
+
+
+@node Invocation, Overview, Conventions, Top
+@comment node-name, next, previous, up
+@section Invocation
+@cindex Options
+@cindex Command Line Options
+@cindex Startup Options
+@cindex Invocation
+
+To start @code{Tap}, merely type @kbd{tap} at the shell prompt. If it
+is properly installed, you should be presented with the interface. If
+it isn't, then read the file @file{INSTALL} for information on how to do
+so. @code{Tap} can be invoked with several different command line
+options.
+
+@menu
+* Help:: The --help command line option.
+* version:: The --version command line option.
+* port:: The --port command line option.
+* save-history:: The --save-history command line option.
+@end menu
+
+
+@node Help, version, Invocation, Invocation
+@comment node-name, next, previous, up
+@subsection @code{--help}
+@findex --help
+@findex -h
+@cindex @code{help}, Command Line Option
+
+@code{--help}, @code{-h}
+
+Invoking @code{Tap} with this option will cause @code{Tap} to print a
+short help message to @var{stdout} and then exit.
+
+
+@node version, port, Help, Invocation
+@comment node-name, next, previous, up
+@subsection @code{--version}
+@findex --version
+@findex -v
+@cindex @code{version}, Command Line Option
+
+@code{--version}, @code{-v}
+
+Invoking @code{Tap} with this option will cause @code{Tap} to print
+version and copyright information to @var{stdout} and then exit.
+
+
+@node port, save-history, version, Invocation
+@comment node-name, next, previous, up
+@subsection @code{--port}
+@cindex Default Port
+@cindex Port, Opening on Invocation
+@findex --port
+@findex -p
+@cindex @code{port}, Command Line Option
+
+@code{--port} @file{serial port}, @code{-p} @file{serial port}
+
+With this option, @code{Tap} will open @file{serial port} at startup.
+If the serial port can't be opened, @code{Tap} will print an error
+message at startup.
+
+
+@node save-history, , port, Invocation
+@comment node-name, next, previous, up
+@subsection @code{--save-history}
+@findex --save-history
+@findex -s
+@cindex @code{save-history}, Command Line Option
+@cindex Saving History
+@cindex History, Saving
+@cindex History File
+@cindex Default History File
+
+@code{--save-history} @file{history filename}, @code{-s} @file{history filename}
+
+This option will cause @code{Tap} to read history information at startup
+from the file specified and to write history information at shutdown to
+the file. If the file specified doesn't exist, it will be created, and
+if no file is specified, the default will be used, which is usually
+@file{~/.tap_history}.
+
+
+@node Overview, , Invocation, Introduction
+@comment node-name, next, previous, up
+@section Overview
+@findex help, Command
+
+This overview assumes that @code{tap} is already properly installed on
+your system. If it isn't, read the file @file{INSTALL} for instructions.
+
+To start, invoke @code{tap} from the command line by typing @kbd{tap}.
+Once it is started, you will notice that the screen is divided into two
+parts, both with headers. The top part is called the @dfn{input window}
+and the bottom part is called the @dfn{output window}. At the bottom of
+the screen is the status bar. It should state that no serial port is
+open on one side, and suggest typing @code{help} for help.
+
+As a first experiment, try typing @code{help}. You will be presented
+with a brief summary of all of the commands available. To get more
+specific help information, type @code{help command-name}
+
+
+@node The Command Line, Command Overview, Introduction, Top
+@comment node-name, next, previous, up
+@chapter The Command Line
+@cindex Command Line Interface
+
+If you are familiar with @code{Bash} or @code{Emacs}, then you should
+already have a good grasp of most of the functionality of the command
+line interface. While @code{Tap} doesn't actually use the @code{GNU
+Readline} or the @code{GNU History} libraries, the interface was
+designed to be very similar. All commands are saved in a history list,
+although if a command is repeated one or more times, only one copy is
+saved. Also, while entering text on the command line, a variety of
+keystrokes are available for command line editing.
+
+@menu
+* History:: How to use the history functionality.
+* Editing:: Command line editing.
+@end menu
+
+@node History, Editing, The Command Line, The Command Line
+@comment node-name, next, previous, up
+@section History
+@cindex History Functionality
+@cindex History List
+@cindex History File
+@kindex C-P
+@kindex C-N
+@kindex Up Arrow
+@kindex Arrow, Up
+@kindex Down Arrow
+@kindex Arrow, Down
+
+Every time a command is entered, it is automatically inserted into the
+internal history list. However, if the command is identical to the
+previous command, a list entry is not made.
+
+To access previous entries, press either @kbd{Up Arrow}, or
+@kbd{C-P}. To access more recent entries, press either @kbd{Down
+Arrow}, or @kbd{C-N}.
+
+If a previous entry is edited and @kbd{Enter} is not pressed, the edited
+copy will be saved in the place of the original. However, once
+@kbd{Enter} is pressed, the original copy will once again be available.
+
+When @code{Tap} is invoked with the @code{--save-history}
+(@pxref{save-history}) option, all history entries are read at startup
+from the file specified, or, if one isn't specified, from the default
+file. At shutdown, the current history list is appended onto the file.
+
+If a file is specified that doesn't exist, then one will be created at
+shutdown.
+
+
+@node Editing, , History, The Command Line
+@comment node-name, next, previous, up
+@section Editing
+@cindex Command Line Editing
+@cindex Editing, Command Line
+
+@code{Tap} contains features for editing the current command line. The
+keystrokes are the same as used in @code{Emacs} and in the @code{Bash}
+shell's @code{Emacs} mode.
+
+@menu
+--- list of keystrokes ---
+* C-B: Moving Left. Moving the cursor to the left.
+* Left Arrow: Moving Left.
+ Moving the cursor to the left.
+* C-F: Moving Right. Moving the cursor to the right.
+* Right Arrow: Moving Right.
+ Moving the cursor to the right.
+* C-A:: Moving the cursor to the start of the line.
+* C-E:: Moving the cursor to the end of the line.
+* C-D:: Deleting the character under the point.
+* C-H:: Deleting the character to the left of the point.
+* C-U:: Entering a numerical argument.
+* C-space: Killing and Yanking Text.
+ Setting the mark position.
+* C-K: Killing and Yanking Text.
+ Killing from the point to the end of the line.
+* C-W: Killing and Yanking Text.
+ Killing in between the mark and the point.
+* C-Y: Killing and Yanking Text.
+ Yanking text from the kill ring.
+* C-T:: Transposing characters.
+* C-L:: Clearing the screen.
+* tab:: Command line completion.
+@end menu
+
+@node Moving Left, Moving Right, Editing, Editing
+@comment node-name, next, previous, up
+@subsection Moving Left
+@kindex C-B
+@kindex Left Arrow
+@kindex Arrow, Left
+@cindex Point Movement
+@cindex Cursor Movement
+
+@kbd{C-B}, @kbd{Left Arrow}
+
+Both of these keystrokes will move the point one character to the left,
+if possible.
+
+
+@node Moving Right, C-A, Moving Left, Editing
+@comment node-name, next, previous, up
+@subsection Moving Right
+@kindex C-F
+@kindex Right Arrow
+@kindex Arrow, Right
+@cindex Point Movement
+@cindex Cursor Movement
+
+@kbd{C-F}, @kbd{Right Arrow}
+
+Both of these keystrokes will move the point one character to the right,
+if possible.
+
+
+@node C-A, C-E, Moving Right, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{C-A}
+@kindex C-A
+@cindex Cursor Movement
+@cindex Point Movement
+@cindex Start of Line, Moving the Point to
+
+@kbd{C-A}
+
+This keystroke will move the point to the start of the line.
+
+
+@node C-E, C-D, C-A, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{C-E}
+@kindex C-E
+@cindex Cursor Movement
+@cindex Point Movement
+@cindex End of Line, Moving the Point to
+
+@kbd{C-E}
+
+This keystroke will move the point to the end of the line.
+
+
+@node C-D, C-H, C-E, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{C-D}
+@kindex C-D
+@kindex Delete
+@cindex Deleting Characters
+
+@kbd{C-D}, @kbd{Delete}
+
+Both of these keystrokes will delete the character under the point.
+
+
+@node C-H, C-U, C-D, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{C-H}
+@kindex C-H
+@kindex Backspace
+@cindex Deleting Characters
+
+@kbd{C-H}, @kbd{Backspace}
+
+Both of these keystrokes will delete the character to the left of the
+point.
+
+
+@node C-U, Killing and Yanking Text, C-H, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{C-U}
+@kindex C-U
+@cindex Entering Numerical Arguments
+@cindex Numerical Arguments, Entering
+@cindex Arguments, Numerical
+@cindex Numerical Arguments
+
+@kbd{C-U}
+
+This command prompts for a number. After the number is entered, press
+@kbd{Enter}, and then the desired key. If the key entered was @kbd{C-Y}
+(@pxref{Killing and Yanking Text}), then text from the kill ring will be
+entered. If @kbd{Enter} was pressed, then it will be just as if
+@kbd{Enter} had been pressed without the argument (i.e. the command line
+will be processed). Any other key will be repeated as many times as was
+indicated by the number.
+
+For example, type
+
+@example
+@kbd{C-U} @kbd{2} @kbd{0} @kbd{Enter} @kbd{a}
+@end example
+
+@noindent
+to insert 20 copies of the letter `a', or type
+
+@example
+@kbd{C-U} @kbd{5} @kbd{Enter} @kbd{C-D}
+@end example
+
+@noindent
+to delete the character under the point and four to the right of it.
+
+
+@node Killing and Yanking Text, C-T, C-U, Editing
+@comment node-name, next, previous, up
+@subsection Killing and Yanking Text
+@kindex C-space
+@kindex C-W
+@kindex C-K
+@kindex C-Y
+@cindex Killing Text
+@cindex Yanking Text
+@cindex Kill Ring
+@cindex Copying Text
+@cindex Cutting Text
+@cindex Pasting Text
+@cindex Setting the Mark
+@cindex Mark, Setting
+
+@kbd{C-space} Set the mark.
+
+@kbd{C-W} Kill the text from the mark to the point.
+
+@kbd{C-K} Kill the text from the mark to the end of the line.
+
+@kbd{C-Y} Yank from the kill ring and insert it at the point.
+
+Tap utilizes a kill ring for storage of text which has been killed using
+the above commands. The single character delete commands will not
+store anything to the ring.
+
+The @kbd{C-Y} command will only yank the most recent entry. In order to
+yank older entries than that, it must be used in combination with the
+@kbd{C-U} command (@pxref{C-U}). For example, type
+
+@example
+@kbd{C-U} @kbd{3} @kbd{Enter} @kbd{C-Y}
+@end example
+
+@noindent
+to insert the text from the third to last kill.
+
+
+@node C-T, C-L, Killing and Yanking Text, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{C-T}
+@kindex C-T
+@cindex Transposing Characters
+@cindex Characters, Transposing
+
+@kbd{C-T}
+
+This keystroke transposes the character under the point with the
+character to its left.
+
+
+@node C-L, tab, C-T, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{C-L}
+@kindex C-T
+@cindex Clearing the Screen
+
+@kbd{C-L}
+
+This keystroke clears the screen and redraws the current line.
+
+@xref{clear}.
+
+
+@node tab, , C-L, Editing
+@comment node-name, next, previous, up
+@subsection @kbd{tab}
+@kindex tab
+@cindex Command Line Completion
+@cindex Completion, Command
+@cindex Command Completion
+
+@kbd{tab}
+
+Pressing the tab key will complete the token under the point, if at all
+possible. If the point is over the first token, then a command
+completion will be attempted. If it is over any other token, a
+completion will be attempted, based on the arguments that the command
+takes. If only a partial completion is possible, the token is completed
+as far as it can be, and all of the matching completions are printed
+out. If no completion is possible, the program just beeps.
+
+
+@node Command Overview, Input and Output, The Command Line, Top
+@comment node-name, next, previous, up
+@chapter Command Overview
+@cindex Commands
+@cindex Command Overview
+
+These are descriptions of all of the commands. Some commands are
+documented elsewhere, so for them, there will be only a short
+description.
+
+@menu
+* alias:: Assign a different name to a command.
+* capture:: Capture incoming data to a file or a register.
+* clear:: Clear the input window.
+* close:: Close an open serial port.
+* help:: Get help on a command.
+* open:: Open a serial port.
+* out:: Write format controlled data to the serial port.
+* print:: Print the contents of a file or a register.
+* quit:: Quit the program.
+* set:: Change the behavior of the program.
+* unalias:: Remove an alias.
+@end menu
+
+
+@node alias, capture, Command Overview, Command Overview
+@comment node-name, next, previous, up
+@section @code{alias}
+@findex alias, Command
+@cindex Aliasing Command Names
+@cindex Renaming Commands
+
+@code{alias}
+
+Invoking @code{alias} with no arguments will print out all of the
+aliases which have been assigned.
+
+@code{alias} @var{alias}
+
+The @code{alias} command with one argument will print out the alias and
+the command to which it is aliased.
+
+@code{alias} @var{alias} @var{command}
+
+With two options, @code{alias} will assign @var{alias} to @var{command}
+so that when @var{alias} is entered, the program will act as if
+@var{command} itself had been entered.
+
+This command can be very useful to decrease the amount of typing
+necessary. If, for example, the @code{out} (@pxref{out}) command were to
+be aliased to @code{o}, then rather than typing
+
+@example
+out foo bar\n
+@end example
+
+@noindent
+it would be possible to merely type
+
+@example
+o foo bar\n
+@end example
+
+@noindent
+which doesn't save that much typing, but does illustrate the point.
+
+However, @code{alias} is limited to aliasing commands only, so it is not
+possible to type something like
+
+@example
+alias bin 'set if bin'
+@end example
+
+Also see @ref{unalias}.
+
+
+@node capture, clear, alias, Command Overview
+@comment node-name, next, previous, up
+@section @code{capture}
+
+@code{capture} @option{file} @file{filename}
+
+When invoked in this manner, @code{capture} starts capturing data
+recieved from the serial port to @file{filename}. Only one file may be
+open at a time.
+
+@code{capture} @option{file} @option{off}
+
+This causes @code{Tap} to stop capturing data and to close the file.
+
+@code{capture} @option{register} @option{1--64}
+
+@code{capture}, when invoked like this, will cause @code{Tap} to start
+capturing data to a register. Data is captured until it is turned off,
+as described below, or the register is full. The size of the registers
+may be changed by using the command @code{set}.
+
+@code{capture} @option{register} @option{off}
+
+This stops the capturing to the register.
+
+
+@xref{set}, and @ref{The Set Command}.
+
+@node clear, close, capture, Command Overview
+@comment node-name, next, previous, up
+@section @code{clear}
+
+@code{clear}
+
+Invoking clear will clear the input window.
+
+@xref{C-L}.
+
+
+@node close, help, clear, Command Overview
+@comment node-name, next, previous, up
+@section @code{close}
+
+@code{close}
+
+This command closes the currently open serial port.
+
+
+@node help, open, close, Command Overview
+@comment node-name, next, previous, up
+@section @code{help}
+
+@code{help}
+
+When invoked without a command name, @code{help} prints a short
+description of every command.
+
+@code{help} @option{command name}
+
+This provides help on individual commands.
+
+
+@node open, out, help, Command Overview
+@comment node-name, next, previous, up
+@section @code{open}
+
+@code{open} @option{serial port}
+
+@code{open} opens a serial port and prepares it for communication. The
+properties of the serial port may be changed with the command
+@code{set}.
+
+@xref{set}.
+
+
+@node out, print, open, Command Overview
+@comment node-name, next, previous, up
+@section @code{out}
+
+@code{out} @option{data}
+
+The @code{out} command writes data to the serial port.
+
+@xref{Input and Output}.
+
+
+@node print, quit, out, Command Overview
+@comment node-name, next, previous, up
+@section @code{print}
+
+@code{print} @option{file}
+
+If a file is currently being captured to, this will print the contents
+of that file. If no file is open, then an error will be thrown.
+
+@code{print} @option{file} @file{filename}
+
+This prints the contents of the file specified in @file{filename}.
+
+@code{print} @option{file} @file{filename} @option{bytes}
+
+This does the same as above, but only prints the first @option{bytes}
+number of bytes.
+
+@code{print} @option{register}
+
+If a register is currently being captured to, this will print its
+contents. If one isn't being used, then an error will be thrown.
+
+@code{print} @option{register} @option{register number}
+
+This will print the contents of the register specified.
+
+@code{print} @option{register} @option{register number} @option{bytes}
+
+This will print the first @option{bytes} number of bytes of the
+specified register.
+
+
+@node quit, set, print, Command Overview
+@comment node-name, next, previous, up
+@section @code{quit}
+
+@code{quit}
+
+This command quits the program, closing any open files and the serial
+port, if one is open.
+
+
+@node set, unalias, quit, Command Overview
+@comment node-name, next, previous, up
+@section @code{set}
+
+@code{set} @option{options}
+
+The @code{set} command adjusts various run time parameters of
+@code{Tap}. @xref{The Set Command}, for a full explanation.
+
+
+@node unalias, , set, Command Overview
+@comment node-name, next, previous, up
+@section @code{unalias}
+
+@code{unalias} @option{alias}
+
+The @code{unalias} command removes the alias @option{alias} from the
+alias list.
+
+
+@node Input and Output, The Set Command, Command Overview, Top
+@comment node-name, next, previous, up
+@chapter Input and Output
+
+
+
+@node The Set Command, Index, Input and Output, Top
+@comment node-name, next, previous, up
+@chapter The Set Command
+
+Often, while working with @code{Tap}, you will find that you might want
+to change some of the operational parameters.
+
+@node Index, , The Set Command, Top
+@comment node-name, next, previous, up
+@unnumbered Command, Concept, and Keystroke Index
+
+@printindex cp
+
+@contents
+@bye
diff --git a/tap/ui.c b/tap/ui.c
new file mode 100755
index 0000000..02822ec
--- /dev/null
+++ b/tap/ui.c
@@ -0,0 +1,369 @@
+/* ui.c
+ * This is everything concerned with the visual part of Tap's
+ * user interface (almost).
+ */
+
+/* Copyright (C) 1999 Jonathan duSaint
+ *
+ * This file is part of Tap, an interactive program for reading and
+ * writing data to the serial port to facilitate the reverse
+ * engineering of communication protocols.
+ *
+ * Tap is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Tap is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * The GNU General Public License is generally kept in a file called
+ * COPYING or LICENSE. If you do not have a copy of the license, write
+ * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tap.h"
+
+/* global variables used to determine window dimensions */
+int window_height;
+int window_width;
+
+/* used when in passive mode */
+int saved_window_height;
+
+/* the windows where all of the action takes place */
+WINDOW *input_window;
+WINDOW *output_window;
+
+/* just header/footer information */
+WINDOW *status_bar;
+WINDOW *input_header;
+WINDOW *output_header;
+
+/* this is displayed if there are an even number of lines in the terminal */
+WINDOW *title_bar = NULL;
+
+
+/* Write HOW_MUCH bytes from serial_buffer to output_window using
+ * the default format.
+ */
+void
+write_to_output_window (int how_much)
+{
+ char *inpb, *outb = NULL;
+
+ inpb = xmalloc (how_much + 1);
+
+ strncpy (inpb, serial_buffer, how_much);
+ inpb[how_much] = 0;
+
+ switch (output_format)
+ {
+ case BIN:
+ outb = translate_to_bin (inpb);
+ break;
+ case OCT:
+ outb = translate_to_oct (inpb);
+ break;
+ case HEX:
+ outb = translate_to_hex (inpb);
+ break;
+ case ASCII_RAW:
+ outb = translate_to_ascii_raw (inpb);
+ break;
+ case ASCII_COOKED:
+ outb = translate_to_ascii_cooked (inpb);
+ }
+
+ waddstr (output_window, outb);
+ wrefresh (output_window);
+
+ xfree (outb);
+ xfree (inpb);
+
+ wrefresh (input_window); /* transfer control back to input_window */
+}
+
+/* The next three functions are for displaying a series of
+ * lines with pagination.
+ */
+
+/* The number of lines which have been printed. */
+int lines_printed;
+
+/* Initialize pagination */
+void
+page_init (void)
+{
+ lines_printed = 0;
+}
+
+/* Called after a single line has been printed. Returns 0 if
+ * it is OK to keep printing lines, otherwise 1.
+ */
+int
+page_line_printed (void)
+{
+ int answer;
+
+ lines_printed++;
+
+ /* a full page has been output */
+ if (!((lines_printed + 1) % window_height))
+ {
+ waddstr (input_window, "press any key to continue, <q> to quit: ");
+ answer = sgetch ();
+ waddch (input_window, '\n');
+
+ if (answer == 'q' || answer == 'Q') return (1);
+
+ clear_scr (NULL);
+ lines_printed = 0;
+ }
+
+ return (0);
+}
+
+/* Finalize. This isn't always necessary to call. */
+void
+page_finalize (void)
+{
+ lines_printed = 0;
+}
+
+/* Print a multiline string to WINDOW with pagination. */
+void
+wprintstr (WINDOW *window, char *string)
+{
+ char *work_area;
+ int start = 0, end = 0;
+
+ work_area = xmalloc (strlen (string) + 2);
+
+ strcpy (work_area, string);
+
+ if (string[strlen (string) - 1] != '\n')
+ {
+ work_area[strlen (string)] = '\n';
+ work_area[strlen (string) + 1] = 0;
+ }
+
+ page_init ();
+
+ while (1)
+ {
+ while (work_area[end] != '\n') end++;
+
+ work_area[end] = 0;
+
+ wprintw (window, "%s\n", work_area + start);
+
+ start = ++end;
+
+ if (page_line_printed ()) break;
+ if (work_area[start] == 0) break;
+ }
+
+ page_finalize ();
+
+ xfree (work_area);
+}
+
+/* beep and print a message */
+void
+inp_error (char *msg)
+{
+ beep ();
+
+ wprintw (input_window, "?? %s\n", msg);
+ wrefresh (input_window);
+}
+
+/* just beep */
+void
+warning_beep (void)
+{
+ beep ();
+}
+
+/* This is used when going from passive mode into active mode. Changes
+ * the dimensions of input_window.
+ */
+void
+ui_expand_input_window (void)
+{
+ int pad;
+ WINDOW *twoutput, *twinput;
+
+ window_height = saved_window_height;
+ pad = 1 - (LINES % 2);
+
+ twinput = newwin (window_height, window_width, pad + 1, 0);
+
+ mvwin (output_header, window_height + pad + 1, 0);
+
+ twoutput = newwin (window_height, window_width, window_height + pad + 2, 0);
+
+ scrollok (twinput, TRUE);
+ scrollok (twoutput, TRUE);
+
+ delwin (input_window);
+ delwin (output_window);
+
+ input_window = twinput;
+ output_window = twoutput;
+
+ wrefresh (input_window);
+ wrefresh (output_header);
+ wrefresh (output_window);
+
+ return;
+}
+
+/* This is used when going from active mode into passive mode. Changes
+ * the dimensions of input_window.
+ */
+void
+ui_shrink_input_window (void)
+{
+ int pad;
+ WINDOW *twoutput, *twinput;
+
+ if (window_height - 5 < 1) return;
+
+ saved_window_height = window_height;
+ window_height = 5;
+
+ pad = 1 - (LINES % 2);
+
+ twinput = newwin (window_height, window_width, pad + 1, 0);
+
+ mvwin (output_header, window_height + pad + 1, 0);
+
+ twoutput = newwin (2 * saved_window_height - 5, window_width,
+ window_height + pad + 2, 0);
+
+ scrollok (twinput, TRUE);
+ scrollok (twoutput, TRUE);
+
+ delwin (input_window);
+ delwin (output_window);
+
+ input_window = twinput;
+ output_window = twoutput;
+
+ wrefresh (input_window);
+ wrefresh (output_header);
+ wrefresh (output_window);
+
+ return;
+}
+
+/* set up the user interface */
+void
+init_console_ui (void)
+{
+ int io_win_height, k, pad = 0;
+
+ if ((LINES < 11) || (COLS < 70))
+ {
+ fprintf (stderr, "%s: window too small to be of use\n", pname);
+ endwin ();
+ exit (1);
+ }
+
+ /* the display should look something like
+ *
+ * ----------- title bar --------------
+ * | input header |
+ * | |
+ * | input area |
+ * | |
+ * | output header |
+ * | |
+ * | output area |
+ * | |
+ * ---- status area -------------------
+ *
+ * although if there are an odd number of lines in the terminal,
+ * then there will be no title bar
+ */
+
+ io_win_height = ((LINES / 2) + ((LINES % 2) - 1)) - 1;
+
+ /* create title if space permits */
+ if (!(LINES % 2))
+ {
+ pad = 1;
+ title_bar = newwin (1, COLS, 0, 0);
+ wattron (title_bar, A_REVERSE);
+ for (k = 0; k < (COLS - 32) / 2; k++) waddch (title_bar, ' ');
+ waddstr (title_bar, "*** tap - serial line tapper ***");
+ for (k = 0; k < (COLS - 32) / 2; k++) waddch (title_bar, ' ');
+ wrefresh (title_bar);
+ }
+
+ input_header = newwin (1, COLS, pad, 0);
+ wattron (input_header, A_REVERSE);
+ waddstr (input_header, "+++ to serial port ");
+ for (k = 19; k < COLS; k++) waddch (input_header, '+');
+ wrefresh (input_header);
+
+ input_window = newwin (io_win_height, COLS, 1 + pad, 0);
+ scrollok (input_window, TRUE);
+
+ output_header = newwin (1, COLS, io_win_height + pad + 1, 0);
+ wattron (output_header, A_REVERSE);
+ waddstr (output_header, "+++ from serial port ");
+ for (k = 21; k < COLS; k++) waddch (output_header, '+');
+ wrefresh (output_header);
+
+ output_window = newwin (io_win_height, COLS, io_win_height + pad + 2, 0);
+ scrollok (output_window, TRUE);
+
+ status_bar = newwin (1, COLS, LINES - 1, 0);
+ wattron (status_bar, A_REVERSE);
+
+ window_height = io_win_height;
+ window_width = COLS;
+}
+
+/* clean up the user interface */
+void
+destroy_console_ui (void)
+{
+ delwin (input_window);
+ delwin (output_window);
+ delwin (status_bar);
+ delwin (input_header);
+ delwin (output_header);
+
+ if (title_bar != NULL) delwin (title_bar);
+}
+
+
+/* periodically refresh the status bar */
+void
+refresh_console_status_line (void)
+{
+ int k, len;
+
+ if (port == NULL)
+ {
+ waddstr (status_bar, "+++ no serial port open ");
+ len = 24;
+ }
+ else
+ {
+ len = 5 + strlen (port);
+ wprintw (status_bar, "+++ %s ", port);
+ }
+
+ for (k = 0; k < COLS - (len + 25); k++) waddch (status_bar, '+');
+ waddstr (status_bar, " type `help' for help +++");
+ wrefresh (status_bar);
+
+ wmove (status_bar, 0, 0);
+}
diff --git a/tap/version.h b/tap/version.h
new file mode 100755
index 0000000..9afb71a
--- /dev/null
+++ b/tap/version.h
@@ -0,0 +1 @@
+char version[] = "1.0pre1";