v13i074: Binary patch program, ported to 80286 etc.

Rich Salz rsalz at bbn.com
Mon Feb 29 04:14:00 AEST 1988


Submitted-by: rupley!local at ARIZONA.EDU
Posting-number: Volume 13, Issue 74
Archive-name: bpatch2

Neat code and program.  Dump or edit files (binary or acsii), displayed by
256-byte records in side-by-side hex and ascii formats.  Various other
features (eg, toggled swap within byte pairs).  I spent some time tonight
getting bpatch to work well on a Vax (at least one particular Vax) running
BSD4.3 with NFS.  The macros in ctype.h gave some problems.  The code
attached here compiles both on Microport SysV and BSD4.3, without change,
if the proper Makefile is used.  The program appears to work equally in
the two environments.  I expect that there should be little problem in
adjusting for other flavors of BSD or SysV.

There are two Makefiles now, for bsd and Sysv.  Small changes in README
and the man pages.

John Rupley
    uucp: ..{ihnp4 | hao!noao}!arizona!rupley!local
    internet: rupley!local at megaron.arizona.edu
    telex: 9103508679(JARJAR)
    (H) 30 Calle Belleza, Tucson AZ  85716 - (602) 325-4533
    (O) Dept. Biochemistry, Univ. Arizona, Tucson AZ 85721 - (602) 621-3929

************************cut here******************************************
# To unbundle, sh this file
echo unbundling README 1>&2
cat >README <<'AlBeRtEiNsTeIn'

BPATCH.C
Original code written by Garry M. Johnson and Steven Lisk.

Neat code and program.  Dump or edit files (binary or acsii), displayed
by 256-byte records in side-by-side hex and ascii formats.  Various
other features (eg, toggled swap within byte pairs).

Here converted to 80286 (Microport sysV/AT). More details in bpatch.c, 
under Change History.  Some of the changes also serve to fix code that 
appeared to be broken even for a 32-bit environment.

Makefile.sys5 is set for Microport SysV/AT.2.2.  The code should compile 
under standard SysV environments.

The man pages are changed only slightly from the original distribution.

The code compiles on a Vax running BSD4.3, with Makefile.bsd, of 
course.  Testing was with an AT compatible logged in as a terminal, 
with setenv TERM vt100.  There may be curses/terminal problems for 
other environments.  A terminal which was an adm3a equivalent was ok.

Beware of using the shell escape feature!

Like the previous authors, I would appreciate learning of further 
changes and improvements in the code:

John Rupley
 uucp: ..{ihnp4 | hao!noao}!arizona!rupley!local
 internet: rupley!local at megaron.arizona.edu
 telex: 9103508679(JARJAR)
 (H) 30 Calle Belleza, Tucson AZ 85716 - (602) 325-4533
 (O) Dept. Biochemistry, Univ. Arizona, Tucson AZ 85721 - (602) 621-3929

+++++++++++++++++++++original distribution README+++++++++++++++++++++++
>Herewith find BPATCH - a marvelously utile utility.  While not of
>my original creation, I have been given permission to place in the
>public domain.  I have made substantial modifications to the original
>source given to me.  Specifically I cleaned it up a bit and made it
>work with SVR2 curses.  Personally, I think it's pretty neat.
>
>OK - for those of you who may scream by now "WHAT THE HELL IS IT ALREADY?"
>I respond that it is a binary file editor and dump utility!  That's 
>right!  You can dump your file in the nicely laid out side-by-side
>hex and ascii format or you can actually EDIT it at your terminal!
>Yes, I have seen the BED editor that came across the network.
>Unfortunately, it converted the entire file before and after editing.
>Bpatch, on the other hand, works with one 256 byte page at a time.
>It is marvelously useful for looking at things like raw disk UNIFY
>databases and even raw disks!  While the man page may not be absolutely
>up to date, the online help is.  Try the question mark (?) command.
>
>As always, I would love to hear about bugs/changes/enhancements/requests.
>	Steven List @ Benetics Corporation, Mt. View, CA
>	Just part of the stock at "Uncle Bene's Farm"
>	{cdp,engfocus,idi,oliveb,opusys,plx,pyramid,tolerant}!bene!luke!itkin
>
>Addition by the moderator:
>I have added code, surrounded by #ifdef MOD_HAX, that gets bpatch
>(barely?) working on my 4.2 system.  I would be very interested in
>publishing a set of diffs that's less of a hack.  Oh yeah:  I also
>wrote the Makefile.
>	/Rich $alz
+++++++++++++++++++++end of original distribution README++++++++++++++++++++
AlBeRtEiNsTeIn
echo unbundling Makefile.bsd 1>&2
cat >Makefile.bsd <<'AlBeRtEiNsTeIn'
# This may have to change on your system.
# You may have to fiddle with various combinations of curses, termcap,
# terminfo, etc.  Good luck!
LIBS	= -lcurses -ltermcap
#LIBS	= -ltermlib
#LIBS	= -lterminfo
#for sysV
#LIBS	= -lcurses

