[mod.sources] v07i014: Binary

sources-request@mirror.UUCP (09/02/86)

Submitted by: pyramid!lukeII!itkin (Steven List)
Mod.sources: Volume 7, Issue 14
Archive-name: bpatch



[  See me notes at the end of the README.  --r$  ]

#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".

# Exit status; set to 1 on "wc" errors or if would overwrite.
STATUS=0
# Contents:  README Makefile bpatch.1 bpatch.c
 
echo x - README
if test -f README ; then
    echo README exists, putting output in $$README
    OUT=$$README
    STATUS=1
else
    OUT=README
fi
sed 's/^XX//' > $OUT <<'@//E*O*F README//'
XXHerewith find BPATCH - a marvelously utile utility.  While not of
XXmy original creation, I have been given permission to place in the
XXpublic domain.  I have made substantial modifications to the original
XXsource given to me.  Specifically I cleaned it up a bit and made it
XXwork with SVR2 curses.  Personally, I think it's pretty neat.

XXOK - for those of you who may scream by now "WHAT THE HELL IS IT ALREADY?"
XXI respond that it is a binary file editor and dump utility!  That's 
XXright!  You can dump your file in the nicely laid out side-by-side
XXhex and ascii format or you can actually EDIT it at your terminal!
XXYes, I have seen the BED editor that came across the network.
XXUnfortunately, it converted the entire file before and after editing.
XXBpatch, on the other hand, works with one 256 byte page at a time.
XXIt is marvelously useful for looking at things like raw disk UNIFY
XXdatabases and even raw disks!  While the man page may not be absolutely
XXup to date, the online help is.  Try the question mark (?) command.

XXAs always, I would love to hear about bugs/changes/enhancements/requests.
XX	Steven List @ Benetics Corporation, Mt. View, CA
XX	Just part of the stock at "Uncle Bene's Farm"
XX	{cdp,engfocus,idi,oliveb,opusys,plx,pyramid,tolerant}!bene!luke!itkin

XXAddition by the moderator:
XXI have added code, surrounded by #ifdef MOD_HAX, that gets bpatch
XX(barely?) working on my 4.2 system.  I would be very interested in
XXpublishing a set of diffs that's less of a hack.  Oh yeah:  I also
XXwrote the Makefile.
XX	/Rich $alz
@//E*O*F README//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - Makefile
if test -f Makefile ; then
    echo Makefile exists, putting output in $$Makefile
    OUT=$$Makefile
    STATUS=1
else
    OUT=Makefile
fi
sed 's/^XX//' > $OUT <<'@//E*O*F Makefile//'
XX# This may have to change on your system.
XX# You may have to fiddle with various combinations of curses, termcap,
XX# terminfo, etc.  Good luck!
XXLIBS	= -lcurses -ltermcap
XX#LIBS	= -ltermlib
XX#LIBS	= -lterminfo

XX# However you need getopt.
XXGETOPT	= -lgetopt

XX# If you're running on a 4.[23] system, you probably want this.
XXWORK	= -DMOD_HAX

XXCFLAGS	= -O $(WORK)

XXbpatch:		bpatch.o
XX	$(CC) -o bpatch $(CFLAGS) bpatch.o $(GETOPT) $(LIBS)

XXinstall:
XX	@echo Use cp to put things where you want them
@//E*O*F Makefile//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - bpatch.1
if test -f bpatch.1 ; then
    echo bpatch.1 exists, putting output in $$bpatch.1
    OUT=$$bpatch.1
    STATUS=1
else
    OUT=bpatch.1
fi
sed 's/^XX//' > $OUT <<'@//E*O*F bpatch.1//'
XX.TH "bpatch" "1" "Benetics Local"
XX.if t .nr LL 7i
XX.if t .nr IN .8i
XX.if n .nr LL 70
XX.if n .nr IN 8
XX.fi
XX.ad b
XX.SH NAME
XXbpatch - binary patch and dump file utility
XX.SH SYNOPSIS
XXbpatch [ -b blksize ] [ -d ] [ -D pagecnt ] [ -e ] [ -p ] [ -r reclen ] [ -s ] [ -x ] file...
XX.SH DESCRIPTION
XX\fIBpatch\fR allows the viewing and/or modification of files, independent of
XXfile type (text, executable, data file, and so forth).  \fIBpatch\fR
XXallows the data to either be examined at the terminal, dumped to a print
XXdevice or file, or edited in the general manner of \fIvi(1)\fR.  The
XXdata in the file is dumped or displayed in \fIpages\fR of 256 bytes.
XX.SS Options
XX.IP "-b blksize" 12
XXThe \fI-b\fR option specifies the blocksize of the data file.  This is used
XXprimarily with tapes, and is allowed only with one of the dump (\fI-d\fR
XXor \fI-D\fR) options.  When this option is specified, the file is opened
XXin readonly mode.
XX.IP "-d" 12
XXThe \fI-d\fR option indicates that a dump (no terminal manipulation) is
XXto be performed.  The entire file will be dumped to standard output.  No
XXediting of the data is allowed and the file is opened in readonly mode.
XX.IP "-D pagecnt" 12
XXThe \fI-D\fR option is similar to the \fI-d\fR option, with the
XXfollowing exception: the pagecnt argument limits the dump to the
XXspecified number of \fIpages\fR.
XX.IP "-e" 12
XXThe \fI-e\fR option indicates that the file contains EBCDIC data and
XXshould be converted in the character portion of the dump.
XX.IP "-p" 12
XXUsed with one of the \fIdump\fR options, this option causes the program
XXto pause between \fIpages\fR.  The program will then wait for the user
XXto press either the \fIreturn\fR key to continue, or the \fIDEL\fR (or
XX\fIrubout\fR) key to stop the dump.
XX.IP "-r reclen" 12
XXThe \fI-r\fR option indicates the record length of the data within the
XXdump.  When specified, this option causes \fIbpatch\fR to place a colon
XX(:) between the last byte of one record and the first byte of the next.
XX.IP "-s" 12
XXThis option turns on the byte swap option.  It may be toggled dynamically
XXduring execution (see \fI-x\fP under Commands below).
XX.IP "-x" 12
XXThis option specifies the suppression of pages that contain only NUL
XXcharacters.  The result is that only the page header (name and page
XXnumber) will appear for such a page.  This option may only be used with
XXone of the dump options.
XX.SS Arguments
XX.IP file 12
XXAny number of files may be specified.
XX.SS Commands
XXAll commands are valid only in the non-dump, interactive mode.  Commands
XXmay be entered in either upper or lower case.  Commands of the form '^x'
XXindicate that the control character \fIx\fR is to be entered.
XX.P
XXAll commands that request movement within a file or between files cannot
XXbe executed if any changes have been made.  To proceed in this case, the
XXuser must either enter the \fIw\fR command, the \fIu\fR command, or the
XX\fIr\fR command.
XX.P
XXRequesting a next or previous file when there is no such will cause the
XXissuance of an error message.
XX.P
XXNote that certain commands allow/require either some text or numeric
XXvalue.  In those cases, the user should type in characters and end the
XXstring with either a <cr> or <DEL>.
XX.IP ? 6
XXDisplay the help screen.  The help screen will remain until the user
XXeither redraws the screen (see \fI^r\fR) or changes pages or files.
XX.IP ! 6
XXExecute the following command in the shell.
XX.IP backslash 6
XXDisplay the previous page.
XX.IP <cr> 6
XXDisplay the next page.
XX.IP DEL 6
XXQuit the program if no changes have been made.
XX.IP / 6
XXThis command initiates an ASCII search.  The text entered on the command
XXline will be used as a search string, and the file will be searched
XXstarting with the current page.  When the string is found, the page
XXcontaining the string will be displayed.  If the string is not found, an
XXapapropriate message will be displayed.
XX.IP ^f 6
XXOpen a named file whose name will be entered on the command line and
XXfollowed either by <cr> or DEL.
XX.IP ^n 6
XXOpen the next file and display the first page.
XX.IP ^p 6
XXOpen the previous file and display the first page.
XX.IP ^q 6
XXQuit without writing current changes.
XX.IP ^r 6
XXRedraw the screen.
XX.IP NNN 6
XXEntering a numeric value requests that the specified page be displayed.
XX.IP -x 6
XXToggle the command line option represented by \fIx\fR:
XX.RS 12
XX.IP a 6
XXToggle display to ascii (assume data is ascii).
XX.IP e 6
XXToggle display to dbcdic (assume data is ebcdic).
XX.IP s 6
XXToggle byte swap.
XX.RE
XX.IP a 6
XXEdit the ASCII display.  End edits by pressing the DEL key.  All other
XXcharacters will be treated as valid input.  Cursor movement keys (arrows
XXand home) allow movement within the edit window.  Nonprinting
XXcharacters are displayed as dot (.) in this window.
XX.IP f 6
XXDisplay the first page in the current file.
XX.IP g 6
XXDisplay the page containing the byte address typed in following the command.
XX.IP h 6
XXEdit the HEXADECIMAL display.  End edits by pressing DEL key.  Cursor
XXmovement keys (arrows and home) allow movement within the edit window.
XXTwo keystrokes are required to modify a byte, and both must be valid
XXhexadecimal values (0-9 and a-f).  To cancel a change after typing one
XXcharacter, press DEL.
XX.IP l 6
XXDisplay the last page in the current file.
XX.IP q 6
XXQuit the file.  A warning will be issued if any changes have been made
XXbut not written out.
XX.IP r 6
XXReread the current page.
XX.IP u 6
XXUndo all changes to the current page.
XX.IP w 6
XXWrite out the current page.
XX.SH "SEE ALSO"
XXod(1)
@//E*O*F bpatch.1//
chmod u=rw,g=rw,o=rw $OUT
 
