home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v92.tgz
/
v92.tar
/
v92
/
src
/
common
/
patchstr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-22
|
5KB
|
192 lines
/*
* patchstr.c -- install a string at preconfigured points in an executable
*
* Usage: patchstr filename newstring -- to patch a file
* patchstr filename -- to report existing values
*
* Patchstr installs or changes strings in an executable file. It replaces
* null-terminated strings of up to 500 characters that are immediately
* preceded by the eighteen (unterminated) characters "%PatchStringHere->".
*
* If the new string is shorter than the old string, it is null-padded.
* If the old string is shorter, it must have suffient null padding to
* accept the new string.
*
* If no "newstring" is specified, existing values are printed.
*
* 4-Aug-91, 14-Feb-92 gmt
*/
#include "::h:rt.h"
#undef strlen
int report Params((char *filename));
int patchstr Params((char *filename, char *newstring));
int findpattern Params((FILE *f));
int oldval Params((FILE *f, char *buf));
/* guard pattern; first character must not reappear later */
#define PATTERN "%PatchStringHere->"
/* maximum string length */
#define MAXLEN 500
int exitcode = 0; /* exit code; nonzero if any problems */
int nfound = 0; /* number of strings found */
int nchanged = 0; /* number of strings changed */
/*
* main program
*/
main (argc, argv)
int argc;
char *argv[];
{
char *fname, *newstr;
if (argc < 2 || argc > 3) {
fprintf(stderr, "usage: %s filename [newstring]\n", argv[0]);
exit(1);
}
fname = argv[1];
newstr = argv[2];
if (newstr)
patchstr(fname, newstr);
else
report(fname);
exit(exitcode);
/*NOTREACHED*/
}
/*
* report (filename) -- report existing string values in a file
*/
report (fname)
char *fname;
{
FILE *f;
long posn;
int n;
char buf[MAXLEN+2];
if (!(f = fopen(fname, ReadBinary))) { /* open read-only */
perror(fname);
exit(1);
}
while (findpattern(f)) { /* find occurrence of magic string */
nfound++;
posn = ftell(f); /* remember current location */
n = oldval(f, buf); /* check available space */
fseek(f, posn, 0); /* reposition to beginning of string */
if (n > MAXLEN) {
strcpy (buf+40, "... [unterminated]");
exitcode = 1;
}
printf("at byte %ld:\t%s\n", posn, buf); /* print value */
}
if (nfound == 0) {
fprintf(stderr, "flag pattern not found\n");
exitcode = 1;
}
}
/*
* patchstr (filename, newstring) -- patch a file
*/
patchstr (fname, newstr)
char *fname, *newstr;
{
FILE *f;
long posn;
int n;
char buf[MAXLEN+2];
if (!(f = fopen(fname, ReadEndBinary))) { /* open for read-and-update */
perror(fname);
exit(1);
}
while (findpattern(f)) { /* find occurrence of magic string */
nfound++;
posn = ftell(f); /* remember current location */
n = oldval(f, buf); /* check available space */
fseek(f, posn, 0); /* reposition to beginning of string */
if (n > MAXLEN) {
fprintf(stderr, "%at byte %ld: unterminated string\n",
posn);
exitcode = 1;
}
else if (n < (int)strlen(newstr)) {
fprintf (stderr, "at byte %ld: buffer only holds %d characters\n",
posn, n);
exitcode = 1;
}
else {
fputs(newstr, f); /* rewrite string with new value */
n -= strlen(newstr);
while (n-- > 0)
putc('\0', f); /* pad out with NUL characters */
nchanged++;
fseek(f, 0L, 1); /* re-enable reading */
}
}
if (nfound == 0) {
fprintf(stderr, "flag pattern not found\n");
exitcode = 1;
}
else
fprintf(stderr, "replaced %d occurrence%s\n", nchanged,
nchanged == 1 ? "" : "s");
}
/*
* findpattern(f) - read until the magic pattern has been matched
*
* Return 1 if successful, 0 if not.
*/
int findpattern(f)
FILE *f;
{
int c;
char *p;
p = PATTERN; /* p points to next char we're looking for */
for (;;) {
c = getc(f); /* get next char from file */
if (c == EOF)
return 0; /* if EOF, give up */
if (c != *p) {
p = PATTERN; /* if mismatch, start over */
if (c == *p) /* (but see if matched pattern start) */
p++;
continue;
}
if (*++p == '\0') /* if entire pattern matched */
return 1;
}
}
/*
* oldval(f, buf) - read old string into buf and return usable length
*
* The "usable" (replaceable) length for rewriting takes null padding into
* account up to MAXLEN. A returned value greater than that indicates an
* unterminated string. The file will need to be repositioned after calling
* this function.
*/
oldval(f, buf)
FILE *f;
char buf[MAXLEN+2];
{
int n;
char *e, *p;
n = fread(buf, 1, MAXLEN+1, f); /* read up to MAXLEN + null char */
e = buf + n; /* note end of read area */
n = strlen(buf); /* count string length proper */
for (p = buf + n + 1; p < e && *p == '\0'; p++)
n++; /* count nulls beyond end */
return n; /* return usable length */
}