# However you need getopt.
#GETOPT	= -lgetopt
#not for sysV! (nor for some BSD)
#GETOPT	=

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

#BSD or thereabouts
CFLAGS	= -O $(WORK)
#Microport sysV/AT, large model, for sdb debugger
#CFLAGS	= -g -Ml

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

install:
	@echo Use cp to put things where you want them
AlBeRtEiNsTeIn
echo unbundling Makefile.sys5 1>&2
cat >Makefile.sys5 <<'AlBeRtEiNsTeIn'
# This may have to change on your system.
# You may have to fiddle with various combinations of curses, termcap,
# terminfo, etc.  Good luck!
#LIBS	= -lcurses -ltermcap
#LIBS	= -ltermlib
#LIBS	= -lterminfo
#for sysV
LIBS	= -lcurses

# However you need getopt.
#GETOPT	= -lgetopt
#not for sysV! (nor for some BSD)
#GETOPT	=

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

#BSD or thereabouts
#CFLAGS	= -O $(WORK)
#Microport sysV/AT, large model, for sdb debugger
CFLAGS	= -g -Ml

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

install:
	@echo Use cp to put things where you want them
AlBeRtEiNsTeIn
echo unbundling bpatch.1 1>&2
cat >bpatch.1 <<'AlBeRtEiNsTeIn'
.TH "bpatch" "1" "Benetics Local"
.UC 4
\" .if t .nr LL 7i
\" .if t .nr IN .8i
\" .if n .nr LL 70
\" .if n .nr IN 8
\" .fi
\" .ad b
.SH NAME
bpatch - binary patch and dump file utility
.SH SYNOPSIS
bpatch [ -b blksize ] [ -d ] [ -D pagecnt ] [ -e ] [ -p ] [ -r reclen ] [ -s ] [ -x ] file...
.SH DESCRIPTION
\fIBpatch\fR allows the viewing and/or modification of files, independent of
file type (text, executable, data file, and so forth).  \fIBpatch\fR
allows the data to either be examined at the terminal, dumped to a print
device or file, or edited in the general manner of \fIvi(1)\fR.  The
data in the file is dumped or displayed in \fIpages\fR of 256 bytes.
.SS Options
.IP "-b blksize" 12
The \fI-b\fR option specifies the blocksize of the data file.  This is used
primarily with tapes, and is allowed only with one of the dump (\fI-d\fR
or \fI-D\fR) options.  When this option is specified, the file is opened
in readonly mode.
.IP "-d" 12
The \fI-d\fR option indicates that a dump (no terminal manipulation) is
to be performed.  The entire file will be dumped to standard output.  No
editing of the data is allowed and the file is opened in readonly mode.
<DEL> interrupts a continuous display, producing a pause after the
current record is displayed; at this point, a second <DEL> exits and
and other character begins display of the next file.
.IP "-D pagecnt" 12
The \fI-D\fR option is similar to the \fI-d\fR option, with the
following exception: the pagecnt argument limits the dump to the
specified number of \fIpages\fR.
.IP "-e" 12
The \fI-e\fR option indicates that the file contains EBCDIC data and
should be converted in the character portion of the dump.
.IP "-p" 12
Used with one of the \fIdump\fR options, this option causes the program
to pause between \fIpages\fR.  The program will then wait for the user
to press either the \fIreturn\fR key to continue, or the \fIDEL\fR (or
\fIrubout\fR) key to stop the dump.
.IP "-r reclen" 12
The \fI-r\fR option indicates the record length of the data within the
dump.  When specified, this option causes \fIbpatch\fR to place a colon
(:) between the last byte of one record and the first byte of the next.
.IP "-s" 12
This option turns on the byte swap option.  It may be toggled dynamically
during execution (see \fI-x\fP under Commands below).
.IP "-x" 12
This option specifies the suppression of pages that contain only NUL
characters.  The result is that only the page header (name and page
number) will appear for such a page.  This option may only be used with
one of the dump options.
.SS Arguments
.IP file 12
Any number of files may be specified.
.SS Commands
All commands are valid only in the non-dump, interactive mode.  Commands
may be entered in either upper or lower case.  Commands of the form '^x'
indicate that the control character \fIx\fR is to be entered.
.P
All commands that request movement within a file or between files cannot
be executed if any changes have been made.  To proceed in this case, the
user must either enter the \fIw\fR command, the \fIu\fR command, or the
\fIr\fR command.
.P
Requesting a next or previous file when there is no such will cause the
issuance of an error message.
.P
Note that certain commands allow/require either some text or numeric
value.  In those cases, the user should type in characters and end the
string with either a <cr> or <DEL>.
.IP ? 6
Display the help screen.  The help screen will remain until the user
either redraws the screen (see \fI^r\fR) or changes pages or files.
.IP ! 6
Execute the following command in the shell.
.IP backslash 6
Display the previous page.
.IP <cr> 6
Display the next page.
.IP DEL 6
Quit the program if no changes have been made.
.IP / 6
This command initiates an ASCII search.  The text entered on the command
line will be used as a search string, and the file will be searched
starting with the current page.  When the string is found, the page
containing the string will be displayed.  If the string is not found, an
apapropriate message will be displayed.
.IP ^f 6
Open a named file whose name will be entered on the command line and
followed either by <cr> or DEL.
.IP ^n 6
Open the next file and display the first page.
.IP ^p 6
Open the previous file and display the first page.
.IP ^q 6
Quit without writing current changes.
.IP ^r 6
Redraw the screen.
.IP NNN 6
Entering a numeric value requests that the specified page be displayed.
.IP -x 6
Toggle the command line option represented by \fIx\fR:
.RS 12
.IP a 6
Toggle display to ascii (assume data is ascii).
.IP e 6
Toggle display to dbcdic (assume data is ebcdic).
.IP s 6
Toggle byte swap.
.RE
.IP a 6
Edit the ASCII display.  End edits by pressing the DEL key.  All other
characters will be treated as valid input.  Cursor movement keys (arrows
and home) allow movement within the edit window.  Nonprinting
characters are displayed as dot (.) in this window.
.IP f 6
Display the first page in the current file.
.IP g 6
Display the page containing the byte address typed in following the command.
.IP h 6
Edit the HEXADECIMAL display.  End edits by pressing DEL key.  Cursor
movement keys (arrows and home) allow movement within the edit window.
Two keystrokes are required to modify a byte, and both must be valid
hexadecimal values (0-9 and a-f).  To cancel a change after typing one
character, press DEL.
.IP l 6
Display the last page in the current file.
.IP q 6
Quit the file.  A warning will be issued if any changes have been made
but not written out.
.IP r 6
Reread the current page.
.IP u 6
Undo all changes to the current page.
.IP w 6
Write out the current page.
.SH "SEE ALSO"
od(1)
AlBeRtEiNsTeIn
echo unbundling bpatch.c 1>&2
cat >bpatch.c <<'AlBeRtEiNsTeIn'
/*T bpatch - A binary file patch/dump utility */
/*S Introduction */
/*F bpatch ***********************************************************
* bpatch
* by Garry M Johnson - 09/17/84
* (C) Copyright 1984, 1985
*
* Change History:
*
* 11/29/87 - PORT TO 80286 SYSTEM (MICROPORT SYSV/AT, 2.2)
* 
* -> sorted out nonportable int -ne char *  and int -ne long (ever-
* annoying problems for the 286); the changes should not have broken 
* the code for 32-bit int -eq char *  machines; indeed, some of the 
* changes fix apparently broken code
* -> calls to outstr() now pass only a string address; where values are to 
* be displayed, they are entered into the string with a prior 
* sprintf(); 
* -> calls to errmsg() handled as for outstr(), except there is a second 
* parameter, "sleep_time", to specify the length of a sleep after message 
* display; this is *not* implemented; call of sleep dumps core -- signal 
* handling problem??
* -> after "windowed" is set, forced all exit()'s into passing first 
* through reset() and likewise everywhere follow reset() with immediate 
* exit()
* -> in the segment following "not interactive - keep dumping ...",
* repaired broken code that controlled flow for the -d and -D options;
* allow DEL interrupt of continuous dump of long file, in order to 
* quit or go to next file
* -> in reset(), ioctl'd terminal to be as at entry
* -> in arrow(), added vi-like cursor control
* -> cleaned up code for formats where specification did not agree with
* declared type for variable; same for function parameter lists; checked 
* casts and conversions to/from long; miscellaneous general cleanup 
* of the code
* -> cleaned up the display, but lots left to be done
* 
* 
* REMAINING MINOR BUGS AND INFELICITIES AND WISH LIST --
* 
* -> spawn a properly working interactive shell; probably just need 
* a fork and a full reset() under "!" option
* -> easy repeat of string search to find next occurrence; highlight 
* string positions in the display; put edit cursor at start of string
* -> in debug mode, allow backspace over command entered, to cancel it
* -> errmsg() display not nice, if have several messages output in
* sequence; no pause in errmsg() (sleep not working?)
* -> column under pointer not always erased (local clrtoeol problem ??)
* -> irregular passing of pointers to record and related arrays
* -> most of the external vars should be local to main()
* -> signal handling?
* -> file closing?
* 
* COMMENTS --
* 
* -> thanks to Steven List and Garry Johnson for a very useful program;
* it's a nice way for one who is lazy to avoid a lot of compilation 
* when what is wanted is a small change in data; the code is easy to 
* read -- again compliments to the authors;
* -> these modifications are hacks of the previous authors' code; the 
* modified program has not been hardened, although I tried to check 
* its operation under limit conditions; please be careful in using it
* -> like the authors, I would appreciate receiving a copy of any 
* improvements
* 
* John Rupley, Dept. Biochemistry, Univ. Arizona, Tucson, AZ 85721
* {ihnp4 | hao!noao}!arizona!rupley!local or rupley!local at megaron.arizona.edu
*
******************************************************************************
*
*  03/05/86 - added further terminal independence
*	      added use of ioctl (see main and mstdin)
*	      added -D versus -d command line option
*	      added use of standard getopt
*	      cleaned up code, eliminated function "ikf"
*	      added original versions of ezlib functions, such as
*		icc, setterm, cm, mstdin, erase, length, move
*	      added ^R, ^Q, ^N, and ^P commands
*	      added ^F, !, and ^X (-X) commands
*			  changed name to "bpatch"
*			  added direct address command (g)
*	      added ASCII search capability
*  07/07/86 - converted to use curses
*	      modified direct addressing to use suffixes
*	      updated HELP function
*
*   Steven List @ Benetics Corporation, Mt. View, CA
*   {cdp,engfocus,idi,oliveb,plx,tolerant}!bene!luke!itkin
*********************************************************************/
/*E*/
/*S includes, globals, and defines */
/*Page Eject*/
#include	<curses.h>
#include <fcntl.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>