echo x - bpatch.c
if test -f bpatch.c ; then
    echo bpatch.c exists, putting output in $$bpatch.c
    OUT=$$bpatch.c
    STATUS=1
else
    OUT=bpatch.c
fi
sed 's/^XX//' > $OUT <<'@//E*O*F bpatch.c//'
XX/*T bpatch - A binary file patch/dump utility */
XX/*S Introduction */
XX/*F bpatch ***********************************************************
XX* bpatch
XX* by Garry M Johnson - 09/17/84
XX* (C) Copyright 1984, 1985
XX*
XX* Change History:
XX*  03/05/86 - added further terminal independence
XX*             added use of ioctl (see main and mstdin)
XX*             added -D versus -d command line option
XX*             added use of standard getopt
XX*             cleaned up code, eliminated function "ikf"
XX*             added original versions of ezlib functions, such as
XX*               icc, setterm, cm, mstdin, erase, length, move
XX*             added ^R, ^Q, ^N, and ^P commands
XX*             added ^F, !, and ^X (-X) commands
XX*			  changed name to "bpatch"
XX*			  added direct address command (g)
XX*             added ASCII search capability
XX*  07/07/86 - converted to use curses
XX*             modified direct addressing to use suffixes
XX*             updated HELP function
XX*
XX*   Steven List @ Benetics Corporation, Mt. View, CA
XX*   {cdp,engfocus,idi,oliveb,plx,tolerant}!bene!luke!itkin
XX*********************************************************************/
XX/*E*/
XX/*S includes, globals, and defines */
XX/*Page Eject*/
XX#include	<curses.h>
XX#include <fcntl.h>
XX#include <signal.h>
XX#include <ctype.h>
XX#include <sys/types.h>
XX#include <sys/stat.h>

XXstatic int pbrk = 0;
XXstruct stat sb;

XXvoid icc ();
XXvoid copyrec ();
XXvoid schwapp ();

XX	/* ------------------------------------------------------------ */
XX	/* Some defines added by the moderator to get it work on 4.2    */
XX	/* ------------------------------------------------------------ */
XX#ifdef	MOD_HAX
XX    /* Fifos?  We ain't got no steenkin' fifos. */
XX#define S_IFIFO		123450
XX    /* "Spelling differences." */
XX#define beep()		fprintf (stderr, "\007")
XX#define cbreak()	crmode()
XX    /* Our curses doesn't translate keypad keys to single characters. */
XX#define keypad(a, b)	/* null */
XX#define KEY_UP		'^'
XX#define KEY_DOWN	'v'
XX#define KEY_LEFT	'<'
XX#define KEY_RIGHT	'>'
XX#define KEY_HOME	'@'
XX#endif	/* MOD_HAX */


XX	/* ------------------------------------------------------------ */
XX	/* Some convenient defines                                      */
XX	/* ------------------------------------------------------------ */

XX#define DEL '\177'
XX#define HEX 1
XX#define ALPHA 0

XX	/* ------------------------------------------------------------ */
XX	/* general purpose identification and control variables         */
XX	/* ------------------------------------------------------------ */

XXchar	filename[64];			/* current file being examined		*/
XXchar	record[16][16];			/* record (page) buffer				*/
XXchar	unch_rec[16][16];		/* record before any changes		*/
XXint 	zp;						/* current input character			*/

XXint		block = 0;				/* block size if -b in command		*/
XXint		block_spec;				/* true if file is block special	*/
XXint		bytes = 0;				/* number of bytes from last read	*/
XXint		char_spec;				/* true if file is char special		*/
XXint		debug = 0;				/* true if debug is turned on		*/
XXint		dir_spec;				/* true if file is directory		*/
XXint		dump = 0;				/* nonzero if dump instead of change*/
XXint		ebcdic = 0;				/* true if -e option				*/
XXint		fifo_spec;				/* true if file is fifo				*/
XXint		honly = 0;				/* true if dump is to be hex only	*/
XXint		mod = 0;				/* true if record has been modified	*/
XXint		pause = 0;				/* true if -p option				*/
XXint		rawfile = 0;			/* true if file is c/b/p			*/
XXint		reclen = 0;				/* record length, if -r				*/
XXint		recno = 0;				/* current record (page) number		*/
XXint		stay = 0;				/* true if no position change 		*/
XXint		swab = 0;				/* true if byte swapping is on		*/
XXint		windowed = 0;			/* true if windowing - not dump		*/

XXlong	position = 0;			/* byte address in file				*/

XXWINDOW *hexwin = NULL;
XXWINDOW *alphawin = NULL;
XXWINDOW *errwin = NULL;

