DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T b

⟦2c104edab⟧ TextFile

    Length: 35893 (0x8c35)
    Types: TextFile
    Names: »bpatch.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec8/bpatch/bpatch.c« 

TextFile

/*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:
*  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 ();

	/* ------------------------------------------------------------ */
	/* 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 */
#define KEY_UP		'^'
#define KEY_DOWN	'v'
#define KEY_LEFT	'<'
#define KEY_RIGHT	'>'
#define KEY_HOME	'@'
#endif	/* MOD_HAX */


	/* ------------------------------------------------------------ */
	/* 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		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 = 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 = 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;

/*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 ();

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

	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);
				break;
			case	'e':		/* file is ebcdic			*/
				ebcdic = 1;
				break;
			case	'p':		/* pause between pages - dump	*/
				pause = 1;
				break;
			case	'r':		/* record length for dump		*/
				reclen = atoi (optarg);
				break;
			case	's':		/* byte swapping required		*/
				swab = 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 ) && !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);
		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");
		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)
			{
				errmsg ("error on reading file %s", filename);
				status = EOF;
				continue;
			}
			if (bytes > 0)
			{
				if (swab) schwapp (record, 256);

				copyrec (record, unch_rec, sizeof record);

				show (bytes, record, filename, size, recno,
						position, m,reclen, dump, ebcdic, swab,
						block, honly);
			}
			mod = 0;
		}
	/* ------------------------------------------------------------ */
	/* not interactive - keep dumping or open next file             */
	/* ------------------------------------------------------------ */
		if (dump)
		{
			if ((dump < 0 && bytes == 0) || (--dump == 0))
			{
				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++;
					}

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

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

				if (pbrk) status = EOF;
			}

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

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

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

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

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

			case	'/':			/* search for a string		*/
				stay = 1;
				if (mod)
				{
					errmsg ("No write since last change");
				}
				else search (fid, zp);
				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 = !swab;
						break;
				}
				if (change)
				{
					show (bytes, record, filename, size,
							recno, position, m,reclen, dump,
							ebcdic, swab, block, honly);
				}

				break;

			case '\022':			/* redraw screen (^R)		*/
				clear ();
				show (bytes, record, filename, size, recno,
					  position, m, reclen, dump, ebcdic,
					  swab, block, honly);
				stay = 1;
				break;
			
			case	'\030':			/* toggle debug (^X)		*/
				debug = !debug;
				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");
					stay = 1;
				}
				else if (optind == (argc - 1))
				{
					errmsg ("No more files");
					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");
						reset (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");
					stay = 1;
				}
				else if (optind == firstfile)
				{
					errmsg ("No previous file");
					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");
						reset (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!");
					stay = 1;
				}
				else
				{
					status = EOF;
				}
				break;

			case '\\': /* back up 1 record */
				if (mod)
				{
					errmsg ("No write since last change");
					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");
							beep ();
							++recno;
							stay = 1;
						}
					}
					else
					{
						errmsg ("No previous records");
						beep ();
						stay = 1;
					}
				}
				break; 

			case 'F': /* go to first record */
				if (mod)
				{
					errmsg ("No write since last change");
					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");
					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);
				show (bytes, record, filename, size, recno,
						position, m,reclen, dump, ebcdic, swab,
						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");
					stay = 1;
				}
				else
				{
					byteaddr = getnum (zp, FALSE);
					stay = 1;
					errmsg ("Position to byte %ld", byteaddr);
					if (!rawfile && byteaddr > size)
					{
						errmsg ("Address outside file");
						beep ();
					}
					else if (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);
				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);
				wrefresh (hexwin);

				while ((z = wgetch (hexwin)) != DEL)
				{
					if (!arrow (z, &r, &c))
					{
						hexc = c * 3;
						z = toupper (z);
						if (!isxdigit (z))
						{
							beep ();
						}
						else
						{
							waddch (hexwin, tolower (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;
								}
								z = toupper (z);
								if (!isxdigit (z))
								{
									beep ();
								}
								else
								{
									waddch (hexwin, tolower (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");
					beep ();
				}
				if (swab) schwapp (record, 256);
				if (write (fid, record, bytes) != bytes)
				{
					errmsg ("error writing to file");
					sleep (1);
					reset (0);
					exit (0);
				}
				if (swab) schwapp (record, 256);
				mod = 0;
				errmsg ("Record written");
				break;

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

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

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

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

	int		row = 0;
	int		col = 0;

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

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

	if (!dump) move (0, 0);
	outstr ("FILE: %s ", filename);
	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) outstr ("(directory - %ld)", size);
	else outstr ("(%ld)", size);

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

	if (!dump)
	{
		clrtoeol ();
		move (1,0);
		printw ("PAGE: %d (%d)", recno, position);
		clrtoeol ();
		row = 2;
	}
	else
	{
		printf ("\nPAGE: %d (%d)\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) continue;

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

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

				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 != ' ')
					outstr ("\b%c", s);
			}
			else
			{
				outstr ("   ");
			}
		}

		outstr ("     ");

		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 outstr ("%c", temp[j]);
		}

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

	if (!dump)
	{
		clrtobot ();
		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, arrow;
	static int flag = 1;

	if (flag)
	{
		left = 0;
		arrow = 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[arrow], record, left);
				record += left;
				want -= left;
			}

			arrow = 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[arrow], record, want);
			arrow += 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 ebcdic_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 = ebcdic_codes[*buf];
		}
	}
	else if (!strcmp (type, "EA"))
	{
		for (i = 0; i < nch; i++, buf++)
		{
			for (j = 0; j < 128; j++)
			{
				if (*buf == ebcdic_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)
	{
		errmsg ("file not found (%s)", filename);
		fid = -1;
	}

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

	if (fid < 0)
	{
		errmsg ("error opening file %s", filename);
		perror (filename);
		fid = -1;
	}
	else
	{
		errmsg ("File %s opened successfully ", filename);
		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[] = {
	"!   - execute command in the shell",	"a   - edit ascii portion",
	"-x   - toggle command line option",	"f   - display first page of file",
	"<cr> - display next page",	NULL,
	"?    - display this help text",	"h   - edit hexadecimal portion",
	"DEL  - quit the program",		"l   - display last page of file",
	"\\    - display previous page",		"nnn - direct addressing",
	"/    - search for ASCII string",		"q   - quit the program",
	"^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",
	"^q   - quit without writing changes",	NULL,
	"^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);
	werase (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);
	werase (helpwin);
	wrefresh (helpwin);
	delwin (helpwin);

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

	if (k == KEY_UP)
	{
		if (*r == 0) beep ();
		else (*r)--;
	}
	else if (k == KEY_DOWN || k == '\n')
	{
		if (*r == 15) beep ();
		else (*r)++;
	}
	else if (k == KEY_LEFT || k == '\b' )
	{
		if (*c == 0)
		{
			if (*r == 0) beep ();
			else
			{
				*c = 15;
				(*r)--;
			}
		}
		else (*c)--;
	}
	else if (k == KEY_RIGHT)
	{
		if (*c == 15)
		{
			if (*r == 15) beep ();
			else
			{
				*c = 0;
				(*r)++;
			}
		}
		else (*c)++;
	}
	else if (k == KEY_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);
	}

	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);
		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);
		wrefresh (errwin);
	}
	else
	{
		errmsg ("String %s not found", cp);
		stay = 1;
	}

	return;
}
errmsg (fmt, arg1, arg2, arg3, arg4)
register char *fmt;
register char *arg1;
register char *arg2;
register char *arg3;
register char *arg4;
{
	int y, x;

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

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

	return;
}