static int pbrk = 0;
struct stat sb;

void icc ();
void copyrec ();
void schwapp ();

/* added declarations, mostly for cleanliness */
extern long lseek();
extern long atol();
extern char *strncpy();
extern void exit();
extern unsigned sleep();	/* signal problems ??? if sleep called */
extern void perror();

/* set up for calls to outstr and errmsg, etc, */
/* by use of sprintf to fill outbuf */
char outbuf[512];

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

/* vi-like cursor control = vi keys, as control characters */
/* this is a hack, and I hope does not interfere with keypad() */
#define VI_UP		('K' - 0x40)
#define VI_DOWN		('J' - 0x40)
#define VI_LEFT		('H' - 0x40)
#define VI_RIGHT	('L' - 0x40)
#define VI_HOME		('G' - 0x40)

#define SLEEP_TIME	(unsigned )0	/* a small pause after errmsg */
					/* does not work -- signals?? */
	/* ------------------------------------------------------------ */
	/* Some convenient defines					 */
	/* ------------------------------------------------------------ */

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

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

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

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

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

WINDOW *hexwin = NULL;
WINDOW *alphawin = NULL;
WINDOW *errwin = NULL;

#ifdef	MOD_HAX
#else	/* use original code... */
	/* plus some more for restoring terminal function */
	struct termio asis, aswas;