XX/*S main - control all the work from here */
XX/*H main *************************************************************
XX*
XX*                            main
XX*
XX*	set up the globals, initilize the state, and process the file
XX*
XX*********************************************************************/
XX/*E*/
XXmain (argc, argv)
XXint argc;
XXchar *argv[];
XX{
XX	extern WINDOW *subwin ();
XX	extern WINDOW *newwin ();

XX#ifdef	MOD_HAX
XX#else	/* use original code... */
XX	struct termio asis;
XX#endif	/* MOD_HAX */

XX	register char	*cp;				/* general purpose char ptr	*/
XX	extern   char	*gets ();			/* get string from stdin	*/
XX	         char	m = '\017';			/* mask for hex edit		*/
XX	         char	response[512];		/* general purpose buffer	*/
XX	         int 	z;					/* character read in		*/
XX         
XX	int		breakp ();			/* signal trapping function			*/
XX	int		c;					/* current screen column			*/
XX	int		change = 0;			/* true if cmd line option toggled	*/
XX	int		fid;				/* file descriptor					*/
XX	int		firstfile;			/* arg # of first file in cmd line	*/
XX	int		h;					/* temp for hex edit				*/
XX	int		i;					/* general purpose loop index		*/
XX	int		j;					/* general purpose loop index		*/
XX	int		r;					/* current screen row				*/
XX	int		hexc;				/* current cursor column in hexwin	*/

XX	long	byteaddr;			/* planned byte address for 'G'		*/
XX	long	size;				/* file size in bytes				*/
XX	long	status;				/* EOF if at end of file or error	*/

XX	extern int optind;			/* getopt index into argv			*/
XX	extern char *optarg;		/* getopt pointer to opt arg		*/

XX	extern long getnum ();
XX	extern char *instr ();		/* get a string from the cmd line	*/
XX	extern int reset ();		/* exit function - reset terminal	*/

XX	/* ------------------------------------------------------------ */
XX	/* set up signal handling                                       */
XX	/* ------------------------------------------------------------ */

XX	if (!dump) signal (SIGINT, breakp);

XX	signal (SIGTERM, reset);

XX	/* ------------------------------------------------------------ */
XX	/* process command line arguments                               */
XX	/* ------------------------------------------------------------ */

XX	while ((i = getopt (argc, argv, "r:dD:b:pxXse")) != EOF)
XX	{
XX		switch (i)
XX		{
XX			case	'b':		/* blocking					*/
XX				block = atoi (optarg);
XX				if (block < 1 || block > 10240)
XX				{
XX					fprintf (stderr,
XX						"invalid block size: %d\n", block);
XX					exit (1);
XX				}
XX				break;
XX			case	'd':		/* straight dump - no limit	*/
XX				dump = -1;
XX				break;
XX			case	'D':		/* dump - page count spec	*/
XX				dump = atoi (optarg);
XX				break;
XX			case	'e':		/* file is ebcdic			*/
XX				ebcdic = 1;
XX				break;
XX			case	'p':		/* pause between pages - dump	*/
XX				pause = 1;
XX				break;
XX			case	'r':		/* record length for dump		*/
XX				reclen = atoi (optarg);
XX				break;
XX			case	's':		/* byte swapping required		*/
XX				swab = 1;
XX				break;
XX			case	'x':		/* hex dump only				*/
XX				honly = 1;
XX				break;
XX			case	'X':
XX				debug = 1;
XX				break;
XX			default:			/* uhoh							*/
XX				fprintf (stderr,
XX"usage: bpatch [ -b blocksz ] [ -d<ump> ] [ -D pagecnt ] [ -e<bcdic> ]\n");
XX				fprintf (stderr,
XX"              [ -p<ause> ] [ -r reclen ] [ -s<wap bytes> ] [ -x<only> ]\n");
XX				exit (1);
XX		}
XX	}

XX	/* ------------------------------------------------------------ */
XX	/* check for valid combinations of options                      */
XX	/* ------------------------------------------------------------ */

XX	if ((honly || block || reclen || pause ) && !dump)
XX	{
XX		fprintf (stderr, "-x|-b|-r|-p requires -d or -D\n");
XX		exit (2);
XX	}

XX	/* ------------------------------------------------------------ */
XX	/* At least one file name must be specified on the cmd line     */
XX	/* ------------------------------------------------------------ */

XX	if (optind == argc)
XX	{
XX		fprintf (stderr, "no file name(s) specified\n");
XX		exit (2);
XX	}

XX	/* ------------------------------------------------------------ */
XX	/* set up the screen, if this is an interactive session         */
XX	/* ------------------------------------------------------------ */

XX	if (!dump)
XX	{
XX		windowed = 1;
XX		initscr ();
XX		nonl ();
XX		noecho ();
XX		cbreak ();
XX		keypad (stdscr, TRUE);
XX		hexwin = subwin (stdscr, 16, 48, 4, 4);
XX		keypad (hexwin, TRUE);
XX		alphawin = subwin (stdscr, 16, 16, 4, 57);
XX		keypad (alphawin, TRUE);
XX		errwin = subwin (stdscr, 1, 80, 23, 0);

XX#ifdef	MOD_HAX
XX		/* This is not exactly what the original code does,
XX		   but it's good enough.  -r$ */
XX		raw();
XX#else	/* use original code... */
XX		ioctl (0, TCGETA, &asis);
XX		asis.c_cc[VINTR] = '\0';
XX		asis.c_iflag &= ~IXON;
XX		asis.c_iflag &= ~IXOFF;
XX		asis.c_iflag &= ~IXANY;
XX		ioctl (0, TCSETA, &asis);
XX#endif	/* MOD_HAX */
XX	}

XX	/* ------------------------------------------------------------ */
XX	/* save the first file's index for backing up later             */
XX	/* ------------------------------------------------------------ */

XX	firstfile = optind;

XX	/* ------------------------------------------------------------ */
XX	/* open the first file                                          */
XX	/* ------------------------------------------------------------ */

XX	for (fid = -1; fid < 0 && optind < argc;)
XX	{
XX		fid = ckfile (argv[optind], &size);
XX		if (fid < 0) optind++;
XX	}
XX	if (fid < 0)
XX	{
XX		fprintf (stderr, "could not handle the file list\n");
XX		exit (2);
XX	}

XX	strncpy (filename, argv[optind], sizeof filename);

XX	if (block != 0)
XX	{
XX		size = -1;
XX	}

XX	recno = 0;
XX	stay = 0;
XX	mod = 0;
XX	status = 0;

XX	/* ------------------------------------------------------------ */
XX	/* Until the user exits...                                      */
XX	/* ------------------------------------------------------------ */

XX	if (!dump) clear ();

XX	while (status != EOF)
XX	{
XX	/* ------------------------------------------------------------ */
XX	/* change of location - read and display                        */
XX	/* ------------------------------------------------------------ */
XX		if (stay == 0)
XX		{
XX			position = lseek (fid, (long)(recno * 256), 0);

XX			if ((bytes = bread (fid, record, 256, block)) < 0)
XX			{
XX				errmsg ("error on reading file %s", filename);
XX				status = EOF;
XX				continue;
XX			}
XX			if (bytes > 0)
XX			{
XX				if (swab) schwapp (record, 256);

XX				copyrec (record, unch_rec, sizeof record);

XX				show (bytes, record, filename, size, recno,
XX						position, m,reclen, dump, ebcdic, swab,
XX						block, honly);
XX			}
XX			mod = 0;
XX		}
XX	/* ------------------------------------------------------------ */
XX	/* not interactive - keep dumping or open next file             */
XX	/* ------------------------------------------------------------ */
XX		if (dump)
XX		{
XX			if ((dump < 0 && bytes == 0) || (--dump == 0))
XX			{
XX				if (optind == argc) status = EOF;
XX				else
XX				{
XX					close (fid);
XX					fid = -1;
XX					for (optind++; fid < 0 && optind < argc;)
XX					{
XX						fid = ckfile (argv[optind], &size);
XX						if (fid < 0) optind++;
XX					}

XX					strncpy (filename, argv[optind], sizeof filename);

XX					if (block != 0)
XX					{
XX						size = -1;
XX					}
XX					recno = 0;
XX					stay = 0;
XX					status = lseek (fid, (long)0, 0);
XX				}
XX			}
XX			++recno;
XX	/* ------------------------------------------------------------ */
XX	/* if pause, beep and wait                                      */
XX	/* ------------------------------------------------------------ */
XX			if (status != EOF && pause)
XX			{
XX				pbrk = 0;
XX				fprintf (stderr, "\007");
XX				gets (response);

XX				if (pbrk) status = EOF;
XX			}

XX			continue;
XX		}
XX	/* ------------------------------------------------------------ */
XX	/* if we got here, this is an interactive session               */
XX	/* ------------------------------------------------------------ */
XX		stay = 0;
XX		move (22, 0);
XX	/* ------------------------------------------------------------ */
XX	/* get the user's command                                       */
XX	/* ------------------------------------------------------------ */
XX		response[0] = EOF;
XX		mvaddstr (22, 0, "> ");
XX		clrtoeol ();
XX		refresh ();
XX		zp = getch ();

XX		if (debug && !dump)
XX		{
XX			if (isascii (zp) && isprint (zp))
XX				errmsg ("command entered is %c", zp);
XX			else errmsg ("command entered is ^%c (%#x)", zp + '@', zp);
XX			getch ();
XX		}

XX		if (isascii (zp) && isalpha (zp) && islower (zp))
XX			zp = toupper (zp);
XX	/* ------------------------------------------------------------ */
XX	/* here we go - what does the user want?                        */
XX	/* ------------------------------------------------------------ */
XX		refresh ();

XX		switch (zp)
XX		{ 
XX			case	'!':			/* shell escape				*/
XX				echo ();
XX				move (23,0);
XX				clrtoeol ();
XX				addstr ("shell command: ");
XX				refresh ();
XX				getstr (response);
XX				erase ();
XX				refresh ();
XX				nl ();
XX				system (response);
XX				noecho ();
XX				nonl ();
XX				move (23,0);
XX				standout ();
XX				addstr (" <Press any key> ");
XX				standend ();
XX				clrtoeol ();
XX				refresh ();
XX				getch ();
XX				clear ();
XX				break;

XX			case	'?':			/* HELP						*/
XX				dbg_msg ("Help");
XX				dohelp ();
XX				touchwin (stdscr);
XX				refresh ();
XX				stay = 1;
XX				break;

XX			case	'/':			/* search for a string		*/
XX				stay = 1;
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX				}
XX				else search (fid, zp);
XX				break;

XX			case '-':				/* toggle options			*/
XX				zp = getch ();
XX				stay = 1;
XX				change = 0;
XX				switch (zp)
XX				{
XX					case 'a': /* ascii */
XX						if (ebcdic)
XX						{
XX							dbg_msg ("toggle to ascii");
XX							change = 1;
XX						}
XX						ebcdic = 0;
XX						break;

XX					case 'e': /* ebcdic */
XX						if (ebcdic == 0)
XX						{
XX							dbg_msg ("toggle to ebcdic");
XX							change = 1;
XX						}
XX						ebcdic = 1;
XX						break;

XX					case 's': /* swab */
XX						dbg_msg ("toggle byte swap");
XX						change = 1;
XX						schwapp (record, 256);
XX						swab = !swab;
XX						break;
XX				}
XX				if (change)
XX				{
XX					show (bytes, record, filename, size,
XX							recno, position, m,reclen, dump,
XX							ebcdic, swab, block, honly);
XX				}

XX				break;

XX			case '\022':			/* redraw screen (^R)		*/
XX				clear ();
XX				show (bytes, record, filename, size, recno,
XX					  position, m, reclen, dump, ebcdic,
XX					  swab, block, honly);
XX				stay = 1;
XX				break;
XX			
XX			case	'\030':			/* toggle debug (^X)		*/
XX				debug = !debug;
XX				break;

XX			case	'\006':			/* new file (^F)			*/
XX				close (fid);
XX				fid = ckfile (cp = instr (), &size);
XX				if (fid < 0)
XX				{
XX					fid = ckfile (filename, &size);
XX				}
XX				else
XX				{
XX					strncpy (filename, cp, sizeof filename);
XX					stay = 0;
XX					recno = 0;
XX				}
XX				break;

XX			case	'\016':			/* next file (^N)			*/
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX					stay = 1;
XX				}
XX				else if (optind == (argc - 1))
XX				{
XX					errmsg ("No more files");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					close (fid);
XX					for (fid = -1, optind++; fid < 0 && optind < argc;)
XX					{
XX						fid = ckfile (argv[optind], &size);
XX						if (fid < 0) optind++;
XX					}
XX					if (fid < 0)
XX					{
XX						errmsg ("could not handle the file list");
XX						reset (0);
XX					}
XX					strncpy (filename, argv[optind], sizeof filename);
XX					stay = 0;
XX					recno = 0;
XX				}
XX				break;

XX			case	'\020':			/* prev file (^P)			*/
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX					stay = 1;
XX				}
XX				else if (optind == firstfile)
XX				{
XX					errmsg ("No previous file");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					close (fid);
XX					for (fid = -1, optind--; fid < 0 && optind >= firstfile;)
XX					{
XX						fid = ckfile (argv[optind], &size);
XX						if (fid < 0) optind--;
XX					}
XX					if (fid < 0)
XX					{
XX						errmsg ("could not handle the file list");
XX						reset (0);
XX					}
XX					strncpy (filename, argv[optind], sizeof filename);
XX					stay = 0;
XX					recno = 0;
XX				}
XX				break;

