Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!ll-xn!husc6!necntc!ncoast!allbery
From: tanner@ki4pv.UUCP
Newsgroups: comp.sources.misc
Subject: A File Patching Package
Message-ID: <2765@ncoast.UUCP>
Date: Thu, 2-Jul-87 20:14:34 EDT
Article-I.D.: ncoast.2765
Posted: Thu Jul  2 20:14:34 1987
Date-Received: Sat, 4-Jul-87 10:17:57 EDT
Sender: allbery@ncoast.UUCP
Lines: 873
Approved: allbery@ncoast.UUCP
X-Archive: comp.sources.misc/8707/5


: "un-pack me with /bin/sh"
# This shar file contains a file patcher known around here as "fddt".
# The "Makefile" is incredibly simple.  The man page explains
# everything (hihi).  I hand-shar'ed the thing, as I don't have a
# "shar" prog running here.  It might unpack anyway.  Try it, after
# inspecting for trojan horse droppings.

echo	"unshar: x-fddt.1"
sed s/\^X-// > fddt.1 < Makefile < fddt.c <
X-#include  
X-
X-#define	 SZ		0x0100		/* size of things */
X-
X- /*	this program allows someone to apply patches to files
X-  *	of almost any type.  it helps a lot if lseek() will work
X-  *	on the file, but it is not required if the file to be
X-  *	"patched" is a serial device which is really being fed
X-  *	a stream of bytes.
X-  *
X-  *	usage:
X-  *	  fddt [-rw] 
X-  *	or:
X-  *	  fddt [-w]  -p  old1=new1 old2=new2 ...
X-  *	where
X-  *	  -r	read-only; patches may not be applied
X-  *	  -w	write-only; old contents may not be displayed
X-  *	  -p	"patch" mode, starts at addr and applies patch
X-  *
X-  *	once a file is selected for editing, the following commands
X-  *	will apply for interactive mode within the prog:
X-  *	 d	display data
X-  *	 e	enter new values
X-  *	 f	find data; will prompt for values
X-  *	 q,x	exit
X-  *	all commands take either one or two addresses (if no addr
X-  *	given, no work is done).  the first addr is a starting addr;
X-  *	the second, if given, is an ending addr.  default end is EOF.
X-  *	note that all addresses and data values are to be expressed
X-  *	in hex.  new values being entered are entered as 1-byte hex
X-  *	values.
X-  *
X-  *	patch mode is a way to non-interactively change values in the
X-  *	file being edited.  see the man page.
X-  *
X-  *	warning:  if your unix does not have rdchk(), you may either
X-  *	provide a substitute with ioctl() or eliminate the line of
X-  *	code using it with a return(0) and just use ^C to interrupt
X-  *	commands.  rdchk() appears new with SYS-3, replacing a V7
X-  *	ioctl() call.
X-  *
X-  *	note for cd_txt[] -- this is supplied by a little daemon
X-  *	which creates /lib/cdate.o containing today's date.  the
X-  *	daemon to do this is available from "ki4pv!tanner" upon
X-  *	application.  you could also eliminate the reference.
X-  *
X-  *	This prog and documentation (C) 1987, CompuData, Inc.
X-  *	Permission is granted to use it, so long as this
X-  *	copyright notice remains intact, and so long as you
X-  *	don't try to sell it or claim that you wrote it.
X-  *	By making this program available, CompuData neither gives
X-  *	up any rights in it, nor assumes any responsibility for
X-  *	any damages caused by it.
X-  */
X-
X-	 /*  important vars  */
X-
X-
X-static char
X-	tf_blt[] =	"FDDT   vers 1.2a  built %s\n\n",
X-
X-	tf_usg[] =	"? usage:  %s [-rw]  [-p  old=new ...]\n",
X-
X-	tf_sup[] =	"%% %s suppressed\n",
X-	tx_rd[] =	"reading",
X-	tx_wr[] =	"writing",
X-
X-	tf_bad[] =	"? %s: bad %s: %s\n",
X-	tf_bdr[] =	"? bad range: %08lX > %08lX\n",
X-	tf_nos[] =	"? no search values\n",
X-	tf_sek[] =	"? can't seek: %08lX\n",
X-	tf_wre[] =	"? write error: file %s, off 0x%08X, n 0x%X\n",
X-
X-	tf_fnd[] =	"found @ 0x%08lX\n",
X-	tf_nfd[] =	"not found, end @ 0x%08lX\n",
X-	tf_8x[] =	"%08lX: ",
X-	tf_2x[] =	"%02X ",
X-
X-	tf_pat[] =	"patching 0x%08lX: ",
X-	tf_pr1[] =	"0x%02X",
X-	tx_prx[] =	" xx ",
X-	tf_per[] =	"read mismatch: exp 0x%02X, got 0x%02X\n",
X-	tx_pex[] =	"patch expr",
X-
X-	tx_int[] =	"** intr **\n";
X-
X-
X-unsigned int _fmode =	0x8000;		/* for ms-dos */
X-
X-
X- /* - - - - */
X-
X-short int
X-	stoppt,			/* "action stopped" flag */
X-	rw_sup,			/* -r or -w flag */
X-	patch,			/* set true if patching */
X-	ed_fd;			/* fd of file to be patched */
X-
X-char
X-	*prog_name,
X-	*inbuf,			/* user input buffer */
X-	*ed_fn,			/* name of file being patched */
X-	*ed_buf,		/* edit buffer */
X-	*match;			/* file match buffer */
X-
X-  /* - - - - - */
X-
X-extern char
X-	cd_txt[];		/* /lib/cdate.o, kept by daemon */
X-
X- /*  = = = = =  */
X-
X-short int
X-	do_hdr(),		/* things to do before any work */
X-	do_lev(),		/* evaluate a long addr */
X-	get_ln(),		/* get series of numbers */
X-	get_st(),		/* get "stopped" flag */
X-	pat_ev(),		/* eval expression for patch */
X-	sig_st();		/* signal handler */
X-
X-void
X-	do_opn(),		/* open the file */
X-	do_pat(),		/* patch the file */
X-	do_edt(),		/* edit the file */
X-	do_dmp(),		/* dump part of file */
X-	do_inp(),		/* input new values to file */
X-	do_src(),		/* find values in file */
X-	usage();
X-
X-  /* - - - - - */
X-
X-extern long int
X-	lseek();
X-
X-extern int
X-	chupper(),		/* $LOCLIB */
X-	dehex();		/* $LOCLIB */
X-	isprint(), iswhite(), isxdigit(),
X-	rdchk();		/* $SYSDEP */ /* pending input check */
X-
X-extern char
X-	*malloc(),
X-	*strbrk(),		/* $LOCLIB */
X-	*strchr();
X-
X-	 /*  main block of prog  */
X-
X-main(ac, av)
X-short int ac;
X-char	**av;
X-	{
X-	register char
X-		*p;
X-
X-
X-	fprintf(stderr, tf_blt, cd_txt);
X-
X-	prog_name = **av ? *av : "FDDT";
X-
X-	if  (ac < 2)
X-		usage();
X-
X-	if  (*(p = *++av) == '-')  {	/* have flag */
X-		if  (((rw_sup = chupper(*++p)) != 'R') &&
X-		     (rw_sup != 'W'))
X-			usage();
X-		++av;
X-		}
X-	else
X-		rw_sup = 0;
X-
X-	ed_fn = *av;			/* get working filename */
X-
X-	setbuf(stdout, (char *)0);
X-
X-	if  ((!(ed_buf = malloc(SZ))) ||
X-	     (!(match = malloc(2*SZ))) ||
X-	     (!(inbuf = malloc(SZ))))  {
X-		fprintf(stderr, "? %s: can't allocate\n", prog_name);
X-		exit(1);
X-		}
X-
X-	signal(SIGINT, sig_st);		/* catch ^C to abort command */
X-
X-	do_opn();			/* open the file */
X-
X-	if  (*++av)
X-		do_pat(av);		/* patch the file */
X-	else
X-		do_edt();		/* edit the file */
X-
X-	if  (close(ed_fd))		/* close the file */
X-		no_clos(ed_fn);
X-
X-	exit(0);
X-
X-	}
X-
X-
X-static void usage()
X-	{
X-
X-	fprintf(stderr, tf_usg, prog_name);
X-	exit(1);
X-
X-	}
X-
X-
X-	 /*  open file to be edited  */
X-
X-
X-void do_opn()
X-	{
X-	register short int
X-		mode;
X-
X-
X-	switch (rw_sup)  {		/* select file open mode */
X-		case 'R':
X-			mode = 0;
X-			break;
X-		case 'W':
X-			mode = 1;
X-			break;
X-		default:
X-			mode = 2;
X-		}
X-
X-	if  ((ed_fd = open(ed_fn, mode)) < 0)
X-		no_open(ed_fn);
X-
X-	}
X-
X-	 /*  patch the file  */
X-
X-void do_pat(ap)
X-char	**ap;
X-	{
X-	register char
X-		*p;
X-	short int
X-		old, new;
X-	long int
X-		p_addr,			/* patch addr */
X-		tmp;			/* tmp value from eval */
X-	unsigned char
X-		c;			/* in/out data item */
X-
X-
X-	if  ((*(p = *ap) != '-') ||
X-	     (chupper(*++p) != 'P'))
X-		usage();
X-
X-	if  (do_lev(*++ap, &p_addr))  {	/* eval addr */
X-		fprintf(stderr, tf_bad, prog_name, "addr", *ap);
X-		exit(1);
X-		}
X-
X-	if  (lseek(ed_fd, p_addr, 0) != p_addr)  {	/* just test */
X-		fprintf(stderr, tf_sek, p_addr);
X-		exit(2);
X-		}
X-
X-	for  ( ; p = *++ap ; ++p_addr )  {
X-		p += pat_ev(p, &old, "old");
X-		if  (*p++ != '=')  {
X-			fprintf(stderr, tf_bad, prog_name, tx_pex, *ap);
X-			exit(3);
X-			}
X-		p += pat_ev(p, &new, "new");
X-		if  (*p)  {
X-			fprintf(stderr, tf_bad, prog_name, tx_pex, *ap);
X-			exit(4);
X-			}
X-		printf(tf_pat, p_addr);
X-		if  (old >= 0)  {		/* match old */
X-			if  (rw_sup == 'R')  {
X-				fprintf(stderr, tf_sup, tx_rd);
X-				exit(5);
X-				}
X-			if  ((lseek(ed_fd, p_addr, 0) != p_addr) ||
X-			     (read(ed_fd, &c, 1) != 1) ||
X-			     (c != old))  {
X-				fprintf(stderr, tf_per, old, c);
X-				exit(6);
X-				}
X-			printf(tf_pr1, old);
X-			}
X-		else
X-			printf(tx_prx);
X-		printf(" -> ");
X-		if  (new >= 0)  {
X-			if  (rw_sup == 'W')  {
X-				fprintf(stderr, tf_sup, tx_wr);
X-				exit(7);
X-				}
X-			c = new;
X-			if  ((lseek(ed_fd, p_addr, 0) != p_addr) ||
X-			     (write(ed_fd, &c, 1) != 1))  {
X-				fprintf(stderr, tf_wre, ed_fn, p_addr, 1);
X-				exit(8);
X-				}
X-			printf(tf_pr1, new);
X-			}
X-		else
X-			printf(tx_prx);
X-		printf(" ok\n");
X-		}
X-
X-	}
X-
X-
X-	  /*  patch support: evaluate old/new value  */
X-
X-
X-static short int pat_ev(sp, dp, err)
X-char	*sp, *err;
X-short int *dp;			/* result goes here */
X-	{
X-	register char
X-		*q;
X-	long int
X-		tmp;
X-
X-
X-	if  (chupper(*sp) == 'X')  {
X-		*dp = -1;
X-		return(1);
X-		}
X-	if  (do_lev(sp, &tmp) || (tmp < 0) || (tmp > 0xFF))  {
X-		fprintf(stderr, tf_bad, prog_name, err, sp);
X-		exit(3);
X-		}
X-	*dp = tmp;
X-
X-	for  ( q=sp ; isxdigit(*q) ; ++q );
X-	return((short int)(q - sp));
X-
X-	}
X-
X-	 /*  edit the file (top-level interaction)  */
X-
X-
X-void do_edt()
X-	{
X-	register char
X-		*p;
X-	register short int
X-		nrd;
X-
X-
X-	while  (((nrd=read(0, inbuf, 100)) > 0) || get_st())  {
X-		if  (nrd < 0)		/* ^C caused I/O err */
X-			nrd = 0;
X-		*(inbuf+nrd) = 0;	/* null at end-of-input */
X-		if  (p = strchr(inbuf, '\n'))
X-			*p = 0;
X-		p = inbuf;
X-		while (iswhite(*p))
X-			++p;
X-		switch (chupper(*p))  {
X-			case 'F':
X-				do_src(p+1);
X-				break;
X-			case 'E':
X-				do_inp(p+1);
X-				break;
X-			case 'D':
X-				do_dmp(p+1);
X-				break;
X-			case 'Q':
X-			case 'X':
X-				return;
X-			case '?':
X-				printf("D-display  E-enter  F-find  Q-exit\n");
X-				break;
X-			default:
X-				printf("unknown: %c\n", *p);
X-			case 0:
X-				break;
X-			}
X-		}
X-
X-	}
X-
X-	 /*  dump values  */
X-
X-
X-void do_dmp(p)
X-char	*p;
X-	{
X-	register short int
X-		sz, nd;
X-	long int
X-		ed_adr,
X-		ed_cur,
X-		ed_end,
X-		lnend;
X-
X-
X-	if  (do_hdr('R', p, &ed_adr, &ed_end))	/* input bad */
X-		return;
X-
X-	ed_cur = ed_adr;		/* back to start */
X-
X-	do  {
X-		lnend = ed_cur - (ed_cur % 16) + 15;
X-		if  (lnend > ed_end)
X-			lnend = ed_end;
X-		sz = lnend - ed_cur + 1;
X-		if  ((nd = read(ed_fd, ed_buf, sz)) < sz)
X-			sz = nd;
X-		if  (sz < 1)  {
X-			printf("e-o-f\n");
X-			break;
X-			}
X-		printf(tf_8x, ed_cur);
X-		for  ( nd=0 ; nd= 0  ; )  {
X-		if  ((n > 0) && (write(ed_fd, ed_buf, n) < n))  {
X-			fprintf(stderr, tf_wre, ed_fn, ed_cur, n);
X-			break;
X-			}
X-		if  ((ed_cur += n) > ed_end)	/* gave exit point */
X-			break;
X-		}
X-
X-	}
X-
X-
X-	 /*  find values in file  */
X-
X-#define	 MATCH		(*(ed_buf+bufm) == *(match+bufo+bufm))
X-
X-void do_src(p)
X-char	*p;
X-	{
X-	register short int
X-		nsrc,				/* # to search for */
X-		nbuf,				/* # chars in buff */
X-		bufo,				/* buffer offset */
X-		bufm,				/* buffer # matched */
X-		nrd;
X-	long int
X-		ed_adr,
X-		ed_cur,
X-		ed_end,
X-		val;
X-
X-
X-	if  (do_hdr('R', p, &ed_adr, &ed_end))	/* input bad */
X-		return;
X-
X-	ed_cur = ed_adr;		/* back to start */
X-
X-	if  ((nsrc = get_ln(0L)) <= 0)  {
X-		printf(tf_nos);
X-		return;
X-		}
X-
X-	printf("searching...");
X-	nrd = nbuf = read(ed_fd, match, 2*SZ);
X-	for  ( bufo=0 ;; )  {
X-		for  ( bufm=0 ; (bufm < nsrc) && MATCH ; ++bufm );
X-		if  (bufm == nsrc)  {
X-			printf(tf_fnd, ed_cur);
X-			return;
X-			}
X-		++ed_cur;		/* start at next char */
X-		if  (++bufo > SZ)  {	/* must read more */
X-			move(match, match+SZ, SZ);
X-			bufo -= SZ;
X-			nbuf -= SZ;
X-			if  (get_st())	/* input, stop search */
X-				nrd = 0;
X-			if  (nrd && ((nrd=read(ed_fd, match+SZ, SZ)) > 0))
X-				nbuf += nrd;
X-			}
X-		if  ((bufo >= nbuf) || (ed_cur > ed_end))  {
X-			printf(tf_nfd, ed_cur);
X-			return;
X-			}
X-		}
X-
X-	}
X-
X-	 /*  common support routines  */
X-
X-
X- /*  handle the command understanding for both display and edit
X-  *  expects
X-  *	sup		'R', 'W' if reading, writing required
X-  *	p		user's input
X-  *	sad, ead	ptrs to display/edit start/end addr
X-  *  returns
X-  *	  0		good input
X-  *	 -1		didn't
X-  */
X-static short int do_hdr(sup, p, sad, ead)
X-char	sup, *p;
X-long int *sad, *ead;
X-	{
X-
X-	if  (rw_sup && (rw_sup != sup))  {	/* make sure it's OK */
X-		printf(tf_sup, (sup=='R') ? tx_rd : tx_wr);
X-		return;
X-		}
X-
X-	if  (do_lev(p, sad))			/* get starting addr */
X-		return(-1);
X-
X-	*ead = 0x40000000;			/* dflt end addr */
X-
X-	while (iswhite(*p))			/* skip white space */
X-		++p;
X-
X-	if  ((p = strbrk(p, "-, ")) && do_lev(++p, ead))  {
X-		printf(tf_bad, prog_name, "end", p);
X-		return(-1);
X-		}
X-
X-	if  (*ead < *sad)  {
X-		printf(tf_bdr, *sad, *ead);
X-		return(-1);
X-		}
X-
X-	if  (lseek(ed_fd, *sad, 0) != *sad)  {	/* do the seek */
X-		printf(tf_sek, *sad);
X-		return(-1);
X-		}
X-
X-	return(0);
X-
X-	}
X-
X-
X- /*  evaluate an address
X-  *  expects
X-  *	p	ptr to addr to scan
X-  *	adr	addr to receive value if we found number
X-  *  returns
X-  *	 0	worked
X-  *	-1	no addr found
X-  *  note
X-  *	if it works, *adr will be filled in.
X-  */
X-
X-static short int do_lev(p, adr)
X-char	*p;
X-long int *adr;
X-	{
X-	register long int
X-		val;
X-
X-
X-	while (iswhite(*p))		/* skip */
X-		++p;
X-
X-	if  (! isxdigit(*p))
X-		return(-1);
X-
X-	for  ( val=0 ; isxdigit(*p) ; ++p )
X-		val = (val << 4) + dehex(*p);
X-
X-	if  (*p && (! iswhite(*p)) && (*p != '=') && (*p != '-'))
X-		return(-1);
X-
X-	*adr = val;
X-	return(0);
X-
X-	}
X-
X-
X- /*  get a list of numbers into the edit buffer
X-  *  expects
X-  *	ed_cur	address to be printed in prompt
X-  *  returns
X-  *	 -1	trouble
X-  *	 n	# bytes specified on line by user
X-  *  fills in ed_buf with the values given
X-  */
X-
X-static short int get_ln(ed_cur)
X-long int ed_cur;
X-	{
X-	register char
X-		*p;
X-	register short int
X-		n;
X-	long int
X-		val;
X-
X-
X-	printf(tf_8x, ed_cur);			/* prompt */
X-	zero(inbuf, SZ);
X-	if  (read(0, p=inbuf, 200) < 1)  {	/* hit EOF */
X-		fputs(" ** OK\n", stdout);
X-		return(-1);
X-		}
X-	for  ( n=0 ; *p ; )  {			/* scan & convert */
X-		if  (do_lev(p, &val) ||
X-		    (val > 0x00FF) || (val < 0))  {
X-			printf("bad value: %s\n", p);
X-			n = 0;
X-			break;
X-			}
X-		*(ed_buf+(n++)) = val;
X-		while (isxdigit(*p))
X-			++p;
X-		while (isxdigit(*p))
X-			++p;
X-		if  (*p == ',')
X-			++p;
X-		while (iswhite(*p))
X-			++p;
X-		}
X-
X-	return(n);
X-
X-	}
X-
X-	 /*  user-attention handlers  */
X-
X- /*  user hits ^C, set flag to indicate same
X-  *  note:  under ms-dos, signal() only works for ^C
X-  *	but that's OK.  use MS-C; lattice doesn't have
X-  *	signal(2).
X-  */
X-static short int sig_st()
X-	{
X-
X-	signal(SIGINT, sig_st);		/* continued protection */
X-	printf(tx_int);			/* ack for abuser */
X-	stoppt = 1;			/* set flag */
X-
X-	}
X-
X-
X- /*  routine to see if user wants to stop command
X-  *  checks/resets "stoppt" flag set by ^C
X-  *  if machine has rdchk() uses that to see if pending input
X-  */
X- /* $SYSDEP */
X-static short int get_st()
X-	{
X-
X-	if  (stoppt)  {			/* hit ^C */
X-		stoppt = 0;		/* clear it */
X-		return(1);
X-		}
X-
X-	return(rdchk(0) > 0);		/* pending input */
X-
X-	}
X-
X-	 /*  local library routines  */
X-
X- /*  these routines normally live in a local library.  the names
X-  *  are actually left-overs from CP/M days.
X-  */
X-#ifndef	DONT_NEED
X- /*  convert a hex digit  */
X-int dehex(c)
X-int	c;
X-	{
X-	if  ((c >= '0') && (c <= '9'))
X-		return(c - '0');
X-	if  ((c >= 'A') && (c <= 'F'))
X-		return(c + 10 - 'A');
X-	if  ((c >= 'a') && (c <= 'f'))
X-		return(c + 10 - 'a');
X-	return(-1);
X-	}
X-
X- /*  find character in "breakset"  */
X-char *strbrk(s1, s2)
X-register char *s1, *s2;
X-	{
X-
X-	if  (s1 && s2)				/* have strings */
X-		for  ( ; *s1 ; ++s1 )		/* scan string */
X-			if  (strchr(s2, *s1))	/* match any? */
X-				return(s1);	/* yup, winner */
X-
X-	return((char *)0);
X-
X-	}
X-
X- /*  case conversion -- don't trust "toupper" or "tolower  */
X-int chupper(c)
X-int	c;
X-	{
X-	return(((c >= 'a') && (c <= 'z')) ? (c - ('a'-'A')) : c);
X-	}
X-
X-#endif
X-
END_OF_FILE