#endif	/* MOD_HAX */

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

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

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

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

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

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

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

	signal (SIGTERM, reset);

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

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

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

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

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

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

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

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

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

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

	firstfile = optind;

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

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

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

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

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

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

	if (!dump) clear ();

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

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

				copyrec (record, unch_rec, sizeof record);

				if (!dump) clear ();
				show (bytes, record, filename, size, recno,
						position, m,reclen, dump, ebcdic, swab_opt,
						block, honly);
			}
			mod = 0;
		}
	/* ------------------------------------------------------------ */
	/* not interactive - keep dumping or open next file		 */
	/* ------------------------------------------------------------ */
		/* major changes in control of flow */
		/* first records of multiple-files now dump */
		/* core is not dumped at end of filelist */
		/* can break with DEL into a long dump */
		if (dump)
		{
			if (dump > 0) dump--;
			if ((dump < 0 && bytes == 0) || dump == 0)
			{
				if (Dump) dump = Dump;
				if (optind == argc) status = EOF;
				else
				{
					close (fid);
					fid = -1;
					for (optind++; fid < 0 && optind < argc;)
					{
						fid = ckfile (argv[optind], &size);
						if (fid < 0) optind++;
					}
					if (fid < 0)
					{
						status = EOF;
						continue;
					}

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

					if (block != 0)
					{
						size = -1;
					}
					recno = 0;
					stay = 0;
					status = lseek (fid, (long)0, 0);
				}
			}
			else
			{
				++recno;
			}
	/* ------------------------------------------------------------ */
	/* if pause, beep and wait					 */
	/* ------------------------------------------------------------ */
			/* settings to bypass show() */
			/* and go to read of next file */
			/* if type DEL during file display */
			if (status != EOF && (pause_opt || pbrk))
			{
				if (pbrk)
				{
					bytes = 0;
					dump = -1;
					stay = 1;
				}
				pbrk = 0;
				fprintf (stderr, "\007");
				gets (response);

				if (pbrk) status = EOF;
			}

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

		if (debug && !dump)
		{
			/* cheap cleanup of errwin */
			errmsg ("", SLEEP_TIME);
			if (isascii (zp) && isprint (zp))
			{
				sprintf (outbuf, "command entered is %c", (char )zp);
				errmsg (outbuf, 0);
			}
			else
			{
				sprintf (outbuf, "command entered is ^%c (%#x)", (char )zp + '@', zp);
				errmsg (outbuf, 0);
			}
			getch ();
		}

		/* assume normal ascii character sequence		*/
		if ((zp >= 'a') && (zp <= 'z'))
			zp = zp - 0x20;
	/* ------------------------------------------------------------ */
	/* here we go - what does the user want?			 */
	/* ------------------------------------------------------------ */
		refresh ();
		errmsg ("", SLEEP_TIME);
		switch (zp)
		{ 
			case	'!':	/* shell escape	*/
				echo ();
				move (23,0);
				clrtoeol ();
				addstr ("shell command: ");
				refresh ();
				getstr (response);
				clear ();
				nl ();
				system (response);
				noecho ();
				nonl ();
				move (23,0);
				standout ();
				addstr (" <Press any key> ");
				standend ();
				clrtoeol ();
				refresh ();
				getch ();
				break;

			case	'?':	/* HELP	*/
				clear ();
				dbg_msg ("Help");
				dohelp ();
				break;

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

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

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

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

				break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

						}
						else
						{
							beep ();
						}

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

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

				break;

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

				while ((z = wgetch (hexwin)) != DEL)
				{
					if (!arrow (z, &r, &c))
					{
						hexc = c * 3;
						if ((z >= 'a') && (z <= 'z'))
							z = z - 0x20;
						if (!(((z >= '0') && (z <= '9')) || ((z >= 'A') && (z <= 'F'))))
						{
							beep ();
						}
						else
						{
							if (z >= 'A')
								waddch (hexwin, tolower (z));
							else
								waddch (hexwin, z);
							wrefresh (hexwin);

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

							h = (z & m) << 4;

							while (2)
							{
								z = EOF;
								z = getch ();
								if (z == EOF)
								{
									pbrk = 0;
									h = -1;
									break;
								}
								if ((z >= 'a') && (z <= 'z'))
									z = z - 0x20;
								if (!(((z >= '0') && (z <= '9')) || ((z >= 'A') && (z <= 'F'))))
								{
									beep ();
								}
								else
								{
									if (z >= 'A')
 										waddch (hexwin, tolower (z));
 									else
 										waddch (hexwin, z);
									wrefresh (hexwin);
									if (z > '9') z -= 7;

									h |= z & m;
									break;
								}
							}

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

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

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

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

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

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

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

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

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

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

	reset (0);
	if (fid > 0) return (close (fid));
	else return (0);
}
/*S show - display a record on the terminal */
/*H show */
/*E*/
/*checked typing of parameters as declared in fucntion */
/* versus declarations at call */
show (bytes, record, filename, size, recno, position,
	  m,reclen, dump, ebcdic, swab_opt, block, honly)
int bytes;
char record[16][16];
char *filename;
long size;
int recno;
long position;
char m;
int reclen;
int dump;
int ebcdic;
int swab_opt;
int block;
int honly;
{
	int		i;
	int		j;
	char	s;
	char	temp[16];
	char	*look = NULL;

	int		row = 0;
	int		col = 0;

	if (dump)
		printf ("\n\n");
	if (!dump)
		move (0, 0);
	sprintf (outbuf, "FILE: %s ", filename);
	outstr (outbuf);
	if (block_spec) outstr ("(block special)");
	else if (char_spec) outstr ("(character special)");
	else if (fifo_spec) outstr ("(fifo (named pipe))");
	else if (dir_spec)
	{
		sprintf (outbuf, "(directory - %ld)", size);
		outstr (outbuf);
	}
	else 
	{
		sprintf (outbuf, "(%ld)", size);
		outstr (outbuf);
	}
	if (ebcdic) outstr (" - EBCDIC");
	else outstr (" - ASCII");
	if (swab_opt) outstr (" - SWAP");
	if (block) 
	{
		sprintf (outbuf, " - BLOCK (%d)", block);
		outstr (outbuf);
	}
	if (reclen) 
	{
		sprintf (outbuf, " - RECORD (%d)", reclen);
		outstr (outbuf);
	}
	if (!dump)
	{
		clrtoeol ();
		move (1,0);
		printw ("PAGE: %d (%ld)", recno, position);
		clrtoeol ();
		row = 2;
	}
	else
	{
		printf ("\nPAGE: %d (%ld)\n", recno, position);
	}

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

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

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

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

		sprintf (outbuf, "%02x: ", i);
		outstr (outbuf);

		for (j=0; j<16; ++j)
		{
			if (i*16+j < bytes)
			{
				if (record[i][j] < '\0')
				{
					sprintf (outbuf, "%x%x ",
						(record[i][j] >> 4) & m, record[i][j] & m);
					outstr (outbuf);
				}
				else
				{
					sprintf (outbuf, "%02x ", record[i][j]);
					outstr (outbuf);
				}
				s = ' ';
				if (reclen > 0 && (position+i*16+j+1)%reclen == 0)
					s = ':';
				if (block > 0 && (position+i*16+j+1)%block == 0)
				{
					if (s == ' ')
						s = '/';
					else
						s = '%';
				}
				if (s != ' ')
				{
					sprintf (outbuf, "\b%c", s);
					outstr (outbuf);
				}
			}
			else
			{
				outstr ("   "); /* set at 3 spaces */
			}
		}

		outstr ("	 ");	/* set at tab + 1 space */

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

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

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

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

	/* moved debug output so it would display + other related changes */
	if (!dump) clrtobot ();
	if (debug && !dump)
	{
		getyx (stdscr, row, col);
		move (23,0);
		printw ("show: %d|%ld|%s|%ld|%d|%ld|%#x|%d|%d|%d|%d|%d|%d",
			bytes, record, filename, size, recno, position,
			m, reclen, dump, ebcdic, swab_opt, block, honly);
		move (row, col);
	}
	if (!dump) 
	{
		touchwin (stdscr);
		refresh ();
	}
	
	return;
}
/*S breakp - set pbrk on interrupt */
/*H breakp */
/*E*/
int breakp (i)
int i;
{
	int s;
	extern int pbrk;
	s = (int) signal (SIGINT, breakp);
	pbrk = i;
}
/*S bread - buffered read */
/*H bread */
/*E*/
int bread (fid, record, want, block)
int fid, want, block;
char *record;
{
	int i, j, k;
	int what, bytes, orig;
	static char buffer[10240];
	static int left, xarrow;
	static int flag = 1;

	if (flag)
	{
		left = 0;
		xarrow = 0;
		flag = 0;
	}

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

	if (block & 1) ++block;

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

			xarrow = 0;
			left = 0;

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

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

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

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

	if (nch & 1) --nch;

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

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

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

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

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

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

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

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

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

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

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

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

	helpwin = newwin (LINES, COLS, 0, 0);
	wclear (helpwin);

	wrefresh (helpwin);

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

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

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

	return;
}
/*S reset - reset terminal to original state */
/*H reset */
/*E*/
reset (sig)
int sig;
{
	if (windowed)
	{
		move (23, 0);
		refresh ();
#ifndef MOD_HAX
		ioctl (0, TCSETA, &aswas);
#endif
		endwin ();
	}
	fprintf (stderr, "\n");
	if (sig)
	{
		fprintf (stderr, "killed with signal %d\n", sig);
		exit (sig);
	}
	return (0);
}
/*S arrow - determine if current character is a cursor control key */
/*H arrow */
/*E*/
arrow (k, r, c)
register int k;
register int *r;
register int *c;
{
	register ret = 1;

	/* watch out for conflict of VI_* amd KEY_* definitions */
	if (k == KEY_UP || k == VI_UP)
	{
		if (*r == 0) beep ();
		else (*r)--;
	}
	else if (k == KEY_DOWN || k == VI_DOWN)
	{
		if (*r == 15) beep ();
		else (*r)++;
	}
	else if (k == KEY_LEFT || k == VI_LEFT)
	{
		if (*c == 0)
		{
			if (*r == 0) beep ();
			else
			{
				*c = 15;
				(*r)--;
			}
		}
		else (*c)--;
	}
	else if (k == KEY_RIGHT || k == VI_RIGHT)
	{
		if (*c == 15)
		{
			if (*r == 15) beep ();
			else
			{
				*c = 0;
				(*r)++;
			}
		}
		else (*c)++;
	}
	else if (k == KEY_HOME || k == VI_HOME)
	{
		*r = *c = 0;
	}
	else
	{
		ret = 0;
	}

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

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

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

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

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

	refresh ();

	*p = '\0';

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

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

	register long retval = 0;

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

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

	*p = '\0';

	retval = atol (buf);

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

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

	refresh ();

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

	char	lrecord[sizeof record + 1];

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

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

	int row, col;

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

	pbrk = 0;

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

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

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

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

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

	return;
}
/* simplified call to errmsg(), by using sprintf to load format */
/* sleep_time is not implemented and awaits cleaning up of the signals (?) */
errmsg (fmt, sleep_time)
unsigned sleep_time;
char *fmt;
{
	int y, x;

	if (windowed)
	{
		getyx (stdscr, y, x);
		wmove (errwin, 0, 0);
		wstandout (errwin);
		wprintw (errwin, fmt);
		wstandend (errwin);
		wclrtoeol (errwin);
		touchwin (errwin);
		wrefresh (errwin);
		move (y, x);
	}
	else
	{
		fprintf (stderr, fmt);
		fprintf (stderr, "\n");
	}
	/* signal problem ?? if sleep called
	if (sleep_time)
		sleep (sleep_time);
	*/
	return;
}
/* simplified call to outstr(), by using sprintf to load format */
outstr (fmt)
char *fmt;
{
	if (dump) printf (fmt);
	else printw (fmt);

	return;
}
outch (ch)
register char ch;
{
	if (dump) putchar (ch);
	else addch (ch);

	return;
}
AlBeRtEiNsTeIn
exit
-- 
For comp.sources.unix stuff, mail to rsalz at uunet.uu.net.



More information about the Comp.sources.unix mailing list