XX			case	'\021':		/* quit absolutely (^Q)		*/
XX				status = EOF;
XX				break;

XX			case DEL:			/* quit with check			*/
XX			case 'Q': /* quit */
XX				if (mod)
XX				{
XX					errmsg ("No write since last change!");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					status = EOF;
XX				}
XX				break;

XX			case '\\': /* back up 1 record */
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					if (recno > 0)
XX					{
XX						--recno;
XX						stay = 0;

XX						status = lseek (fid, (long)recno*256, 0);
XX						if (status < 0)
XX						{
XX							move (22, 0);
XX							clrtoeol ();
XX							perror (filename);
XX							errmsg ("error positioning in file");
XX							beep ();
XX							++recno;
XX							stay = 1;
XX						}
XX					}
XX					else
XX					{
XX						errmsg ("No previous records");
XX						beep ();
XX						stay = 1;
XX					}
XX				}
XX				break; 

XX			case 'F': /* go to first record */
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					status = lseek (fid, (long)0, 0);
XX					recno = 0;
XX				}
XX				break;

XX			case 'L': /* go to last record */
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					position = lseek (fid, (long)0, 2);
XX					recno = position / 256;
XX					j = position % 256;
XX					if (j == 0) --recno;
XX					status = lseek (fid, (long)(recno*256), 0);
XX				}
XX				break;

