home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / common / patchstr.c < prev    next >
C/C++ Source or Header  |  2001-12-12  |  5KB  |  190 lines

  1. /*
  2.  * patchstr.c -- install a string at preconfigured points in an executable
  3.  *
  4.  *  Usage:  patchstr filename newstring        -- to patch a file
  5.  *          patchstr filename            -- to report existing values
  6.  *
  7.  *  Patchstr installs or changes strings in an executable file.  It replaces
  8.  *  null-terminated strings of up to 500 characters that are immediately
  9.  *  preceded by the eighteen (unterminated) characters "%PatchStringHere->".
  10.  *
  11.  *  If the new string is shorter than the old string, it is null-padded.
  12.  *  If the old string is shorter, it must have suffient null padding to
  13.  *  accept the new string.
  14.  *
  15.  *  If no "newstring" is specified, existing values are printed.
  16.  *
  17.  *  4-Aug-91, 14-Feb-92 gmt
  18.  */
  19.  
  20. #include "../h/rt.h"
  21.  
  22. #undef strlen
  23.  
  24. void    report        (char *filename);
  25. void    patchstr    (char *filename, char *newstring);
  26. int    findpattern    (FILE *f);
  27. int    oldval        (FILE *f, char *buf);
  28.  
  29. /* guard pattern; first character must not reappear later */
  30. #define PATTERN "%PatchStringHere->"
  31.  
  32. /* maximum string length */
  33. #define MAXLEN 500
  34.  
  35. int exitcode = 0;        /* exit code; nonzero if any problems */
  36. int nfound = 0;            /* number of strings found */
  37. int nchanged = 0;        /* number of strings changed */
  38.  
  39. /*
  40.  * main program
  41.  */
  42. int main (argc, argv)
  43. int argc;
  44. char *argv[];
  45.    {
  46.    char *fname, *newstr;
  47.  
  48.    if (argc < 2 || argc > 3) {
  49.       fprintf(stderr, "usage: %s filename [newstring]\n", argv[0]);
  50.       exit(1);
  51.       }
  52.    fname = argv[1];
  53.    newstr = argv[2];
  54.    if (newstr)
  55.       patchstr(fname, newstr);
  56.    else
  57.       report(fname);
  58.    exit(exitcode);
  59.    /*NOTREACHED*/
  60.    }
  61.  
  62. /*
  63.  * report (filename) -- report existing string values in a file
  64.  */
  65. void report (fname)
  66. char *fname;
  67.    {
  68.    FILE *f;
  69.    long posn;
  70.    int n;
  71.    char buf[MAXLEN+2];
  72.  
  73.    if (!(f = fopen(fname, ReadBinary))) {    /* open read-only */
  74.       perror(fname);
  75.       exit(1);
  76.       }
  77.    while (findpattern(f)) {        /* find occurrence of magic string */
  78.       nfound++;
  79.       posn = ftell(f);            /* remember current location */
  80.       n = oldval(f, buf);        /* check available space */
  81.       fseek(f, posn, 0);        /* reposition to beginning of string */
  82.       if (n > MAXLEN) {
  83.          strcpy (buf+40, "...  [unterminated]");
  84.          exitcode = 1;
  85.          }
  86.       printf("at byte %ld:\t%s\n", posn, buf);    /* print value */
  87.       }
  88.    if (nfound == 0) {
  89.       fprintf(stderr, "flag pattern not found\n");
  90.       exitcode = 1;
  91.       }
  92.    }
  93.  
  94. /*
  95.  * patchstr (filename, newstring) -- patch a file
  96.  */
  97. void patchstr (fname, newstr)
  98. char *fname, *newstr;
  99.    {
  100.    FILE *f;
  101.    long posn;
  102.    int n;
  103.    char buf[MAXLEN+2];
  104.  
  105.    if (!(f = fopen(fname, ReadEndBinary))) {    /* open for read-and-update */
  106.       perror(fname);
  107.       exit(1);
  108.       }
  109.    while (findpattern(f)) {        /* find occurrence of magic string */
  110.       nfound++;
  111.       posn = ftell(f);            /* remember current location */
  112.       n = oldval(f, buf);        /* check available space */
  113.       fseek(f, posn, 0);        /* reposition to beginning of string */
  114.       if (n > MAXLEN) {
  115.          fprintf(stderr, "at byte %ld: unterminated string\n", posn);
  116.          exitcode = 1;
  117.          }
  118.       else if (n < (int)strlen(newstr)) {
  119.          fprintf (stderr, "at byte %ld: buffer only holds %d characters\n",
  120.             posn, n);
  121.          exitcode = 1;
  122.          }
  123.       else {
  124.          fputs(newstr, f);        /* rewrite string with new value */
  125.          n -= strlen(newstr);
  126.          while (n-- > 0)
  127.             putc('\0', f);        /* pad out with NUL characters */
  128.          nchanged++;
  129.          fseek(f, 0L, 1);        /* re-enable reading */
  130.          }
  131.       }
  132.    if (nfound == 0) {
  133.       fprintf(stderr, "flag pattern not found\n");
  134.       exitcode = 1;
  135.       }
  136.    else
  137.       fprintf(stderr, "replaced %d occurrence%s\n", nchanged,
  138.          nchanged == 1 ? "" : "s");
  139.    }
  140.  
  141. /*
  142.  * findpattern(f) - read until the magic pattern has been matched
  143.  *
  144.  *  Return 1 if successful, 0 if not.
  145.  */
  146. int findpattern(f)
  147. FILE *f;
  148.    {
  149.    int c;
  150.    char *p;
  151.  
  152.    p = PATTERN;            /* p points to next char we're looking for */
  153.    for (;;) {
  154.       c = getc(f);        /* get next char from file */
  155.       if (c == EOF)
  156.          return 0;        /* if EOF, give up */
  157.       if (c != *p) {
  158.          p = PATTERN;        /* if mismatch, start over */
  159.          if (c == *p)        /* (but see if matched pattern start) */
  160.             p++;
  161.          continue;
  162.          }
  163.       if (*++p == '\0')        /* if entire pattern matched */
  164.          return 1;
  165.       }
  166.    }
  167.  
  168. /*
  169.  * oldval(f, buf) - read old string into buf and return usable length
  170.  *
  171.  *  The "usable" (replaceable) length for rewriting takes null padding into
  172.  *  account up to MAXLEN.  A returned value greater than that indicates an
  173.  *  unterminated string.  The file will need to be repositioned after calling
  174.  *  this function.
  175.  */
  176. int oldval(f, buf)
  177. FILE *f;
  178. char buf[MAXLEN+2];
  179.    {
  180.    int n;
  181.    char *e, *p;
  182.  
  183.    n = fread(buf, 1, MAXLEN+1, f);    /* read up to MAXLEN + null char */
  184.    e = buf + n;                /* note end of read area */
  185.    n = strlen(buf);            /* count string length proper */
  186.    for (p = buf + n + 1; p < e && *p == '\0'; p++)
  187.       n++;                /* count nulls beyond end */
  188.    return n;                /* return usable length */
  189.    }
  190.