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