XX			case 'U':			/* undo changes					*/
XX				stay = 1;
XX				mod = 0;
XX				copyrec (unch_rec, record, sizeof record);
XX				show (bytes, record, filename, size, recno,
XX						position, m,reclen, dump, ebcdic, swab,
XX						block, honly);
XX				break;

XX			case 'R': /* re-read record */
XX				status = lseek (fid, (long)recno*256, 0);
XX				break;

XX			case '0': /* go to some address */
XX			case '1':
XX			case '2':
XX			case '3':
XX			case '4':
XX			case '5':
XX			case '6':
XX			case '7':
XX			case '8':
XX			case '9':
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					byteaddr = getnum (zp, FALSE);
XX					stay = 1;
XX					errmsg ("Position to byte %ld", byteaddr);
XX					if (!rawfile && byteaddr > size)
XX					{
XX						errmsg ("Address outside file");
XX						beep ();
XX					}
XX					else if (byteaddr / 256 != recno)
XX					{
XX						recno = byteaddr / 256;
XX						status = lseek (fid, (long)recno * 256, 0);
XX						stay = 0;
XX					}
XX				}
XX				break;

XX			case 'A': /* alpha modify */
XX				stay = 1;
XX				r = c = 0;
XX				dbg_msg ("edit ascii");
XX				if (bytes == 0) break;
XX				touchwin (stdscr);
XX				refresh ();
XX				wmove (alphawin, r, c);
XX				wrefresh (alphawin);

XX				while ((z = wgetch (alphawin)) != DEL)
XX				{
XX					if (!arrow (z, &r, &c))
XX					{
XX						if (isascii (z))
XX						{
XX							if (isprint (z)) waddch (alphawin, z);
XX							else             waddch (alphawin, '.');

XX							if (ebcdic) icc (&z, 1,"AE");

XX							record[r][c] = z;
XX							mod = 1;

XX							hexc = c * 3;
XX							wmove (hexwin, r, hexc);
XX							if (record[r][c] < '\0')
XX							{
XX								wprintw (hexwin, "%x%x",
XX									(record[r][c] >> 4) & m,
XX									record[r][c] & m);
XX							}
XX							else
XX							{
XX								wprintw (hexwin, "%02x", record[r][c]);
XX							}
XX							wrefresh (hexwin);

XX						}
XX						else
XX						{
XX							beep ();
XX						}

XX						if (c == 15)
XX						{
XX							if (r == 15) beep ();
XX							else
XX							{
XX								c = 0;
XX								++r;
XX							}
XX						}
XX						else
XX						{
XX							c++;
XX						}
XX					}
XX					if (r * 16 + c >= bytes)
XX					{
XX						beep ();
XX						r = (bytes - 1) / 16;
XX						c = (bytes - 1) % 16;
XX					}

XX					wmove (alphawin, r, c);
XX					wrefresh (alphawin);
XX				}

XX				break;

XX			case 'H': /* hex modify */
XX				dbg_msg ("edit hex");
XX				stay = 1;
XX				r = c = hexc = 0;
XX				if (bytes == 0) break;
XX				touchwin (stdscr);
XX				refresh ();
XX				wmove (hexwin, r, hexc);
XX				wrefresh (hexwin);

XX				while ((z = wgetch (hexwin)) != DEL)
XX				{
XX					if (!arrow (z, &r, &c))
XX					{
XX						hexc = c * 3;
XX						z = toupper (z);
XX						if (!isxdigit (z))
XX						{
XX							beep ();
XX						}
XX						else
XX						{
XX							waddch (hexwin, tolower (z));
XX							wrefresh (hexwin);

XX							if (z > '9') z -= 7;

XX							h = (z & m) << 4;

XX							while (2)
XX							{
XX								z = EOF;
XX								z = getch ();
XX								if (z == EOF)
XX								{
XX									pbrk = 0;
XX									h = -1;
XX									break;
XX								}
XX								z = toupper (z);
XX								if (!isxdigit (z))
XX								{
XX									beep ();
XX								}
XX								else
XX								{
XX									waddch (hexwin, tolower (z));
XX									wrefresh (hexwin);
XX									if (z > '9') z -= 7;

XX									h |= z & m;
XX									break;
XX								}
XX							}

XX							if (h < 0)
XX							{
XX								wmove (hexwin, r, hexc);
XX								if (record[r][c] < '\0')
XX								{
XX									wprintw (hexwin, "%x%x",
XX										(record[r][c] >> 4) & m,
XX										record[r][c] & m);
XX								}
XX								else
XX								{
XX									wprintw (hexwin, "%02x", record[r][c]);
XX								}
XX								wrefresh (hexwin);
XX								break;
XX							}

XX							record[r][c] = z = h;
XX							mod = 1;

XX							if (ebcdic) icc (&z, 1,"EA");

XX							wmove (alphawin, r, c);
XX							if (isascii (z) && isprint (z))
XX								waddch (alphawin, z);
XX							else waddch (alphawin, '.');
XX							wrefresh (alphawin);

XX							if (c == 15)
XX							{
XX								if (r == 15) beep ();
XX								else
XX								{
XX									c = 0;
XX									++r;
XX								}
XX							}
XX							else
XX							{
XX								c++;
XX							}
XX						}
XX					}

XX					if (r * 16 + c >= bytes)
XX					{
XX						beep ();
XX						r = (bytes - 1) / 16;
XX						c = (bytes - 1) % 16;
XX					}

XX					hexc = c * 3;
XX					wmove (hexwin, r, hexc);
XX					wrefresh (hexwin);
XX				}
XX				break;

XX			case 'W': /* write record */
XX				stay = 1;
XX				status = lseek (fid, position, 0);
XX				if (status != position)
XX				{
XX					move (22, 0);
XX					clrtoeol ();
XX					perror (filename);
XX					errmsg ("error positioning in file");
XX					beep ();
XX				}
XX				if (swab) schwapp (record, 256);
XX				if (write (fid, record, bytes) != bytes)
XX				{
XX					errmsg ("error writing to file");
XX					sleep (1);
XX					reset (0);
XX					exit (0);
XX				}
XX				if (swab) schwapp (record, 256);
XX				mod = 0;
XX				errmsg ("Record written");
XX				break;

XX			case	'\n':		/* newline - next page			*/
XX			case	'\r':
XX				if (mod)
XX				{
XX					errmsg ("No write since last change");
XX					stay = 1;
XX				}
XX				else
XX				{
XX					++recno;
XX					if (!rawfile && (recno * 256) >= size)
XX					{
XX						recno--;
XX						beep ();
XX						errmsg ("No more records in file");
XX						stay = 1;
XX					}
XX					else stay = 0;
XX				}
XX				break;

XX			default:
XX				if (isascii (zp) && isprint (zp))
XX					errmsg ("Unknown command: %d", zp);
XX				else
XX					errmsg ("Unknown command: %d", zp + '@');
XX				beep ();
XX				stay = 1;
XX				break;
XX		} /* end switch zp */
XX		refresh ();
XX	}

