home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / zap / zap.c < prev   
Encoding:
C/C++ Source or Header  |  1988-01-31  |  24.1 KB  |  1,131 lines

  1. /* zap.c - program to inspect/patch binary files */
  2.  
  3. static char SCCS_id[] = "@(#)@ zap    1.9    zap.c";
  4.  
  5. static char cprght[] = "\
  6. @(#) Written by Johan Vromans at Multihouse Research, Gouda, the Netherlands.\n\
  7. @(#) Copyright 1987 Johan Vromans.\n\
  8. @(#) Distribution free as long as you give credit to the original author.\n\
  9. @(#) Military use and explicit resale prohibited.\n\
  10. @(#) Usage of this program is always at your own risk.";
  11.  
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include <signal.h>
  15.  
  16. #ifndef TRUE
  17. #  define TRUE    1
  18. #  define FALSE    0
  19. #endif
  20.  
  21. /* define SWAB=1 for byte swapping machines, such as vax and pdp-11 */
  22. /* otherwise, define it to 0 */
  23. /* if unknown, don't define it (or set it to 2) - zap will find out */
  24. /* when known, it is up to the C compiler to optimize unneeded code */
  25.  
  26. #ifndef SWAB
  27. /* SWAB not defined - use info for machines we know */
  28. # ifdef vax            /* DEC VAX */
  29. #  define SWAB 1
  30. # endif
  31. # ifdef pdp11            /* DEC PDP-11 */
  32. #  define SWAB 1
  33. # endif
  34. # ifdef hp9000s200        /* Hewlett-Packard HP9000/200 (M68xxx) */
  35. #   define SWAB 0
  36. # endif
  37. # ifdef hp9000s500        /* Hewlett-Packard HP9000/500 (FocusII) */
  38. #   define SWAB 0
  39. # endif
  40. # ifdef M_I86            /* Intel 86 family */
  41. #   define SWAB    1 
  42. # endif
  43. #endif
  44.  
  45. #ifdef SWAB
  46. # if SWAB > 1        /* explicitly unknown */
  47. #  undef SWAB
  48. # endif
  49. #endif
  50.  
  51. #ifndef SWAB
  52. int    swab = FALSE;        /* use dynamic method */
  53. #else
  54. #  define swab    SWAB        /* leave it to the compiler to eliminate */
  55. #endif
  56.  
  57. /* About swabbing - 
  58.  *
  59.  *    Representation of data
  60.  *
  61.  *                swabbing    non-swabbing
  62.  *    type        numeric    character    character
  63.  *    byte        0x61    'a'        'a'
  64.  *    word        0x6162    'ba'        'ab'
  65.  *    longword    0x61626364    'dcba'        'abcd'
  66.  */
  67.  
  68. #ifdef MSDOS
  69. # ifdef LINT_ARGS
  70.  
  71. /* function defs as generated by MS-C V4.0 */
  72.  
  73. /*global*/  int main (int, char**);
  74. /*global*/  int decod (char*, long*);
  75. /*global*/  unsigned int gv_file (long);
  76. /*global*/  int locate (long);
  77. /*global*/  int enter (long, int);
  78. /*global*/  int get_value (long);
  79. /*global*/  int put_value (long, long);
  80. /*global*/  int ptv_file (long, char);
  81. /*global*/  int push_loc (long);
  82. /*global*/  long pop_loc (void);
  83. /*global*/  int quit_search (void);
  84. /*global*/  int search (void);
  85. /*global*/  int verify (void);
  86. /*global*/  int gt_line (char*, char*, long, long, char, char*);
  87. /*global*/  int gt_val (char*, long*);
  88. /*global*/  char* pr_val (long, int);
  89. /*global*/  int zap (char*);
  90. /*global*/  int cant (char*);
  91. /*global*/  int remark (char*, long);
  92. /*global*/  int error (char*);
  93. /*global*/  int swabcheck (void);
  94.  
  95. # endif
  96. #endif
  97.  
  98. long    lseek ();
  99. char    *strcpy ();
  100. char    *calloc ();
  101. char    *realloc ();
  102. void    exit();
  103. #define    V_printf    (void) printf
  104. #define    V_fprintf    (void) fprintf
  105. #define    V_sprintf    (void) sprintf
  106. #ifdef lint
  107. void clearerr ();
  108. #endif
  109.  
  110. char    *my_name    = "zap";    /* identification */
  111. char    *usage      = "usage: zap [-cdrsvw] file";
  112.  
  113. /* option flags */
  114.  
  115. int    f_check   = FALSE;    /* request checksum */
  116. int    f_sum     = FALSE;    /* print checksum */
  117. int     f_write   = FALSE;    /* read-write */
  118. int    f_silent  = FALSE;    /* silent */
  119. int    f_batch   = FALSE;    /* running batch mode */
  120. int    f_verbose = FALSE;    /* give more info */
  121.  
  122. /* main routine */
  123.  
  124. main (argc, argv)
  125. int    argc;        /* # arguments + 1 */
  126. char    *argv[];    /* argument pointers */
  127.  
  128.   {
  129.     int        file_cnt;    /* number of files processed */
  130.     char    *arg_ptr;    /* argument pointer */
  131.     char    c;        /* current option character */
  132.  
  133.     swabcheck ();        /* verify or establish swabbing mode */
  134.  
  135.     /* ignore first argument (program name) */
  136.  
  137.     argc--;
  138.     argv++;
  139.  
  140.     f_batch = !isatty (0);
  141.     file_cnt = 0;        /* haven't seen one yet */
  142.  
  143.     while (argc-- > 0)        /* through arguments */
  144.       {
  145.         /* fetch a pointer to the current argument, and
  146.          * increase argv
  147.          */
  148.  
  149.         arg_ptr = *argv;
  150.         argv++;
  151.  
  152.         if (*arg_ptr == '-')        /* must be an option */
  153.           {
  154.             while (c = *++arg_ptr)    /* get option character */
  155.               switch (c)
  156.                 {
  157.  
  158.               case  'C' :
  159.               case  'c' :
  160.                           f_check = TRUE;    /* request checksum */
  161.                           break;
  162.  
  163.               case  'D' :
  164.               case  'd' :
  165.                           f_sum = TRUE;        /* print checksum */
  166.                           break;
  167.  
  168.               case  'R' :
  169.               case  'r' :
  170.                           f_write = FALSE;    /* read-only */
  171.                           break;
  172.  
  173.               case  'S' :
  174.               case  's' :
  175.                           f_silent = TRUE;    /* a little more quiet */
  176.                           break;
  177.  
  178.               case  'V' :
  179.               case  'v' :
  180.               V_printf ("zap version 1.9\n");
  181. #ifndef SWAB
  182.                     if (!f_verbose)
  183.                 remark ("you may recompile with \"-DSWAB=%ld\"",
  184.                   (long)swab);
  185. #endif
  186.                           f_verbose = TRUE;    /* a little less quiet */
  187.                           break;
  188.               case  'W' :
  189.               case  'w' :
  190.                           f_write = TRUE;    /* allow write access */
  191.                           break;
  192.  
  193.               default   : error (usage);
  194.                           break;
  195.                 }
  196.  
  197.             /* this ends the option processing */
  198.           }
  199.         else
  200.           {
  201.             /* it must be a file specification */
  202.  
  203.             file_cnt++;        /* now we've seen one */
  204.  
  205.             zap (arg_ptr);
  206.  
  207.             /* this ends the file processing */
  208.           }
  209.  
  210.         /* this ends the argument processing */
  211.       }
  212.  
  213.     /* if there were no filespecs, give error */
  214.  
  215.     if (!file_cnt)
  216.       error (usage);
  217.  
  218.     /* that's it */
  219.  
  220. #ifdef vaxc
  221.     return (1);
  222. #else
  223.     return (0);
  224. #endif
  225.   }
  226.  
  227. /* current type values. note - value is also size of type */
  228.  
  229. int    cur_type;
  230. #define    BYTE    1
  231. #define WORD    2
  232. #define LWORD    4
  233.  
  234. char dp_type [] = " \\/ |";
  235.  
  236. /* current display mode */
  237.  
  238. int cur_printmode;
  239. #define OCTAL    0
  240. #define DECIMAL    1
  241. #define HEX    2
  242. #define ASCII    3
  243.  
  244. char *defffmt[]    = { "0%05lo", "%6ld", "x%05lx", "0%05lo" };
  245. char *deffmt[]    = { "0%lo", "%ld", "x%lx", "0%lo" };
  246.  
  247. #define BYTEVAL(x)    ((x) & 0xff)
  248.  
  249. /* current file */
  250.  
  251. FILE    *zf;
  252.  
  253. /* get (decimal, hex or octal) value from input line */
  254. /* a zero return value means : ok */
  255.  
  256. int decod (buf, lp)
  257. char    *buf;
  258. long    *lp;
  259.   {
  260.     long    num;
  261.     char    *cp;
  262.     int dooct = FALSE;
  263.     int dohex = FALSE;
  264.     int doasc = FALSE;
  265.  
  266.     num = 0;
  267.     cp = buf;
  268.     if (*cp == ';')        /* select mode */
  269.       {
  270.     cp++;
  271.         if (*cp == 'x' || *cp == 'X')
  272.         dohex = TRUE;
  273.     else
  274.     if (*cp == 'o' || *cp == 'O')
  275.         dooct = TRUE;
  276.     else
  277.     if (*cp == 'd' || *cp == 'D')
  278.       ;
  279.     else
  280.     if (*cp == 'a' || *cp == 'A')
  281.         doasc = TRUE;
  282.     else
  283.       V_printf ("input error");
  284.     cp++;
  285.       }
  286.     else
  287.       {
  288.     while (*cp == '0')
  289.       {
  290.         dooct = TRUE;
  291.         cp++;
  292.       }
  293.     if (*cp == 'x' || *cp == 'X')
  294.       {
  295.         cp++;
  296.         dohex = TRUE;
  297.       }
  298.       }
  299.  
  300.     if (dohex)
  301.       {
  302.     while (isxdigit (*cp))
  303.       {
  304.         num = num * 16 
  305.           + (isdigit (*cp) 
  306.              ? *cp - '0' 
  307.              : (*cp | 0x20) - 'a' + 10);
  308.         cp++;
  309.       }    
  310.       }
  311.     else
  312.     if (dooct)
  313.       {
  314.     while (isdigit (*cp) && *cp < '8')
  315.       {
  316.         num = num * 8 + *cp - '0';
  317.         cp++;
  318.       }    
  319.       }
  320.     else
  321.     if (doasc)
  322.       {
  323.     int i;
  324.     for (i = 0; i < cur_type && *cp; i++)
  325.       {
  326.         if (swab)
  327.         num += ((long)(*cp++)) << (i << 3);
  328.         else
  329.         num = (num << 8) + *cp++;
  330.       }
  331.       }
  332.     else
  333.       {
  334.     while (isdigit (*cp))
  335.       {
  336.         num = num * 10 + *cp - '0';
  337.         cp++;
  338.       }    
  339.       }
  340.  
  341.     *lp = num;
  342.     if (!*cp)
  343.       return (0);
  344.     if (*cp == '^')
  345.       return (-1);    /* special return value for zap */
  346.     else
  347.       return (1);
  348.   }
  349.  
  350. /* retrieve byte from file */
  351.  
  352. unsigned gv_file (addr)
  353. long    addr;
  354.   {
  355.     long    l;
  356.  
  357.     if (fseek (zf, addr, 0))
  358.       remark ("cannot position to %ld", addr);
  359.  
  360.     (void) clearerr (zf);
  361.     l = fgetc (zf);
  362.  
  363.     if (l == EOF)
  364.       remark (ferror(zf) ? "cannot read at %ld" : "read beyond eof", addr);
  365.  
  366.     return (BYTEVAL(l));
  367.   }
  368.  
  369. #define BUF_INC    512
  370. int    tbl_max = BUF_INC;
  371.  
  372. struct ntry
  373.   {
  374.     long    addr;
  375.     char    val;
  376.     char    old;
  377.   }
  378.     *tbl,        /* value table */
  379.     *tbl_cur,        /* last referenced entry in table */
  380.     *tbl_free,        /* next free entry in table */
  381.     *tbl_ptr;        /* work pointer into table */
  382.  
  383. int locate (adr)
  384. long    adr;
  385.   {
  386.     /* lookup address in table. return tbl_cur at correct entry
  387.      * or next higher */
  388.  
  389.     if (tbl_cur >= tbl && tbl_cur < tbl_free && tbl_cur->addr == adr)
  390.       /* just looked up */
  391.       return (TRUE);
  392.  
  393.     for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
  394.       {
  395.         if (tbl_cur->addr > adr)
  396.           break;
  397.         if (tbl_cur->addr == adr)
  398.           return (TRUE);
  399.       }
  400.     return (FALSE);
  401.   }
  402.  
  403. enter (addr, val)
  404. long    addr;
  405. int    val;
  406.   {
  407.     char    old;
  408.  
  409.     /* lookup address */
  410.     if (locate (addr))
  411.       {
  412.         /* store value, if different from file value */
  413.         if (val != tbl_cur->old)
  414.           {
  415.             tbl_cur->val = val;
  416.              return;
  417.           }
  418.         /* else delete entry from table */
  419.         for (tbl_ptr=tbl_cur; tbl_ptr < tbl_free-1; tbl_ptr++)
  420.           tbl_ptr[0] = tbl_ptr[1];
  421.         tbl_free--;
  422.         return;
  423.       }
  424.  
  425.     /* if not found, tbl_cur points at next higher address entry */
  426.     /* insert new entry at appropriate position */
  427.  
  428.     old = gv_file (addr);
  429.     if (val == old)        /* no-op if new == old */
  430.       return;
  431.  
  432.     /* check for space in table, otherwise extend it */
  433.     if (tbl_free == &tbl[tbl_max])
  434.       {
  435.         tbl_max += BUF_INC;
  436.         if ((tbl = (struct ntry*) realloc ((char*) tbl, (unsigned) tbl_max * sizeof (*tbl))) == NULL)
  437.             error ("table overflow");
  438.       }
  439.  
  440.     for (tbl_ptr=tbl_free-1; tbl_ptr >= tbl_cur; tbl_ptr--)
  441.       tbl_ptr[1] = tbl_ptr[0];
  442.  
  443.     tbl_cur->addr = addr;
  444.     tbl_cur->val = val;
  445.     tbl_cur->old = old;
  446.  
  447.     tbl_free++;
  448.   }
  449.  
  450. /* retrieve value from table */
  451.  
  452. int get_value (addr)
  453. long    addr;
  454.   {
  455.     int        val;
  456.  
  457.     if (locate (addr))
  458.       val = tbl_cur->val;
  459.     else
  460.       val = gv_file (addr);
  461.  
  462.     return (val);
  463.   }
  464.  
  465. /* put byte into table */
  466.  
  467. #define put_byte    enter
  468.  
  469. /* put value into table */
  470.  
  471. put_value (addr, val)
  472. long    addr;
  473. long    val;
  474.   {
  475.     int        i;
  476.  
  477.     for (i=0; i<cur_type; i++)
  478.       {
  479.     register long temp = addr + ((swab) ? i : (cur_type-i-1));
  480.         put_byte (temp, (int)BYTEVAL(val));
  481.         val >>= 8;
  482.       }
  483.   }
  484.  
  485. ptv_file (addr, val)
  486. long    addr;
  487. char    val;
  488.   {
  489.     char     c;
  490.  
  491.     c = val;
  492.  
  493.     if (fseek (zf, addr, 0))
  494.       remark ("cannot position to %ld", addr);
  495.  
  496.     (void) clearerr (zf);
  497.     (void) fputc (c, zf);
  498.     if (ferror(zf) || feof(zf))
  499.       remark ("cannot write at %ld", addr);
  500.   }
  501.  
  502. char    buf [132];
  503. char    *pr_val();
  504.  
  505. #define PREV_MAX 256        /* size of previous goto table    */
  506. long    prevs [PREV_MAX];    /* previous goto table        */
  507. int    prevcnt;        /* next free index in previous table */
  508.  
  509. push_loc (loc)
  510. long loc;
  511.   {
  512.     int i;
  513.     if (prevcnt == PREV_MAX)
  514.       {
  515.     for (i=0; i<prevcnt; i++)
  516.       prevs[i] = prevs[i+1];
  517.     prevcnt--;
  518.       }
  519.     prevs[prevcnt++] = loc;
  520.   }
  521.  
  522. long pop_loc ()
  523.   {
  524.     if (prevcnt > 0)
  525.       return (prevs[--prevcnt]);
  526.     return (0);
  527.   }
  528.  
  529. long    last_value;    /* last printed value        */
  530. long    sstart;        /* search starting value    */
  531. long    ennd;        /* search ending value        */
  532. long    interrupted;    /* search was terminated    */
  533. int    diddots;    /* dots were displayed        */
  534.  
  535. int    quit_search ()
  536.   {
  537.     interrupted = sstart;
  538.     sstart = ennd;
  539.   }
  540.  
  541. foundit (addr)
  542. long addr;
  543.   {
  544.     if (diddots)
  545.       V_printf ("\n");
  546.     V_printf ("Found at ");
  547.     V_printf (defffmt[cur_printmode], addr);
  548.     V_printf ("\n");
  549.     diddots = FALSE;
  550.     push_loc (addr);
  551.   }
  552.  
  553. /* search value in file */
  554.  
  555. search ()
  556.   {
  557.     int        bt;        /* first byte thereof    */
  558.     long    first;
  559.     union {
  560.       long ll;
  561.       char ss[4];
  562.     } uu;
  563.  
  564.     if (!gt_val ("Search for ? ", &uu.ll))
  565.       return;
  566.  
  567.     if (!gt_val ("Start at   ? ", &sstart))
  568.       return;
  569.  
  570.     if (!gt_val ("Stop at    ? ", &ennd))
  571.       return;
  572.  
  573.     /* temporary using first to hold EOF value */
  574.     first = lseek (fileno(zf), 0l, 2);
  575.     if (ennd == 0)
  576.       {
  577.     if (f_verbose)
  578.       {
  579.         V_fprintf (stderr, "EOF at ");
  580.         V_fprintf (stderr, deffmt[cur_printmode], first);
  581.         V_fprintf (stderr, "\n");
  582.       }
  583.     ennd = first - cur_type + 1;
  584.       }
  585.  
  586.     if (sstart > ennd)
  587.       {
  588.     remark ("start > end", 0L);
  589.     return;
  590.       }
  591.  
  592.     if (ennd > first)
  593.       {
  594.     if (f_verbose)
  595.       remark ("end > EOF, truncated", 0L);
  596.     ennd = first;
  597.       }
  598.     /* end of using first to hold EOF value */
  599.  
  600. #ifndef SEARCH_ACTUAL
  601.     if (fseek (zf, sstart, 0))
  602.       {
  603.     V_fprintf (stderr, "cannot position to ");
  604.     V_fprintf (stderr, deffmt[cur_printmode], sstart);
  605.     V_fprintf (stderr, "\n");
  606.     return;
  607.       }
  608. #endif
  609.  
  610.     (void) signal (SIGINT, quit_search);
  611.  
  612.     /* shift to align */
  613.     if (!swab)
  614.       {
  615.     if (cur_type == BYTE)
  616.       uu.ss[0] = uu.ss[3];
  617.     else
  618.     if (cur_type == WORD)
  619.       {
  620.         uu.ss[0] = uu.ss[2];
  621.         uu.ss[1] = uu.ss[3];
  622.       }
  623.       }
  624.     bt = BYTEVAL(uu.ss[0]);
  625.  
  626.     first = sstart;
  627.     diddots = interrupted = FALSE;
  628.  
  629.     while (sstart < ennd)
  630.       {
  631.  
  632.     /* print a dot for every 1K processed */
  633.     if (!f_silent && (((first - sstart) & 0x3ff) == 0) && sstart > first)
  634.       {
  635.         V_printf (".");
  636.         (void) fflush (stdout);
  637.         diddots = TRUE;
  638.       }
  639.  
  640. #ifdef SEARCH_ACTUAL
  641.  
  642.     /* searching the actual values (very slow) */
  643.  
  644.         if (get_value (sstart) == bt)
  645.           {
  646.             if (
  647.             ( cur_type == BYTE    /* looking for byte is easy */
  648.             )
  649.              || ( cur_type == WORD    /* word needs another byte */
  650.                    && (get_value (sstart+1L) == BYTEVAL(uu.ss[1]))
  651.                 )
  652.              || ( cur_type == LWORD     /* lword needs three other bytes */
  653.                && (get_value (sstart+1L) == BYTEVAL(uu.ss[1]))
  654.                && (get_value (sstart+2L) == BYTEVAL(uu.ss[2]))
  655.                && (get_value (sstart+3L) == BYTEVAL(uu.ss[3]))
  656.                 )
  657.                )
  658.            foundit (sstart);
  659.           }
  660.     start++;
  661.  
  662. #else
  663.  
  664.     /* searching the old contents of the file */
  665.  
  666.         if (fgetc (zf) == bt)
  667.           {
  668.         int chr;
  669.         if (cur_type == BYTE)    /* looking for byte is easy */
  670.           foundit (sstart);
  671.         else
  672.           {
  673.         chr = fgetc (zf);
  674.         if (chr == BYTEVAL(uu.ss[1]))
  675.           {
  676.             if (cur_type == WORD)
  677.               {
  678.             foundit (sstart);
  679.             ungetc (chr, zf);
  680.               }
  681.             else
  682.               {
  683.             chr = fgetc (zf);
  684.             if (chr == BYTEVAL(uu.ss[2]))
  685.               {
  686.                 chr = fgetc (zf);
  687.                 if (chr == BYTEVAL(uu.ss[3]))
  688.                   foundit (sstart);
  689.               }
  690.             fseek (zf, sstart+1L, 0);
  691.               }
  692.           }
  693.         else
  694.           ungetc (chr, zf);
  695.           }
  696.       }
  697.         sstart++;
  698.     if (ferror (zf) || feof (zf))
  699.       quit_search ();
  700.  
  701. #endif
  702.  
  703.       }                /* while (sstart < ennd) */
  704.  
  705.     if (diddots)
  706.       V_printf ("\n");
  707.     (void) signal (SIGINT, SIG_DFL);
  708.     if (!f_batch && interrupted)
  709.       {
  710.     V_printf ("Interrupted at ");
  711.     V_printf (defffmt[cur_printmode], sstart);
  712.     V_printf ("\n");
  713.       }
  714.   }
  715.  
  716. /* print verification list */
  717.  
  718. verify ()
  719.   {
  720.     long    addr = 0;
  721.  
  722.     /* display all modifications entered until now. display in portions
  723.      * of cur_printmode. align to lower cur_type boundary
  724.      */
  725.     for (tbl_ptr = tbl; tbl_ptr != tbl_free; tbl_ptr++)
  726.     if (tbl_ptr->addr >= addr)
  727.       {
  728.         addr = tbl_ptr->addr & ~(cur_type-1);
  729.         V_printf ("vfy: ");
  730.         V_printf (defffmt[cur_printmode], addr);
  731.         V_printf ("%c %-7s => ", dp_type[cur_type], pr_val (addr, FALSE));
  732.         V_printf ("%-7s\n", pr_val (addr, TRUE));
  733.         addr += cur_type;
  734.       }
  735.   }
  736.  
  737. int gt_line (dst, prompt, arg1, arg2, arg3, arg4)
  738. char    *dst;
  739. char    *prompt;
  740. long    arg1;
  741. long    arg2;
  742. char    arg3;
  743. char    *arg4;
  744.   {
  745.     if (prompt != NULL && !f_silent)
  746.       V_printf (prompt, arg1, arg2, arg3, arg4);
  747.     (void) fflush (stdout);
  748.     if (!gets (dst))
  749.       {
  750.     if (f_batch && !f_silent)
  751.       V_printf ("[eof]\n");
  752. #ifndef vaxc
  753.     (void) putchar ('\n');
  754. #endif
  755.     return (NULL);
  756.       }
  757.     if (f_batch && !f_silent)
  758.       V_printf ("%s\n", dst);
  759.     if (dst[0] == '^' && dst[1] == 'Z' && dst[2] == '\0')
  760.       return (FALSE);
  761.     else
  762.       return (TRUE);
  763.   }
  764.  
  765. int gt_val (prompt, l)
  766. char    *prompt;
  767. long    *l;
  768.   {
  769.     *l = 0l;
  770.     while (gt_line (buf, prompt, 0L, 0L, '\0', NULL))
  771.       {
  772.         if (!decod (buf, l))
  773.           return (TRUE);
  774.       }
  775.     return (FALSE);
  776.   }
  777.       
  778. /* display value, using current settings (result is in static area) */
  779.  
  780. char *pr_val (addr, cur)
  781. long    addr;
  782. int    cur;        /* 1 = use current, 0 = use previous */
  783.   {
  784.     static char dst [64];
  785.     char    *cp;
  786.     long    val;
  787.     int        i;
  788. #   define getbyte(addr)  BYTEVAL((cur) ? get_value (addr) : gv_file (addr))
  789.  
  790.     last_value = 0;
  791.     if (cur_printmode == ASCII)
  792.       {
  793.         cp = dst;
  794.         for (i=0; i<cur_type; i++)
  795.           {
  796.         val = getbyte (addr);
  797.             addr++;
  798.         if (val >= ' ' && val < 0177 && val != '\\')
  799.           *cp++ = val;
  800.         else
  801.           {
  802.         *cp++ = '\\';
  803.         switch ((int)BYTEVAL(val))
  804.           {
  805.         case '\b':    *cp++ = 'b';
  806.                 break;
  807.         case '\n':    *cp++ = 'n';
  808.                 break;
  809.         case '\t':    *cp++ = 't';
  810.                 break;
  811.         case '\f':    *cp++ = 'f';
  812.                 break;
  813.         case '\r':    *cp++ = 'r';
  814.                 break;
  815.         case '\\':    *cp++ = '\\';
  816.                 break;
  817.         default:    V_sprintf (cp, "%o", val);
  818.                 while (*cp) cp++;
  819.                 break;
  820.           }
  821.           }
  822.         *cp++ = ' ';
  823.       }
  824.     *cp = '\0';
  825.       }
  826.     else
  827.       {
  828.     val = 0l;
  829.     switch (cur_type)
  830.       {
  831.     case BYTE:
  832.             val = getbyte (addr);
  833.         break;
  834.         case WORD:
  835.         if (swab) {
  836.           val =              getbyte (addr+1L);
  837.           val = (val << 8) | getbyte (addr  );
  838.         }
  839.         else {
  840.           val =              getbyte (addr  );
  841.           val = (val << 8) | getbyte (addr+1L);
  842.         }
  843.         break;
  844.     case LWORD:
  845.         if (swab) {
  846.           val =              getbyte (addr+3L);
  847.           val = (val << 8) | getbyte (addr+2L);
  848.           val = (val << 8) | getbyte (addr+1L);
  849.           val = (val << 8) | getbyte (addr  );
  850.         }
  851.         else {
  852.           val =              getbyte (addr  );
  853.           val = (val << 8) | getbyte (addr+1L);
  854.           val = (val << 8) | getbyte (addr+2L);
  855.           val = (val << 8) | getbyte (addr+3L);
  856.         }
  857.             break;
  858.       }
  859.     if ((last_value = val) != 0 || cur_printmode != OCTAL)
  860.       V_sprintf (dst, deffmt[cur_printmode], val);
  861.     else
  862.       (void) strcpy (dst, "0");
  863.       }
  864.  
  865.     return (dst);
  866.   }
  867.  
  868. zap (fname)
  869. char    *fname;
  870.  
  871.   {
  872.     long    base;            /* base of patching sequence    */
  873.     long    offset;            /* offset from base        */
  874.     long    val;            /* holding variable for values    */
  875.     int        i;            /* scratch            */
  876.     char    chr;            /* scratch            */
  877.     int        check;            /* checksum value        */
  878.     int        need_head;        /* header toggle        */
  879.     int        checkwrite = TRUE;    /* check for write access    */
  880.     int        goon = TRUE;        /* until ^Y is used */
  881.     static char *fmt [] = {
  882.                 "0%05lo  0%05lo%c %-7s ",
  883.                 "%6ld  %6ld%c %-7s ",
  884.                 "x%05ld  x%05lx%c %-7s ",
  885.                 "0%05lo  0%05lo%c %-7s " };
  886.  
  887.     /* open file */
  888.  
  889. #ifdef MSDOS
  890.     if ((zf = fopen (fname, (f_write) ? "rb+" : "rb")) == NULL)
  891. #else
  892.     if ((zf = fopen (fname, (f_write) ? "r+" : "r")) == NULL)
  893. #endif
  894.       cant (fname);
  895.  
  896.     /* set defaults and allocate table */
  897.  
  898.     cur_type = BYTE;
  899.     cur_printmode = OCTAL;
  900.     if (!tbl)
  901.       tbl = (struct ntry*) calloc ((unsigned)tbl_max, sizeof (struct ntry));
  902.     if (!tbl)
  903.       error ("no room for table");
  904.     tbl_cur = tbl_free = tbl;
  905.     prevcnt = 0;        /* reset previous location table */
  906.  
  907.     /* loop 1 : loop on Base values */
  908.  
  909.     while (goon && gt_val ("Base ?    ", &base))
  910.       {
  911.         /* loop 2 : loop on offset values */
  912.  
  913.         while (goon && gt_val ("Offset ?  ", &offset))
  914.           {
  915.             need_head = TRUE;
  916.  
  917.             /* loop 3 : loop on patch commands */
  918.  
  919.             while (goon)
  920.               {
  921.                 if (need_head && !f_silent)
  922.                   V_printf ("Base    Offset  Value   New\n");
  923.             need_head = FALSE;
  924.  
  925.                 if (!gt_line (buf, fmt[cur_printmode], base, offset,
  926.                       dp_type[cur_type], pr_val (base+offset, TRUE)))
  927.                   break;
  928.  
  929.                 switch (buf[0])
  930.                   {
  931.             case '\0':
  932.                 /* close current, advance and open new location */
  933.                        offset += cur_type;
  934.                 break;
  935.             case '/':
  936.                 /* re-open current using new type */
  937.                 cur_type = WORD;
  938.                 break;
  939.                 case '\\':
  940.                 /* re-open current using new type */
  941.                 cur_type = BYTE;
  942.                 break;
  943.             case '|':
  944.                 /* re-open current using new type */
  945.                 cur_type = LWORD;
  946.                 break;
  947.             case '^':
  948.             if (buf[1] == '\0')
  949.               {
  950.                 /* close current, backup and open new location */
  951.                 offset -= cur_type;
  952.                 break;
  953.               }
  954.             if (buf[1] != 'Y' || buf[2] != '\0')
  955.               break;
  956.             /* FALL THROUGH */
  957.         case '\031':    /* ^Y */
  958.             goon = FALSE;
  959.             break;
  960.                 case '>':
  961.                         /* goto new location */
  962.                         if (!decod (&buf[1], &val))
  963.                           {
  964.                 push_loc (base+offset);
  965.                             offset = buf[1] ? val : last_value;
  966.                           }
  967.                         break;
  968.                 case '<':
  969.                         /* goto location */
  970.                         if (buf[1] == '\0' && prevcnt > 0)
  971.               offset = pop_loc () - base;
  972.                         break;
  973.             case ';':
  974.                 /* change current display mode ... */
  975.                         chr = buf[1];
  976.                 if (isupper (chr))
  977.                           chr = tolower (chr);
  978.                 if (chr == 'o')
  979.                           cur_printmode = OCTAL;
  980.                 else
  981.                 if (chr == 'd')
  982.                           cur_printmode = DECIMAL;
  983.                 else
  984.                 if (chr == 'x')
  985.                           cur_printmode = HEX;
  986.                 else
  987.                 /* ... or store ascii bytes ... */
  988.                 if (chr == 'a')
  989.                           {
  990.                             cur_printmode = ASCII;
  991.                             for (i=2; chr=buf[i]; i++)
  992.                               {
  993.                 if (checkwrite && !f_write)
  994.                   {
  995.                     need_head = TRUE;
  996.                     checkwrite = FALSE;
  997.                     remark ("no write access", 0L);
  998.                   }
  999.                                 put_byte (base+offset, chr);
  1000.                                 offset++;
  1001.                               }
  1002.                           }
  1003.                 else
  1004.                 /* ... or print modifications ... */
  1005.                 if (chr == 'v')
  1006.                   {
  1007.                             verify ();
  1008.                             need_head = TRUE;
  1009.                           }
  1010.                         else
  1011.                 /* ... or search values */
  1012.                         if (chr == 's')
  1013.                           {
  1014.                             search ();
  1015.                             need_head = TRUE;
  1016.                           }
  1017.  
  1018.                 break;
  1019.                 default:
  1020.                 if ((i = decod (buf, &val)) <= 0)
  1021.                   {
  1022.                 if (checkwrite && !f_write)
  1023.                   {
  1024.                 need_head = TRUE;
  1025.                 checkwrite = FALSE;
  1026.                 remark ("no write access", 0L);
  1027.                   }
  1028.                     put_value (base+offset, val);
  1029.                     if (!i)
  1030.                       offset += cur_type;
  1031.                     else
  1032.                               offset -= cur_type;
  1033.                   }
  1034.                   }
  1035.             /* loop on patch commands */
  1036.               }
  1037.             /* loop on offset values */
  1038.           }
  1039.         /* loop on base values */
  1040.       }
  1041.  
  1042.     /* compute checksum, if requested */
  1043.  
  1044.     if (f_check || f_sum)
  1045.       {
  1046.         check = 0;
  1047.         for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
  1048.           check ^= (BYTEVAL(tbl_cur->val) | ((tbl_cur->old << 8) & 0xff00));
  1049.         if (f_sum)
  1050.       {
  1051.         V_printf ("Checksum = ");
  1052.         V_printf (deffmt[cur_printmode], check);
  1053.         V_printf ("\n");
  1054.       }
  1055.       }
  1056.  
  1057.     /* apply patches, after checksum verification */
  1058.  
  1059.     tbl_cur = tbl;
  1060.  
  1061.     if (f_write)
  1062.       {
  1063.         /* verify checksum */
  1064.  
  1065.         if (f_check)
  1066.           while (gt_val ("Checksum ? ", &val))
  1067.             if (val == check || f_batch)
  1068.               break;
  1069.  
  1070.         if (!(f_check && val != check))
  1071.           for (tbl_cur = tbl; tbl_cur != tbl_free; tbl_cur++)
  1072.                ptv_file (tbl_cur->addr, tbl_cur->val);
  1073.       }
  1074.     
  1075.     if (tbl_cur != tbl_free)
  1076.       error ("no modifications made");
  1077.  
  1078.     if (!f_silent && f_write && tbl == tbl_free)
  1079.       remark ("no modifications requested", 0L);
  1080.  
  1081.     /* close file and exit */
  1082.  
  1083.     (void) fclose (zf);
  1084.   }
  1085.  
  1086. cant (s)
  1087. char *s;
  1088.   {
  1089.     V_fprintf (stderr, "%s: cannot open %s\n", my_name, s);
  1090.     exit (1);
  1091.   }
  1092.  
  1093. remark (s, a)
  1094. char *s;
  1095. long a;
  1096.   {
  1097.     V_fprintf (stderr, "%s: ", my_name);
  1098.     V_fprintf (stderr, s, a);
  1099.     V_fprintf (stderr, "\n");
  1100.   }
  1101.  
  1102. error (s)
  1103. char *s;
  1104.   {
  1105.     V_fprintf (stderr, "%s: %s\n", my_name, s);
  1106.     exit (1);
  1107.   }
  1108.  
  1109. swabcheck ()
  1110.   {
  1111.     union {
  1112.       short s;
  1113.       char a[2];
  1114.     } u;
  1115.     u.s = 0x1357;
  1116. #ifdef SWAB
  1117. #if SWAB
  1118.     if (!(u.a[0] == 0x57 && u.a[1] == 0x13))
  1119.       error ("please recompile with \"-DSWAB=0\"");
  1120. #else
  1121.     if (!(u.a[0] == 0x13 && u.a[1] == 0x57))
  1122.       error ("please recompile with \"-DSWAB=1\"");
  1123. #endif
  1124. #else
  1125.     swab = (u.a[0] == 0x57 && u.a[1] == 0x13);
  1126. #endif
  1127. #ifdef lint
  1128.     SCCS_id[0] = cprght[0] = '\0';
  1129. #endif
  1130.   }
  1131.