XX	if (windowed)
XX	{
XX		reset (0);
XX	}
XX	status = close (fid);

XX	exit (status);
XX}
XX/*S show - display a record on the terminal */
XX/*H show */
XX/*E*/
XXshow (bytes, record, filename, size, recno, position,
XX	  m,reclen, dump, ebcdic, swab, block, honly)
XXint bytes;
XXint size;
XXint recno;
XXint position;
XXint m;
XXint reclen;
XXint dump;
XXint ebcdic;
XXint swab;
XXint honly;
XXchar record[16][16];
XXchar *filename;
XX{
XX	int		i;
XX	int		j;
XX	char	s;
XX	char	temp[16];
XX	char	*look = NULL;

XX	int		row = 0;
XX	int		col = 0;

XX	if (dump) printf ("\n\n");

XX	if (debug)
XX	{
XX		getyx (stdscr, row, col);
XX		move (23,0);
XX		printw ("show: %d|%d|%s|%d|%d|%d|%#x|%d|%d|%d|%d|%d|%d",
XX			bytes, record, filename, size, recno, position,
XX			m, reclen, dump, ebcdic, swab, block, honly);
XX		move (row, col);
XX		row = col = 0;
XX	}

XX	if (!dump) move (0, 0);
XX	outstr ("FILE: %s ", filename);
XX	if (block_spec) outstr ("(block special)");
XX	else if (char_spec) outstr ("(character special)");
XX	else if (fifo_spec) outstr ("(fifo (named pipe))");
XX	else if (dir_spec) outstr ("(directory - %ld)", size);
XX	else outstr ("(%ld)", size);

XX	if (ebcdic) outstr (" - EBCDIC");
XX	else outstr (" - ASCII");
XX	if (swab) outstr (" - SWAP");
XX	if (block) outstr (" - BLOCK (%d)", block);
XX	if (reclen) outstr (" - RECORD (%d)", reclen);

XX	if (!dump)
XX	{
XX		clrtoeol ();
XX		move (1,0);
XX		printw ("PAGE: %d (%d)", recno, position);
XX		clrtoeol ();
XX		row = 2;
XX	}
XX	else
XX	{
XX		printf ("\nPAGE: %d (%d)\n", recno, position);
XX	}

XX	if (honly)
XX	{
XX		look = (char *) record;
XX		for (j=0;j<256;++j)
XX		{
XX			if (*look++ != '\0')
XX			{
XX				look = NULL;
XX				break;
XX			}
XX		}
XX	}

XX	if (!dump) move (row, col);

XX	outstr ("    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf");
XX	outstr ("      0123456789abcdef");

XX	if (!dump)
XX	{
XX		row += 2;
XX		move (row, col);
XX	}
XX	else
XX	{
XX		printf ("\n\n");
XX	}
XX	for (i=0; i<=bytes/16; ++i)
XX	{
XX		if (honly && look != NULL)
XX		{
XX			i = 16;
XX			continue;
XX		}
XX		if (i*16+1 > bytes) continue;

XX		outstr ("%02x: ", i);

XX		for (j=0; j<16; ++j)
XX		{
XX			if (i*16+j < bytes)
XX			{
XX				if (record[i][j] < '\0')
XX					outstr ("%x%x ",
XX						(record[i][j] >> 4) & m, record[i][j] & m);
XX				else
XX					outstr ("%02x ", record[i][j]);

XX				s = ' ';
XX				if (reclen > 0 && (position+i*16+j+1)%reclen == 0)
XX					s = ':';
XX				if (block > 0 && (position+i*16+j+1)%block == 0)
XX				{
XX					if (s == ' ')
XX						s = '/';
XX					else
XX						s = '%';
XX				}
XX				if (s != ' ')
XX					outstr ("\b%c", s);
XX			}
XX			else
XX			{
XX				outstr ("   ");
XX			}
XX		}

XX		outstr ("     ");

XX		copyrec (record[i], temp, 16);

XX		if (ebcdic) icc (temp, 16, "EA");

XX		for (j = 0; j < 16 && i*16+j < bytes; ++j)
XX		{
XX			if (temp[j] < ' ') outch ('.');
XX			else outstr ("%c", temp[j]);
XX		}

XX		if (!dump)
XX		{
XX			move (++row, col);
XX		}
XX		else
XX		{
XX			printf ("\n");
XX		}
XX	}

XX	if (!dump)
XX	{
XX		clrtobot ();
XX		refresh ();
XX	}

XX	return;
XX}
XX/*S breakp - set pbrk on interrupt */
XX/*H breakp */
XX/*E*/
XXint breakp (i)
XXint i;
XX{
XX	int s;
XX	extern int pbrk;
XX	s = (int) signal (SIGINT, breakp);
XX	pbrk = i;
XX}
XX/*S bread - buffered read */
XX/*H bread */
XX/*E*/
XXint bread (fid, record, want, block)
XXint fid, want, block;
XXchar *record;
XX{
XX	int i, j, k;
XX	int what, bytes, orig;
XX	static char buffer[10240];
XX	static int left, arrow;
XX	static int flag = 1;

XX	if (flag)
XX	{
XX		left = 0;
XX		arrow = 0;
XX		flag = 0;
XX	}

XX	if (block == 0)
XX		return (read (fid, record, want));

XX	if (block & 1) ++block;

XX	orig = what = want;
XX	while (1)
XX	{
XX		if (left < want)
XX		{
XX			if (left)
XX			{
XX				copyrec (&buffer[arrow], record, left);
XX				record += left;
XX				want -= left;
XX			}

XX			arrow = 0;
XX			left = 0;

XX			if ((bytes = read (fid, buffer, block)) < 0)
XX			{
XX				what = bytes;
XX				break;
XX			}

XX			if (bytes == 0)
XX			{
XX				what = orig - want;
XX				break;
XX			}

XX			left = bytes;
XX		}
XX		else
XX		{
XX			copyrec (&buffer[arrow], record, want);
XX			arrow += want;
XX			left -= want;
XX			break;
XX		}
XX	}

XX	return (what);
XX}
XX/*S schwapp - swap bytes in place */
XX/*H schwapp */
XX/*E*/
XXvoid
XXschwapp (ptr, nch)
XXregister char *ptr;
XXregister int nch;
XX{
XX	register int i;
XX	register char c;
XX	register char *ptra = ptr + 1;

XX	if (nch & 1) --nch;

XX	for (i = 0; i < nch; i += 2, ptr += 2, ptra += 2)
XX	{
XX		c = *ptr;
XX		*ptr = *ptra;
XX		*ptra = c;
XX	}
XX	return;
XX}
XX/*S copyrec - transfer bytes from f to t for nbytes bytes */
XX/*H copyrec */
XX/*E*/
XXvoid
XXcopyrec (f, t, nbytes)
XXregister char *f;
XXregister char *t;
XXregister int nbytes;
XX{
XX	register int i;

XX	for (i = 0; i < nbytes; i++, f++, t++) *t = *f;

XX	return;
XX}
XX/*S ebcdic codes corresponding to ascii - translation table */
XX/*Page Eject*/
XXchar ebcdic_codes[] = {
XX0, 0x1, 0x2, 0x3, 0x37, 0x2d, 0x2e, 0x2f, 0x16,
XX0x5, 0x25, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
XX0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f,
XX0x27, 0x1c, 0x1d, 0x1e, 0x1f, 0x40, 0x5a, 0x7f, 0x7b,
XX0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b,
XX0x60, 0x4b, 0x61, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
XX0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e,
XX0x6f, 0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
XX0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
XX0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
XX0xe9, 0xad, 0xe0, 0xbd, 0x9a, 0x6d, 0x79, 0x81, 0x82,
XX0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92,
XX0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0xa2, 0xa3,
XX0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0,
XX0x5f, 0x7 };
XX/*S icc - internal code conversion */
XX/*H icc */
XX/*E*/
XXvoid
XXicc (buf, nch, type)
XXregister char *buf;
XXregister int nch;
XXchar *type;
XX{
XX	register int i;
XX	register int j;

XX	if (!strcmp (type, "AE"))
XX	{
XX		for (i = 0; i < nch; i++, buf++)
XX		{
XX			*buf = ebcdic_codes[*buf];
XX		}
XX	}
XX	else if (!strcmp (type, "EA"))
XX	{
XX		for (i = 0; i < nch; i++, buf++)
XX		{
XX			for (j = 0; j < 128; j++)
XX			{
XX				if (*buf == ebcdic_codes[j])
XX				{
XX					*buf = j;
XX					break;
XX				}
XX			}
XX		}
XX	}

XX	return;
XX}
XX/*S ckfile - check on existence, accessibility, and type of file */
XX/*H ckfile */
XX/*E*/
XXckfile (filename, sizep)
XXchar	*filename;
XXlong	*sizep;
XX{
XX	register int fid = 0;

XX	if (access (filename, 0) < 0)
XX	{
XX		errmsg ("file not found (%s)", filename);
XX		fid = -1;
XX	}

XX	if (block || pause || dump)
XX	{
XX		fid = open (filename, O_RDONLY, 0);
XX	}
XX	else
XX	{
XX		fid = open (filename, O_RDWR, 0);
XX	}

XX	if (fid < 0)
XX	{
XX		errmsg ("error opening file %s", filename);
XX		perror (filename);
XX		fid = -1;
XX	}
XX	else
XX	{
XX		errmsg ("File %s opened successfully ", filename);
XX		if (fstat (fid, &sb) == -1)
XX		{
XX			fprintf (stderr, "Can't stat\n");
XX			perror (filename);
XX			fid = -1;
XX		}
XX		else
XX		{
XX			block_spec = (sb.st_mode & S_IFMT) == S_IFBLK;
XX			char_spec = (sb.st_mode & S_IFMT) == S_IFCHR;
XX			fifo_spec = (sb.st_mode & S_IFMT) == S_IFIFO;
XX			dir_spec = (sb.st_mode & S_IFMT) == S_IFDIR;
XX			rawfile = block_spec || char_spec || fifo_spec;

XX			if (rawfile) *sizep = -1;
XX			else
XX			{
XX				if (sb.st_size == 0)
XX				{
XX					fprintf (stderr,
XX						"file %s is empty (zero bytes)\n",
XX						filename);
XX					fid = -1;
XX				}
XX				*sizep = sb.st_size;
XX			}
XX		}
XX	}

XX	return fid;
XX}
XX/*S dohelp - display help text */
XX/*H dohelp */
XX/*E*/
XXdohelp ()
XX{
XX	static char *helptxt[] = {
XX	"!   - execute command in the shell",	"a   - edit ascii portion",
XX	"-x   - toggle command line option",	"f   - display first page of file",
XX	"<cr> - display next page",	NULL,
XX	"?    - display this help text",	"h   - edit hexadecimal portion",
XX	"DEL  - quit the program",		"l   - display last page of file",
XX	"\\    - display previous page",		"nnn - direct addressing",
XX	"/    - search for ASCII string",		"q   - quit the program",
XX	"^f   - select named file",		"r   - reread the current page",
XX	"^n   - select next file",		"u   - undo all changes to page",
XX	"^p   - select previous file",		"w   - write out changed page",
XX	"^q   - quit without writing changes",	NULL,
XX	"^r   - redraw the screen",	NULL,
XX	"^x   - turn on debug",	NULL,
XX	"----------------------------------------------------------------", NULL,
XX	"direct addressing: nnnS, where nnn = some number, and", NULL,
XX	"                      S = type suffix", "b = block (512)",
XX	NULL, "k = kilobyte (1024)",
XX	NULL, "l = long word (4)",
XX	NULL, "p = page (256)",
XX	NULL, "w = word (2)",
XX	NULL, "<cr> = byte",
XX	};

XX	static int nmsg = sizeof helptxt / sizeof (char *);
XX	register int row = 0;
XX	register int i;

XX	register WINDOW *helpwin;
XX	extern WINDOW *newwin ();

XX	helpwin = newwin (LINES, COLS, 0, 0);
XX	werase (helpwin);
XX	wrefresh (helpwin);

XX	wmove (helpwin, 0, 1);
XX	waddstr (helpwin,
XX"---------------------------------- HELP ----------------------------------");

XX	for (row = 1, i = 0; i < nmsg; i+=2)
XX	{
XX		if (helptxt[i])
XX		{
XX			wmove (helpwin, row, 1);
XX			waddstr (helpwin, helptxt[i]);
XX		}
XX		if (i+1 <= nmsg && helptxt[i+1])
XX		{
XX			wmove (helpwin, row, 41);
XX			waddstr (helpwin, helptxt[i+1]);
XX		}
XX		row++;
XX	}

XX	wmove (helpwin, 23, 0);
XX	wstandout (helpwin);
XX	waddstr (helpwin, " <Press any key> ");
XX	wstandend (helpwin);
XX	wclrtoeol (helpwin);
XX	wrefresh (helpwin);
XX	wgetch (helpwin);
XX	werase (helpwin);
XX	wrefresh (helpwin);
XX	delwin (helpwin);

XX	return;
XX}
XX/*S reset - reset terminal to original state */
XX/*H reset */
XX/*E*/
XXreset (sig)
XXint sig;
XX{
XX	move (23, 0);
XX	refresh ();
XX	endwin ();
XX	if (sig) fprintf (stderr, "killed with signal %d\n", sig);
XX	exit (sig);
XX}
XX/*S arrow - determine if current character is a cursor control key */
XX/*H arrow */
XX/*E*/
XXarrow (k, r, c, type)
XXregister int k;
XXregister int *r;
XXregister int *c;
XXregister int type;
XX{
XX	register ret = 1;

XX	if (k == KEY_UP)
XX	{
XX		if (*r == 0) beep ();
XX		else (*r)--;
XX	}
XX	else if (k == KEY_DOWN || k == '\n')
XX	{
XX		if (*r == 15) beep ();
XX		else (*r)++;
XX	}
XX	else if (k == KEY_LEFT || k == '\b' )
XX	{
XX		if (*c == 0)
XX		{
XX			if (*r == 0) beep ();
XX			else
XX			{
XX				*c = 15;
XX				(*r)--;
XX			}
XX		}
XX		else (*c)--;
XX	}
XX	else if (k == KEY_RIGHT)
XX	{
XX		if (*c == 15)
XX		{
XX			if (*r == 15) beep ();
XX			else
XX			{
XX				*c = 0;
XX				(*r)++;
XX			}
XX		}
XX		else (*c)++;
XX	}
XX	else if (k == KEY_HOME)
XX	{
XX		*r = *c = 0;
XX	}
XX	else
XX	{
XX		ret = 0;
XX	}

XX	return ret;
XX}
XX/*S dbg_msg - print a debug message */
XX/*H dbg_msg */
XX/*E*/
XXdbg_msg (msg)
XXregister char *msg;
XX{
XX	if (debug && !dump)
XX	{
XX		errmsg (msg);
XX	}

XX	return;
XX}
XX/*S instr - get a character string from the terminal */
XX/*H instr */
XX/*E*/
XXchar *
XXinstr ()
XX{
XX	static char buf[512];

XX	register int c;
XX	register char *p = buf;
XX	register int col = 0;

XX	move (22, 0);
XX	clrtoeol ();
XX	refresh ();

XX	while ((c = getch ()) != '\r')
XX	{
XX		if (isascii (c) && isprint (c))
XX		{
XX			move (22, col);
XX			addch (c);
XX			*p++ = c;
XX			col++;
XX		}
XX		else if (c == '\b')
XX		{
XX			p--;
XX			col--;
XX			move (22, col);
XX			addch (' ');
XX			move (22, col);
XX		}
XX		refresh ();
XX	}

XX	refresh ();

XX	*p = '\0';

XX	return buf;
XX}
XX/*S getnum - retrieve a number from the terminal */
XX/*H getnum */
XX/*E*/
XXlong
XXgetnum (frst_char, hex)
XXregister int frst_char;
XXregister int hex;
XX{
XX	static char buf[64];

XX	register int c;
XX	register char *p = buf;
XX	register int col = 0;

XX	register long retval = 0;

XX	move (22, 0);
XX	clrtoeol ();
XX	if (frst_char)
XX	{
XX		addch (frst_char);
XX		*p++ = frst_char;
XX		col++;
XX		refresh ();
XX	}

XX	while ((c = getch()) != '\r')
XX	{
XX		if (isascii (c))
XX		{
XX			if ((hex && isxdigit (c)) || isdigit (c))
XX			{
XX				move (22, col);
XX				addch (c);
XX				*p++ = c;
XX				col++;
XX			}
XX			else if (c == '\b')
XX			{
XX				p--;
XX				col--;
XX				move (22, col);
XX				addch (' ');
XX				move (22, col);
XX			}
XX			else
XX			{
XX				break;			/* some character typing the value	*/
XX			}
XX			refresh ();
XX		}
XX	}

XX	*p = '\0';

XX	retval = atol (buf);

XX	mvprintw (22, 0, "%ld", retval);
XX	switch (c)
XX	{
XX		case	'b':			/* block - 512 bytes				*/
XX			retval *= 512;
XX			break;
XX		case	'k':			/* 1024 bytes						*/
XX			retval *= 1024;
XX			break;
XX		case	'l':			/* long word - 4 bytes				*/
XX			retval *= 4;
XX			break;
XX		case	'p':			/* page - 256 bytes					*/
XX			retval *= 256;
XX			break;
XX		case	'w':			/* word - 2 bytes					*/
XX			retval *= 2;
XX			break;
XX		case	'\r':			/* just clear it for display		*/
XX			c = '\0';
XX			break;
XX	}

XX	printw ("%c -> %ld byte offset", c, retval);
XX	clrtoeol ();

XX	refresh ();

XX	return retval;
XX}
XX/*S search - look for an ascii string in the file */
XX/*H search */
XX/*E*/
XXsearch (fid)
XXregister int fid;
XX{
XX	long	curpos = position;
XX	long	currec = recno;

XX	char	lrecord[sizeof record + 1];

XX	register int i;
XX	register int matched = 0;
XX	register int srch_len;

XX	register char *cp = instr ();
XX	register char *rp;

XX	int row, col;

XX	srch_len = strlen (cp);
XX	copyrec (record, lrecord, sizeof record);
XX	lrecord[256] = '\0';

XX	pbrk = 0;

XX	wmove (errwin, 0, 0);
XX	wstandout (errwin);
XX	wmove (errwin, 0, 40);
XX	wstandend (errwin);
XX	wmove (errwin, 0, 1);
XX	waddstr (errwin, "..searching record ");
XX	getyx (errwin, row, col);

XX	do
XX	{
XX		mvwprintw (errwin, row, col, "%ld", currec);
XX		wrefresh (errwin);

XX		for (i = 0, rp = lrecord, matched = 0;
XX			 !matched && i < 256;
XX			 rp++, i++)
XX		{
XX			if (*cp == *rp && !strncmp (cp, rp, srch_len))
XX			{
XX				matched = 1;
XX				break;
XX			}
XX		}

XX		if (!matched)
XX		{
XX			bytes = bread (fid, lrecord, 256, block);
XX			currec++;
XX			lrecord[256] = '\0';
XX		}
XX	}	while (!pbrk && bytes && !matched);

XX	if (matched)
XX	{
XX		recno = currec;
XX		stay = 0;
XX		copyrec (record, unch_rec, sizeof record);
XX		werase (errwin);
XX		wrefresh (errwin);
XX	}
XX	else
XX	{
XX		errmsg ("String %s not found", cp);
XX		stay = 1;
XX	}

XX	return;
XX}
XXerrmsg (fmt, arg1, arg2, arg3, arg4)
XXregister char *fmt;
XXregister char *arg1;
XXregister char *arg2;
XXregister char *arg3;
XXregister char *arg4;
XX{
XX	int y, x;

XX	if (!dump)
XX	{
XX		getyx (stdscr, y, x);
XX		wmove (errwin, 0, 0);
XX		wstandout (errwin);
XX		wprintw (errwin, fmt, arg1, arg2, arg3, arg4);
XX		wstandend (errwin);
XX		wclrtoeol (errwin);
XX		wrefresh (errwin);
XX		move (y, x);
XX	}
XX	else
XX	{
XX		fprintf (stderr, fmt, arg1, arg2, arg3, arg4);
XX	}
XX	return;
XX}
XXoutstr (fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
XXregister char *fmt;
XXregister char *arg1;
XXregister char *arg2;
XXregister char *arg3;
XXregister char *arg4;
XXregister char *arg5;
XXregister char *arg6;
XXregister char *arg7;
XX{
XX	if (dump) printf (fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
XX	else printw (fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7);

XX	return;
XX}
XXoutch (ch)
XXregister char ch;
XX{
XX	if (dump) putchar (ch);
XX	else addch (ch);

XX	return;
XX}
@//E*O*F bpatch.c//
chmod u=rw,g=rw,o=rw $OUT
 
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      28     259    1521 README
      20      83     485 Makefile
     138     990    5412 bpatch.1
    1749    5447   35893 bpatch.c
    1935    6779   43311 total
!!!
wc  README Makefile bpatch.1 bpatch.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp ; then
    echo "Ouch [diff of wc output]:"
    cat $dtemp
    STATUS=1
elif test $STATUS = 0 ; then
    echo "No problems found."
else
    echo "WARNING -- PROBLEMS WERE FOUND..."
fi
exit $STATUS