home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume13 / bpatch2 < prev    next >
Encoding:
Text File  |  1988-09-11  |  52.4 KB  |  2,250 lines

  1. Subject:  v13i074:  Binary patch program, ported to 80286 etc.
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: rupley!local@ARIZONA.EDU
  7. Posting-number: Volume 13, Issue 74
  8. Archive-name: bpatch2
  9.  
  10. Neat code and program.  Dump or edit files (binary or acsii), displayed by
  11. 256-byte records in side-by-side hex and ascii formats.  Various other
  12. features (eg, toggled swap within byte pairs).  I spent some time tonight
  13. getting bpatch to work well on a Vax (at least one particular Vax) running
  14. BSD4.3 with NFS.  The macros in ctype.h gave some problems.  The code
  15. attached here compiles both on Microport SysV and BSD4.3, without change,
  16. if the proper Makefile is used.  The program appears to work equally in
  17. the two environments.  I expect that there should be little problem in
  18. adjusting for other flavors of BSD or SysV.
  19.  
  20. There are two Makefiles now, for bsd and Sysv.  Small changes in README
  21. and the man pages.
  22.  
  23. John Rupley
  24.     uucp: ..{ihnp4 | hao!noao}!arizona!rupley!local
  25.     internet: rupley!local@megaron.arizona.edu
  26.     telex: 9103508679(JARJAR)
  27.     (H) 30 Calle Belleza, Tucson AZ  85716 - (602) 325-4533
  28.     (O) Dept. Biochemistry, Univ. Arizona, Tucson AZ 85721 - (602) 621-3929
  29.  
  30. ************************cut here******************************************
  31. # To unbundle, sh this file
  32. echo unbundling README 1>&2
  33. cat >README <<'AlBeRtEiNsTeIn'
  34.  
  35. BPATCH.C
  36. Original code written by Garry M. Johnson and Steven Lisk.
  37.  
  38. Neat code and program.  Dump or edit files (binary or acsii), displayed
  39. by 256-byte records in side-by-side hex and ascii formats.  Various
  40. other features (eg, toggled swap within byte pairs).
  41.  
  42. Here converted to 80286 (Microport sysV/AT). More details in bpatch.c, 
  43. under Change History.  Some of the changes also serve to fix code that 
  44. appeared to be broken even for a 32-bit environment.
  45.  
  46. Makefile.sys5 is set for Microport SysV/AT.2.2.  The code should compile 
  47. under standard SysV environments.
  48.  
  49. The man pages are changed only slightly from the original distribution.
  50.  
  51. The code compiles on a Vax running BSD4.3, with Makefile.bsd, of 
  52. course.  Testing was with an AT compatible logged in as a terminal, 
  53. with setenv TERM vt100.  There may be curses/terminal problems for 
  54. other environments.  A terminal which was an adm3a equivalent was ok.
  55.  
  56. Beware of using the shell escape feature!
  57.  
  58. Like the previous authors, I would appreciate learning of further 
  59. changes and improvements in the code:
  60.  
  61. John Rupley
  62.  uucp: ..{ihnp4 | hao!noao}!arizona!rupley!local
  63.  internet: rupley!local@megaron.arizona.edu
  64.  telex: 9103508679(JARJAR)
  65.  (H) 30 Calle Belleza, Tucson AZ 85716 - (602) 325-4533
  66.  (O) Dept. Biochemistry, Univ. Arizona, Tucson AZ 85721 - (602) 621-3929
  67.  
  68. +++++++++++++++++++++original distribution README+++++++++++++++++++++++
  69. >Herewith find BPATCH - a marvelously utile utility.  While not of
  70. >my original creation, I have been given permission to place in the
  71. >public domain.  I have made substantial modifications to the original
  72. >source given to me.  Specifically I cleaned it up a bit and made it
  73. >work with SVR2 curses.  Personally, I think it's pretty neat.
  74. >
  75. >OK - for those of you who may scream by now "WHAT THE HELL IS IT ALREADY?"
  76. >I respond that it is a binary file editor and dump utility!  That's 
  77. >right!  You can dump your file in the nicely laid out side-by-side
  78. >hex and ascii format or you can actually EDIT it at your terminal!
  79. >Yes, I have seen the BED editor that came across the network.
  80. >Unfortunately, it converted the entire file before and after editing.
  81. >Bpatch, on the other hand, works with one 256 byte page at a time.
  82. >It is marvelously useful for looking at things like raw disk UNIFY
  83. >databases and even raw disks!  While the man page may not be absolutely
  84. >up to date, the online help is.  Try the question mark (?) command.
  85. >
  86. >As always, I would love to hear about bugs/changes/enhancements/requests.
  87. >    Steven List @ Benetics Corporation, Mt. View, CA
  88. >    Just part of the stock at "Uncle Bene's Farm"
  89. >    {cdp,engfocus,idi,oliveb,opusys,plx,pyramid,tolerant}!bene!luke!itkin
  90. >
  91. >Addition by the moderator:
  92. >I have added code, surrounded by #ifdef MOD_HAX, that gets bpatch
  93. >(barely?) working on my 4.2 system.  I would be very interested in
  94. >publishing a set of diffs that's less of a hack.  Oh yeah:  I also
  95. >wrote the Makefile.
  96. >    /Rich $alz
  97. +++++++++++++++++++++end of original distribution README++++++++++++++++++++
  98. AlBeRtEiNsTeIn
  99. echo unbundling Makefile.bsd 1>&2
  100. cat >Makefile.bsd <<'AlBeRtEiNsTeIn'
  101. # This may have to change on your system.
  102. # You may have to fiddle with various combinations of curses, termcap,
  103. # terminfo, etc.  Good luck!
  104. LIBS    = -lcurses -ltermcap
  105. #LIBS    = -ltermlib
  106. #LIBS    = -lterminfo
  107. #for sysV
  108. #LIBS    = -lcurses
  109.  
  110. # However you need getopt.
  111. #GETOPT    = -lgetopt
  112. #not for sysV! (nor for some BSD)
  113. #GETOPT    =
  114.  
  115. # If you're running on a 4.[23] system, you probably want this.
  116. WORK    = -DMOD_HAX
  117. #sysV
  118. #WORK    =
  119.  
  120. #BSD or thereabouts
  121. CFLAGS    = -O $(WORK)
  122. #Microport sysV/AT, large model, for sdb debugger
  123. #CFLAGS    = -g -Ml
  124.  
  125. bpatch:        bpatch.o
  126.     $(CC) -o bpatch $(CFLAGS) bpatch.o $(GETOPT) $(LIBS)
  127.  
  128. install:
  129.     @echo Use cp to put things where you want them
  130. AlBeRtEiNsTeIn
  131. echo unbundling Makefile.sys5 1>&2
  132. cat >Makefile.sys5 <<'AlBeRtEiNsTeIn'
  133. # This may have to change on your system.
  134. # You may have to fiddle with various combinations of curses, termcap,
  135. # terminfo, etc.  Good luck!
  136. #LIBS    = -lcurses -ltermcap
  137. #LIBS    = -ltermlib
  138. #LIBS    = -lterminfo
  139. #for sysV
  140. LIBS    = -lcurses
  141.  
  142. # However you need getopt.
  143. #GETOPT    = -lgetopt
  144. #not for sysV! (nor for some BSD)
  145. #GETOPT    =
  146.  
  147. # If you're running on a 4.[23] system, you probably want this.
  148. #WORK    = -DMOD_HAX
  149. #sysV
  150. WORK    =
  151.  
  152. #BSD or thereabouts
  153. #CFLAGS    = -O $(WORK)
  154. #Microport sysV/AT, large model, for sdb debugger
  155. CFLAGS    = -g -Ml
  156.  
  157. bpatch:        bpatch.o
  158.     $(CC) -o bpatch $(CFLAGS) bpatch.o $(GETOPT) $(LIBS)
  159.  
  160. install:
  161.     @echo Use cp to put things where you want them
  162. AlBeRtEiNsTeIn
  163. echo unbundling bpatch.1 1>&2
  164. cat >bpatch.1 <<'AlBeRtEiNsTeIn'
  165. .TH "bpatch" "1" "Benetics Local"
  166. .UC 4
  167. \" .if t .nr LL 7i
  168. \" .if t .nr IN .8i
  169. \" .if n .nr LL 70
  170. \" .if n .nr IN 8
  171. \" .fi
  172. \" .ad b
  173. .SH NAME
  174. bpatch - binary patch and dump file utility
  175. .SH SYNOPSIS
  176. bpatch [ -b blksize ] [ -d ] [ -D pagecnt ] [ -e ] [ -p ] [ -r reclen ] [ -s ] [ -x ] file...
  177. .SH DESCRIPTION
  178. \fIBpatch\fR allows the viewing and/or modification of files, independent of
  179. file type (text, executable, data file, and so forth).  \fIBpatch\fR
  180. allows the data to either be examined at the terminal, dumped to a print
  181. device or file, or edited in the general manner of \fIvi(1)\fR.  The
  182. data in the file is dumped or displayed in \fIpages\fR of 256 bytes.
  183. .SS Options
  184. .IP "-b blksize" 12
  185. The \fI-b\fR option specifies the blocksize of the data file.  This is used
  186. primarily with tapes, and is allowed only with one of the dump (\fI-d\fR
  187. or \fI-D\fR) options.  When this option is specified, the file is opened
  188. in readonly mode.
  189. .IP "-d" 12
  190. The \fI-d\fR option indicates that a dump (no terminal manipulation) is
  191. to be performed.  The entire file will be dumped to standard output.  No
  192. editing of the data is allowed and the file is opened in readonly mode.
  193. <DEL> interrupts a continuous display, producing a pause after the
  194. current record is displayed; at this point, a second <DEL> exits and
  195. and other character begins display of the next file.
  196. .IP "-D pagecnt" 12
  197. The \fI-D\fR option is similar to the \fI-d\fR option, with the
  198. following exception: the pagecnt argument limits the dump to the
  199. specified number of \fIpages\fR.
  200. .IP "-e" 12
  201. The \fI-e\fR option indicates that the file contains EBCDIC data and
  202. should be converted in the character portion of the dump.
  203. .IP "-p" 12
  204. Used with one of the \fIdump\fR options, this option causes the program
  205. to pause between \fIpages\fR.  The program will then wait for the user
  206. to press either the \fIreturn\fR key to continue, or the \fIDEL\fR (or
  207. \fIrubout\fR) key to stop the dump.
  208. .IP "-r reclen" 12
  209. The \fI-r\fR option indicates the record length of the data within the
  210. dump.  When specified, this option causes \fIbpatch\fR to place a colon
  211. (:) between the last byte of one record and the first byte of the next.
  212. .IP "-s" 12
  213. This option turns on the byte swap option.  It may be toggled dynamically
  214. during execution (see \fI-x\fP under Commands below).
  215. .IP "-x" 12
  216. This option specifies the suppression of pages that contain only NUL
  217. characters.  The result is that only the page header (name and page
  218. number) will appear for such a page.  This option may only be used with
  219. one of the dump options.
  220. .SS Arguments
  221. .IP file 12
  222. Any number of files may be specified.
  223. .SS Commands
  224. All commands are valid only in the non-dump, interactive mode.  Commands
  225. may be entered in either upper or lower case.  Commands of the form '^x'
  226. indicate that the control character \fIx\fR is to be entered.
  227. .P
  228. All commands that request movement within a file or between files cannot
  229. be executed if any changes have been made.  To proceed in this case, the
  230. user must either enter the \fIw\fR command, the \fIu\fR command, or the
  231. \fIr\fR command.
  232. .P
  233. Requesting a next or previous file when there is no such will cause the
  234. issuance of an error message.
  235. .P
  236. Note that certain commands allow/require either some text or numeric
  237. value.  In those cases, the user should type in characters and end the
  238. string with either a <cr> or <DEL>.
  239. .IP ? 6
  240. Display the help screen.  The help screen will remain until the user
  241. either redraws the screen (see \fI^r\fR) or changes pages or files.
  242. .IP ! 6
  243. Execute the following command in the shell.
  244. .IP backslash 6
  245. Display the previous page.
  246. .IP <cr> 6
  247. Display the next page.
  248. .IP DEL 6
  249. Quit the program if no changes have been made.
  250. .IP / 6
  251. This command initiates an ASCII search.  The text entered on the command
  252. line will be used as a search string, and the file will be searched
  253. starting with the current page.  When the string is found, the page
  254. containing the string will be displayed.  If the string is not found, an
  255. apapropriate message will be displayed.
  256. .IP ^f 6
  257. Open a named file whose name will be entered on the command line and
  258. followed either by <cr> or DEL.
  259. .IP ^n 6
  260. Open the next file and display the first page.
  261. .IP ^p 6
  262. Open the previous file and display the first page.
  263. .IP ^q 6
  264. Quit without writing current changes.
  265. .IP ^r 6
  266. Redraw the screen.
  267. .IP NNN 6
  268. Entering a numeric value requests that the specified page be displayed.
  269. .IP -x 6
  270. Toggle the command line option represented by \fIx\fR:
  271. .RS 12
  272. .IP a 6
  273. Toggle display to ascii (assume data is ascii).
  274. .IP e 6
  275. Toggle display to dbcdic (assume data is ebcdic).
  276. .IP s 6
  277. Toggle byte swap.
  278. .RE
  279. .IP a 6
  280. Edit the ASCII display.  End edits by pressing the DEL key.  All other
  281. characters will be treated as valid input.  Cursor movement keys (arrows
  282. and home) allow movement within the edit window.  Nonprinting
  283. characters are displayed as dot (.) in this window.
  284. .IP f 6
  285. Display the first page in the current file.
  286. .IP g 6
  287. Display the page containing the byte address typed in following the command.
  288. .IP h 6
  289. Edit the HEXADECIMAL display.  End edits by pressing DEL key.  Cursor
  290. movement keys (arrows and home) allow movement within the edit window.
  291. Two keystrokes are required to modify a byte, and both must be valid
  292. hexadecimal values (0-9 and a-f).  To cancel a change after typing one
  293. character, press DEL.
  294. .IP l 6
  295. Display the last page in the current file.
  296. .IP q 6
  297. Quit the file.  A warning will be issued if any changes have been made
  298. but not written out.
  299. .IP r 6
  300. Reread the current page.
  301. .IP u 6
  302. Undo all changes to the current page.
  303. .IP w 6
  304. Write out the current page.
  305. .SH "SEE ALSO"
  306. od(1)
  307. AlBeRtEiNsTeIn
  308. echo unbundling bpatch.c 1>&2
  309. cat >bpatch.c <<'AlBeRtEiNsTeIn'
  310. /*T bpatch - A binary file patch/dump utility */
  311. /*S Introduction */
  312. /*F bpatch ***********************************************************
  313. * bpatch
  314. * by Garry M Johnson - 09/17/84
  315. * (C) Copyright 1984, 1985
  316. *
  317. * Change History:
  318. *
  319. * 11/29/87 - PORT TO 80286 SYSTEM (MICROPORT SYSV/AT, 2.2)
  320. * -> sorted out nonportable int -ne char *  and int -ne long (ever-
  321. * annoying problems for the 286); the changes should not have broken 
  322. * the code for 32-bit int -eq char *  machines; indeed, some of the 
  323. * changes fix apparently broken code
  324. * -> calls to outstr() now pass only a string address; where values are to 
  325. * be displayed, they are entered into the string with a prior 
  326. * sprintf(); 
  327. * -> calls to errmsg() handled as for outstr(), except there is a second 
  328. * parameter, "sleep_time", to specify the length of a sleep after message 
  329. * display; this is *not* implemented; call of sleep dumps core -- signal 
  330. * handling problem??
  331. * -> after "windowed" is set, forced all exit()'s into passing first 
  332. * through reset() and likewise everywhere follow reset() with immediate 
  333. * exit()
  334. * -> in the segment following "not interactive - keep dumping ...",
  335. * repaired broken code that controlled flow for the -d and -D options;
  336. * allow DEL interrupt of continuous dump of long file, in order to 
  337. * quit or go to next file
  338. * -> in reset(), ioctl'd terminal to be as at entry
  339. * -> in arrow(), added vi-like cursor control
  340. * -> cleaned up code for formats where specification did not agree with
  341. * declared type for variable; same for function parameter lists; checked 
  342. * casts and conversions to/from long; miscellaneous general cleanup 
  343. * of the code
  344. * -> cleaned up the display, but lots left to be done
  345. * REMAINING MINOR BUGS AND INFELICITIES AND WISH LIST --
  346. * -> spawn a properly working interactive shell; probably just need 
  347. * a fork and a full reset() under "!" option
  348. * -> easy repeat of string search to find next occurrence; highlight 
  349. * string positions in the display; put edit cursor at start of string
  350. * -> in debug mode, allow backspace over command entered, to cancel it
  351. * -> errmsg() display not nice, if have several messages output in
  352. * sequence; no pause in errmsg() (sleep not working?)
  353. * -> column under pointer not always erased (local clrtoeol problem ??)
  354. * -> irregular passing of pointers to record and related arrays
  355. * -> most of the external vars should be local to main()
  356. * -> signal handling?
  357. * -> file closing?
  358. * COMMENTS --
  359. * -> thanks to Steven List and Garry Johnson for a very useful program;
  360. * it's a nice way for one who is lazy to avoid a lot of compilation 
  361. * when what is wanted is a small change in data; the code is easy to 
  362. * read -- again compliments to the authors;
  363. * -> these modifications are hacks of the previous authors' code; the 
  364. * modified program has not been hardened, although I tried to check 
  365. * its operation under limit conditions; please be careful in using it
  366. * -> like the authors, I would appreciate receiving a copy of any 
  367. * improvements
  368. * John Rupley, Dept. Biochemistry, Univ. Arizona, Tucson, AZ 85721
  369. * {ihnp4 | hao!noao}!arizona!rupley!local or rupley!local@megaron.arizona.edu
  370. *
  371. ******************************************************************************
  372. *
  373. *  03/05/86 - added further terminal independence
  374. *          added use of ioctl (see main and mstdin)
  375. *          added -D versus -d command line option
  376. *          added use of standard getopt
  377. *          cleaned up code, eliminated function "ikf"
  378. *          added original versions of ezlib functions, such as
  379. *        icc, setterm, cm, mstdin, erase, length, move
  380. *          added ^R, ^Q, ^N, and ^P commands
  381. *          added ^F, !, and ^X (-X) commands
  382. *              changed name to "bpatch"
  383. *              added direct address command (g)
  384. *          added ASCII search capability
  385. *  07/07/86 - converted to use curses
  386. *          modified direct addressing to use suffixes
  387. *          updated HELP function
  388. *
  389. *   Steven List @ Benetics Corporation, Mt. View, CA
  390. *   {cdp,engfocus,idi,oliveb,plx,tolerant}!bene!luke!itkin
  391. *********************************************************************/
  392. /*E*/
  393. /*S includes, globals, and defines */
  394. /*Page Eject*/
  395. #include    <curses.h>
  396. #include <fcntl.h>
  397. #include <signal.h>
  398. #include <ctype.h>
  399. #include <sys/types.h>
  400. #include <sys/stat.h>
  401.  
  402. static int pbrk = 0;
  403. struct stat sb;
  404.  
  405. void icc ();
  406. void copyrec ();
  407. void schwapp ();
  408.  
  409. /* added declarations, mostly for cleanliness */
  410. extern long lseek();
  411. extern long atol();
  412. extern char *strncpy();
  413. extern void exit();
  414. extern unsigned sleep();    /* signal problems ??? if sleep called */
  415. extern void perror();
  416.  
  417. /* set up for calls to outstr and errmsg, etc, */
  418. /* by use of sprintf to fill outbuf */
  419. char outbuf[512];
  420.  
  421.     /* ------------------------------------------------------------ */
  422.     /* Some defines added by the moderator to get it work on 4.2     */
  423.     /* ------------------------------------------------------------ */
  424. #ifdef    MOD_HAX
  425.     /* Fifos?  We ain't got no steenkin' fifos. */
  426. /*    #define S_IFIFO        123450    */
  427.     /* "Spelling differences." */
  428. #define beep()        fprintf (stderr, "\007")
  429. /*    #define cbreak()    crmode()    */
  430.     /* Our curses doesn't translate keypad keys to single characters.    */
  431. #define keypad(a, b)        /*    null    */    /* orig defines */
  432. #define KEY_UP        '\0'    /*    '^'    */    /* by MOD_HAX    */
  433. #define KEY_DOWN    '\0'    /*    'v'    */    /* not portable    */
  434. #define KEY_LEFT    '\0'    /*    '<'    */
  435. #define KEY_RIGHT    '\0'    /*    '>'    */
  436. #define KEY_HOME    '\0'    /*    '@'    */
  437. #endif    /* MOD_HAX */
  438.  
  439. /* vi-like cursor control = vi keys, as control characters */
  440. /* this is a hack, and I hope does not interfere with keypad() */
  441. #define VI_UP        ('K' - 0x40)
  442. #define VI_DOWN        ('J' - 0x40)
  443. #define VI_LEFT        ('H' - 0x40)
  444. #define VI_RIGHT    ('L' - 0x40)
  445. #define VI_HOME        ('G' - 0x40)
  446.  
  447. #define SLEEP_TIME    (unsigned )0    /* a small pause after errmsg */
  448.                     /* does not work -- signals?? */
  449.     /* ------------------------------------------------------------ */
  450.     /* Some convenient defines                     */
  451.     /* ------------------------------------------------------------ */
  452.  
  453. #define DEL '\177'
  454. #define HEX 1
  455. #define ALPHA 0
  456.  
  457.     /* ------------------------------------------------------------ */
  458.     /* general purpose identification and control variables         */
  459.     /* ------------------------------------------------------------ */
  460.  
  461. char    filename[64];        /* current file being examined        */
  462. char    record[16][16];        /* record (page) buffer            */
  463. char    unch_rec[16][16];    /* record before any changes        */
  464. int     zp;            /* current input character        */
  465.  
  466. int        block = 0;    /* block size if -b in command        */
  467. int        block_spec;    /* true if file is block special    */
  468. int        bytes = 0;    /* number of bytes from last read    */
  469. int        char_spec;    /* true if file is char special        */
  470. int        debug = 0;    /* true if debug is turned on        */
  471. int        dir_spec;    /* true if file is directory        */
  472. int        dump = 0;    /* nonzero if dump instead of change    */
  473. int        Dump = 0;    /* store of value with -D option    */
  474. int        ebcdic = 0;    /* true if -e option            */
  475. int        fifo_spec;    /* true if file is fifo            */
  476. int        honly = 0;    /* true if dump is to be hex only    */
  477. int        mod = 0;    /* true if record has been modified    */
  478. int        pause_opt = 0;    /* true if -p option            */
  479. int        rawfile = 0;    /* true if file is c/b/p        */
  480. int        reclen = 0;    /* record length, if -r            */
  481. int        recno = 0;    /* current record (page) number        */
  482. int        stay = 0;    /* true if no position change         */
  483. int        swab_opt = 0;    /* true if byte swapping is on        */
  484. int        windowed = 0;    /* true if windowing - not dump        */
  485.  
  486. long    position = 0;        /* byte address in file            */
  487.  
  488. WINDOW *hexwin = NULL;
  489. WINDOW *alphawin = NULL;
  490. WINDOW *errwin = NULL;
  491.  
  492. #ifdef    MOD_HAX
  493. #else    /* use original code... */
  494.     /* plus some more for restoring terminal function */
  495.     struct termio asis, aswas;
  496. #endif    /* MOD_HAX */
  497.  
  498. /*S main - control all the work from here */
  499. /*H main *************************************************************
  500. *
  501. *                 main
  502. *
  503. *    set up the globals, initilize the state, and process the file
  504. *
  505. *********************************************************************/
  506. /*E*/
  507. main (argc, argv)
  508. int argc;
  509. char *argv[];
  510. {
  511.     extern WINDOW *subwin ();
  512.     extern WINDOW *newwin ();
  513.  
  514.     register char    *cp;        /* general purpose char ptr    */
  515.     extern   char    *gets ();    /* get string from stdin    */
  516.           char    m = '\017';    /* mask for hex edit        */
  517.           char    response[512];    /* general purpose buffer    */
  518.           int     z;        /* character read in        */
  519.      
  520.     int        breakp ();    /* signal trapping function    */
  521.     int        c;        /* current screen column    */
  522.     int        change = 0;    /* true if cmd line option toggled */
  523.     int        fid;        /* file descriptor         */
  524.     int        firstfile;    /* arg # of first file in cmd line */
  525.     int        h;        /* temp for hex edit        */
  526.     int        i;        /* general purpose loop index    */
  527.     int        j;        /* general purpose loop index    */
  528.     int        r;        /* current screen row        */
  529.     int        hexc;        /* current cursor column in hexwin */
  530.  
  531.     long    byteaddr;        /* planned byte address for 'G'    */
  532.     long    size;            /* file size in bytes        */
  533.     long    status;            /* EOF if at end of file or error */
  534.  
  535.     extern int optind;        /* getopt index into argv    */
  536.     extern char *optarg;        /* getopt pointer to opt arg    */
  537.  
  538.     extern long getnum ();
  539.     extern char *instr ();        /* get a string from the cmd line */
  540.     extern int reset ();        /* exit function - reset terminal */
  541.  
  542.     /* ------------------------------------------------------------ */
  543.     /* set up signal handling                     */
  544.     /* ------------------------------------------------------------ */
  545.  
  546.     if (!dump) signal (SIGINT, breakp);
  547.  
  548.     signal (SIGTERM, reset);
  549.  
  550.     /* ------------------------------------------------------------ */
  551.     /* process command line arguments                 */
  552.     /* ------------------------------------------------------------ */
  553.  
  554.     while ((i = getopt (argc, argv, "r:dD:b:pxXse")) != EOF)
  555.     {
  556.         switch (i)
  557.         {
  558.             case    'b':    /* blocking            */
  559.                 block = atoi (optarg);
  560.                 if (block < 1 || block > 10240)
  561.                 {
  562.                     fprintf (stderr,
  563.                         "invalid block size: %d\n", block);
  564.                     exit (1);
  565.                 }
  566.                 break;
  567.             case    'd':    /* straight dump - no limit    */
  568.                 dump = -1;
  569.                 break;
  570.             case    'D':    /* dump - page count spec    */
  571.                 dump = atoi (optarg);
  572.                 Dump = dump;
  573.                 break;
  574.             case    'e':    /* file is ebcdic        */
  575.                 ebcdic = 1;
  576.                 break;
  577.             case    'p':    /* pause between pages - dump    */
  578.                 pause_opt = 1;
  579.                 break;
  580.             case    'r':    /* record length for dump    */
  581.                 reclen = atoi (optarg);
  582.                 break;
  583.             case    's':    /* byte swapping required    */
  584.                 swab_opt = 1;
  585.                 break;
  586.             case    'x':    /* hex dump only        */
  587.                 honly = 1;
  588.                 break;
  589.             case    'X':
  590.                 debug = 1;
  591.                 break;
  592.             default:    /* uhoh                */
  593.                 fprintf (stderr,
  594. "usage: bpatch [ -b blocksz ] [ -d<ump> ] [ -D pagecnt ] [ -e<bcdic> ]\n");
  595.                 fprintf (stderr,
  596. "           [ -p<ause> ] [ -r reclen ] [ -s<wap bytes> ] [ -x<only> ]\n");
  597.                 exit (1);
  598.         }
  599.     }
  600.  
  601.     /* ------------------------------------------------------------ */
  602.     /* check for valid combinations of options             */
  603.     /* ------------------------------------------------------------ */
  604.  
  605.     if ((honly || block || reclen || pause_opt ) && !dump)
  606.     {
  607.         fprintf (stderr, "-x|-b|-r|-p requires -d or -D\n");
  608.         exit (2);
  609.     }
  610.  
  611.     /* ------------------------------------------------------------ */
  612.     /* At least one file name must be specified on the cmd line     */
  613.     /* ------------------------------------------------------------ */
  614.  
  615.     if (optind == argc)
  616.     {
  617.         fprintf (stderr, "no file name(s) specified\n");
  618.         exit (2);
  619.     }
  620.  
  621.     /* ------------------------------------------------------------ */
  622.     /* set up the screen, if this is an interactive session         */
  623.     /* ------------------------------------------------------------ */
  624.  
  625.     if (!dump)
  626.     {
  627.         windowed = 1;
  628.         initscr ();
  629.         nonl ();
  630.         noecho ();
  631.         cbreak ();
  632.         keypad (stdscr, TRUE);
  633.         hexwin = subwin (stdscr, 16, 48, 4, 4);
  634.         keypad (hexwin, TRUE);
  635.         alphawin = subwin (stdscr, 16, 16, 4, 57);
  636.         keypad (alphawin, TRUE);
  637.         errwin = subwin (stdscr, 1, 80, 23, 0);
  638.  
  639. #ifdef    MOD_HAX
  640.         /* This is not exactly what the original code does,
  641.            but it's good enough.  -r$ */
  642.         raw();
  643. #else    /* use original code... */
  644.         ioctl (0, TCGETA, &asis);
  645.         aswas = asis;    /* save termio stuff for later restore */
  646.         asis.c_cc[VINTR] = '\0';
  647.         asis.c_iflag &= ~IXON;
  648.         asis.c_iflag &= ~IXOFF;
  649.         asis.c_iflag &= ~IXANY;
  650.         ioctl (0, TCSETA, &asis);
  651. #endif    /* MOD_HAX */
  652.     }
  653.  
  654.     /* ------------------------------------------------------------ */
  655.     /* save the first file's index for backing up later         */
  656.     /* ------------------------------------------------------------ */
  657.  
  658.     firstfile = optind;
  659.  
  660.     /* ------------------------------------------------------------ */
  661.     /* open the first file                          */
  662.     /* ------------------------------------------------------------ */
  663.  
  664.     for (fid = -1; fid < 0 && optind < argc;)
  665.     {
  666.         fid = ckfile (argv[optind], &size);
  667.         if (fid < 0) optind++;
  668.     }
  669.     if (fid < 0)
  670.     {
  671.         fprintf (stderr, "could not handle the file list\n");
  672.         reset (0);
  673.         exit (2);
  674.     }
  675.  
  676.     strncpy (filename, argv[optind], sizeof filename);
  677.  
  678.     if (block != 0)
  679.     {
  680.         size = -1;
  681.     }
  682.  
  683.     recno = 0;
  684.     stay = 0;
  685.     mod = 0;
  686.     status = 0;
  687.  
  688.     /* ------------------------------------------------------------ */
  689.     /* Until the user exits...                     */
  690.     /* ------------------------------------------------------------ */
  691.  
  692.     if (!dump) clear ();
  693.  
  694.     while (status != EOF)
  695.     {
  696.     /* ------------------------------------------------------------ */
  697.     /* change of location - read and display             */
  698.     /* ------------------------------------------------------------ */
  699.         if (stay == 0)
  700.         {
  701.             position = lseek (fid, ((long )recno) * 256, 0);
  702.  
  703.             if ((bytes = bread (fid, record, 256, block)) < 0)
  704.             {
  705.                 sprintf(outbuf, "error on reading file %s", filename);
  706.                 errmsg (outbuf, SLEEP_TIME);
  707.                 status = EOF;
  708.                 continue;
  709.             }
  710.             if (bytes > 0)
  711.             {
  712.                 if (swab_opt) schwapp (record, 256);
  713.  
  714.                 copyrec (record, unch_rec, sizeof record);
  715.  
  716.                 if (!dump) clear ();
  717.                 show (bytes, record, filename, size, recno,
  718.                         position, m,reclen, dump, ebcdic, swab_opt,
  719.                         block, honly);
  720.             }
  721.             mod = 0;
  722.         }
  723.     /* ------------------------------------------------------------ */
  724.     /* not interactive - keep dumping or open next file         */
  725.     /* ------------------------------------------------------------ */
  726.         /* major changes in control of flow */
  727.         /* first records of multiple-files now dump */
  728.         /* core is not dumped at end of filelist */
  729.         /* can break with DEL into a long dump */
  730.         if (dump)
  731.         {
  732.             if (dump > 0) dump--;
  733.             if ((dump < 0 && bytes == 0) || dump == 0)
  734.             {
  735.                 if (Dump) dump = Dump;
  736.                 if (optind == argc) status = EOF;
  737.                 else
  738.                 {
  739.                     close (fid);
  740.                     fid = -1;
  741.                     for (optind++; fid < 0 && optind < argc;)
  742.                     {
  743.                         fid = ckfile (argv[optind], &size);
  744.                         if (fid < 0) optind++;
  745.                     }
  746.                     if (fid < 0)
  747.                     {
  748.                         status = EOF;
  749.                         continue;
  750.                     }
  751.  
  752.                     strncpy (filename, argv[optind], sizeof filename);
  753.  
  754.                     if (block != 0)
  755.                     {
  756.                         size = -1;
  757.                     }
  758.                     recno = 0;
  759.                     stay = 0;
  760.                     status = lseek (fid, (long)0, 0);
  761.                 }
  762.             }
  763.             else
  764.             {
  765.                 ++recno;
  766.             }
  767.     /* ------------------------------------------------------------ */
  768.     /* if pause, beep and wait                     */
  769.     /* ------------------------------------------------------------ */
  770.             /* settings to bypass show() */
  771.             /* and go to read of next file */
  772.             /* if type DEL during file display */
  773.             if (status != EOF && (pause_opt || pbrk))
  774.             {
  775.                 if (pbrk)
  776.                 {
  777.                     bytes = 0;
  778.                     dump = -1;
  779.                     stay = 1;
  780.                 }
  781.                 pbrk = 0;
  782.                 fprintf (stderr, "\007");
  783.                 gets (response);
  784.  
  785.                 if (pbrk) status = EOF;
  786.             }
  787.  
  788.             continue;
  789.         }
  790.     /* ------------------------------------------------------------ */
  791.     /* if we got here, this is an interactive session         */
  792.     /* ------------------------------------------------------------ */
  793.         stay = 0;
  794.     /* ------------------------------------------------------------ */
  795.     /* get the user's command                     */
  796.     /* ------------------------------------------------------------ */
  797.         response[0] = EOF;
  798.         mvaddstr (22, 0, "> ");
  799.         clrtoeol ();
  800.         refresh ();
  801.         zp = getch ();
  802.  
  803.         if (debug && !dump)
  804.         {
  805.             /* cheap cleanup of errwin */
  806.             errmsg ("", SLEEP_TIME);
  807.             if (isascii (zp) && isprint (zp))
  808.             {
  809.                 sprintf (outbuf, "command entered is %c", (char )zp);
  810.                 errmsg (outbuf, 0);
  811.             }
  812.             else
  813.             {
  814.                 sprintf (outbuf, "command entered is ^%c (%#x)", (char )zp + '@', zp);
  815.                 errmsg (outbuf, 0);
  816.             }
  817.             getch ();
  818.         }
  819.  
  820.         /* assume normal ascii character sequence        */
  821.         if ((zp >= 'a') && (zp <= 'z'))
  822.             zp = zp - 0x20;
  823.     /* ------------------------------------------------------------ */
  824.     /* here we go - what does the user want?             */
  825.     /* ------------------------------------------------------------ */
  826.         refresh ();
  827.         errmsg ("", SLEEP_TIME);
  828.         switch (zp)
  829.         { 
  830.             case    '!':    /* shell escape    */
  831.                 echo ();
  832.                 move (23,0);
  833.                 clrtoeol ();
  834.                 addstr ("shell command: ");
  835.                 refresh ();
  836.                 getstr (response);
  837.                 clear ();
  838.                 nl ();
  839.                 system (response);
  840.                 noecho ();
  841.                 nonl ();
  842.                 move (23,0);
  843.                 standout ();
  844.                 addstr (" <Press any key> ");
  845.                 standend ();
  846.                 clrtoeol ();
  847.                 refresh ();
  848.                 getch ();
  849.                 break;
  850.  
  851.             case    '?':    /* HELP    */
  852.                 clear ();
  853.                 dbg_msg ("Help");
  854.                 dohelp ();
  855.                 break;
  856.  
  857.             case    '/':    /* search for a string */
  858.                 stay = 1;
  859.                 if (mod)
  860.                 {
  861.                     errmsg ("No write since last change", SLEEP_TIME);
  862.                 }
  863.                 else search (fid);
  864.                 break;
  865.  
  866.             case '-':    /* toggle options */
  867.                 zp = getch ();
  868.                 stay = 1;
  869.                 change = 0;
  870.                 switch (zp)
  871.                 {
  872.                     case 'a': /* ascii */
  873.                         if (ebcdic)
  874.                         {
  875.                             dbg_msg ("toggle to ascii");
  876.                             change = 1;
  877.                         }
  878.                         ebcdic = 0;
  879.                         break;
  880.  
  881.                     case 'e': /* ebcdic */
  882.                         if (ebcdic == 0)
  883.                         {
  884.                             dbg_msg ("toggle to ebcdic");
  885.                             change = 1;
  886.                         }
  887.                         ebcdic = 1;
  888.                         break;
  889.  
  890.                     case 's': /* swab */
  891.                         dbg_msg ("toggle byte swap");
  892.                         change = 1;
  893.                         schwapp (record, 256);
  894.                         swab_opt = !swab_opt;
  895.                         break;
  896.                 }
  897.                 if (change)
  898.                 {
  899.                     clear ();
  900.                     show (bytes, record, filename, size,
  901.                             recno, position, m,reclen, dump,
  902.                             ebcdic, swab_opt, block, honly);
  903.                 }
  904.  
  905.                 break;
  906.  
  907.             case '\022':    /* redraw screen (^R) */
  908.                 clear ();
  909.                 show (bytes, record, filename, size, recno,
  910.                       position, m, reclen, dump, ebcdic,
  911.                       swab_opt, block, honly);
  912.                 stay = 1;
  913.                 break;
  914.             
  915.             case    '\030':    /* toggle debug (^X) */
  916.                 debug = !debug;
  917.                 stay = 1;
  918.                 break;
  919.  
  920.             case    '\006':    /* new file (^F) */
  921.                 close (fid);
  922.                 fid = ckfile (cp = instr (), &size);
  923.                 if (fid < 0)
  924.                 {
  925.                     fid = ckfile (filename, &size);
  926.                 }
  927.                 else
  928.                 {
  929.                     strncpy (filename, cp, sizeof filename);
  930.                     stay = 0;
  931.                     recno = 0;
  932.                 }
  933.                 break;
  934.  
  935.             case    '\016':    /* next file (^N) */
  936.                 if (mod)
  937.                 {
  938.                     errmsg ("No write since last change", SLEEP_TIME);
  939.                     stay = 1;
  940.                 }
  941.                 else if (optind == (argc - 1))
  942.                 {
  943.                     errmsg ("No more files", SLEEP_TIME);
  944.                     stay = 1;
  945.                 }
  946.                 else
  947.                 {
  948.                     close (fid);
  949.                     for (fid = -1, optind++; fid < 0 && optind < argc;)
  950.                     {
  951.                         fid = ckfile (argv[optind], &size);
  952.                         if (fid < 0) optind++;
  953.                     }
  954.                     if (fid < 0)
  955.                     {
  956.                         errmsg ("could not handle the file list", SLEEP_TIME);
  957.                         reset (0);
  958.                         exit (0);
  959.                     }
  960.                     strncpy (filename, argv[optind], sizeof filename);
  961.                     stay = 0;
  962.                     recno = 0;
  963.                 }
  964.                 break;
  965.  
  966.             case    '\020':    /* prev file (^P) */
  967.                 if (mod)
  968.                 {
  969.                     errmsg ("No write since last change", SLEEP_TIME);
  970.                     stay = 1;
  971.                 }
  972.                 else if (optind == firstfile)
  973.                 {
  974.                     errmsg ("No previous file", SLEEP_TIME);
  975.                     stay = 1;
  976.                 }
  977.                 else
  978.                 {
  979.                     close (fid);
  980.                     for (fid = -1, optind--; fid < 0 && optind >= firstfile;)
  981.                     {
  982.                         fid = ckfile (argv[optind], &size);
  983.                         if (fid < 0) optind--;
  984.                     }
  985.                     if (fid < 0)
  986.                     {
  987.                         errmsg ("could not handle the file list", SLEEP_TIME);
  988.                         reset (0);
  989.                         exit (0);
  990.                     }
  991.                     strncpy (filename, argv[optind], sizeof filename);
  992.                     stay = 0;
  993.                     recno = 0;
  994.                 }
  995.                 break;
  996.  
  997.             case    '\021':    /* quit absolutely (^Q)    */
  998.                 status = EOF;
  999.                 break;
  1000.  
  1001.             case DEL:    /* quit with check */
  1002.             case 'Q':     /* quit */
  1003.                 if (mod)
  1004.                 {
  1005.                     errmsg ("No write since last change!", SLEEP_TIME);
  1006.                     stay = 1;
  1007.                 }
  1008.                 else
  1009.                 {
  1010.                     status = EOF;
  1011.                 }
  1012.                 break;
  1013.  
  1014.             case '\\':     /* back up 1 record */
  1015.                 if (mod)
  1016.                 {
  1017.                     errmsg ("No write since last change", SLEEP_TIME);
  1018.                     stay = 1;
  1019.                 }
  1020.                 else
  1021.                 {
  1022.                     if (recno > 0)
  1023.                     {
  1024.                         --recno;
  1025.                         stay = 0;
  1026.  
  1027.                         status = lseek (fid, ((long )recno) * 256, 0);
  1028.                         if (status < 0)
  1029.                         {
  1030.                             move (22, 0);
  1031.                             clrtoeol ();
  1032.                             perror (filename);
  1033.                             errmsg ("error positioning in file", SLEEP_TIME);
  1034.                             beep ();
  1035.                             ++recno;
  1036.                             stay = 1;
  1037.                         }
  1038.                     }
  1039.                     else
  1040.                     {
  1041.                         errmsg ("No previous records", SLEEP_TIME);
  1042.                         beep ();
  1043.                         stay = 1;
  1044.                     }
  1045.                 }
  1046.                 break; 
  1047.  
  1048.             case 'F':     /* go to first record */
  1049.                 if (mod)
  1050.                 {
  1051.                     errmsg ("No write since last change", SLEEP_TIME);
  1052.                     stay = 1;
  1053.                 }
  1054.                 else
  1055.                 {
  1056.                     status = lseek (fid, (long)0, 0);
  1057.                     recno = 0;
  1058.                 }
  1059.                 break;
  1060.  
  1061.             case 'L':     /* go to last record */
  1062.                 if (mod)
  1063.                 {
  1064.                     errmsg ("No write since last change", SLEEP_TIME);
  1065.                     stay = 1;
  1066.                 }
  1067.                 else
  1068.                 {
  1069.                     position = lseek (fid, (long)0, 2);
  1070.                     recno = position / 256;
  1071.                     j = position % 256;
  1072.                     if (j == 0) --recno;
  1073.                     status = lseek (fid, ((long )recno)*256, 0);
  1074.                 }
  1075.                 break;
  1076.  
  1077.             case 'U':    /* undo changes    */
  1078.                 stay = 1;
  1079.                 mod = 0;
  1080.                 copyrec (unch_rec, record, sizeof record);
  1081.                 clear ();
  1082.                 show (bytes, record, filename, size, recno,
  1083.                         position, m,reclen, dump, ebcdic, swab_opt,
  1084.                         block, honly);
  1085.                 break;
  1086.  
  1087.             case 'R':     /* re-read record */
  1088.                 status = lseek (fid, ((long )recno)*256, 0);
  1089.                 break;
  1090.  
  1091.             case '0':     /* go to some address */
  1092.             case '1':
  1093.             case '2':
  1094.             case '3':
  1095.             case '4':
  1096.             case '5':
  1097.             case '6':
  1098.             case '7':
  1099.             case '8':
  1100.             case '9':
  1101.                 if (mod)
  1102.                 {
  1103.                     errmsg ("No write since last change", SLEEP_TIME);
  1104.                     stay = 1;
  1105.                 }
  1106.                 else
  1107.                 {
  1108.                     byteaddr = getnum (zp, FALSE);
  1109.                     stay = 1;
  1110.                     sprintf (outbuf, "Position to byte %ld", byteaddr);
  1111.                     errmsg (outbuf, 0);
  1112.                     if (!rawfile && byteaddr > size)
  1113.                     {
  1114.                         errmsg ("Address outside file", SLEEP_TIME);
  1115.                         beep ();
  1116.                     }
  1117.                     else if ((int )(byteaddr / 256) != recno)
  1118.                     {
  1119.                         recno = byteaddr / 256;
  1120.                         status = lseek (fid, ((long )recno)*256, 0);
  1121.                         stay = 0;
  1122.                     }
  1123.                 }
  1124.                 break;
  1125.  
  1126.             case 'A':     /* alpha modify */
  1127.                 stay = 1;
  1128.                 r = c = 0;
  1129.                 dbg_msg ("edit ascii");
  1130.                 if (bytes == 0) break;
  1131.                 touchwin (stdscr);
  1132.                 refresh ();
  1133.                 wmove (alphawin, r, c);
  1134.                 touchwin (alphawin);
  1135.                 wrefresh (alphawin);
  1136.  
  1137.                 while ((z = wgetch (alphawin)) != DEL)
  1138.                 {
  1139.                     if (!arrow (z, &r, &c))
  1140.                     {
  1141.                         if (isascii (z))
  1142.                         {
  1143.                             if (isprint (z)) waddch (alphawin, z);
  1144.                             else        waddch (alphawin, '.');
  1145.  
  1146.                             if (ebcdic) icc (&z, 1,"AE");
  1147.  
  1148.                             record[r][c] = z;
  1149.                             mod = 1;
  1150.  
  1151.                             hexc = c * 3;
  1152.                             wmove (hexwin, r, hexc);
  1153.                             if (record[r][c] < '\0')
  1154.                             {
  1155.                                 wprintw (hexwin, "%x%x", (record[r][c] >> 4) & m, record[r][c] & m);
  1156.                             }
  1157.                             else
  1158.                             {
  1159.                                 wprintw (hexwin, "%02x", record[r][c]);
  1160.                             }
  1161.                             wrefresh (hexwin);
  1162.  
  1163.                         }
  1164.                         else
  1165.                         {
  1166.                             beep ();
  1167.                         }
  1168.  
  1169.                         if (c == 15)
  1170.                         {
  1171.                             if (r == 15) beep ();
  1172.                             else
  1173.                             {
  1174.                                 c = 0;
  1175.                                 ++r;
  1176.                             }
  1177.                         }
  1178.                         else
  1179.                         {
  1180.                             c++;
  1181.                         }
  1182.                     }
  1183.                     if (r * 16 + c >= bytes)
  1184.                     {
  1185.                         beep ();
  1186.                         r = (bytes - 1) / 16;
  1187.                         c = (bytes - 1) % 16;
  1188.                     }
  1189.  
  1190.                     wmove (alphawin, r, c);
  1191.                     wrefresh (alphawin);
  1192.                 }
  1193.  
  1194.                 break;
  1195.  
  1196.             case 'H':     /* hex modify */
  1197.                 dbg_msg ("edit hex");
  1198.                 stay = 1;
  1199.                 r = c = hexc = 0;
  1200.                 if (bytes == 0) break;
  1201.                 touchwin (stdscr);
  1202.                 refresh ();
  1203.                 wmove (hexwin, r, hexc);
  1204.                 touchwin (hexwin);
  1205.                 wrefresh (hexwin);
  1206.  
  1207.                 while ((z = wgetch (hexwin)) != DEL)
  1208.                 {
  1209.                     if (!arrow (z, &r, &c))
  1210.                     {
  1211.                         hexc = c * 3;
  1212.                         if ((z >= 'a') && (z <= 'z'))
  1213.                             z = z - 0x20;
  1214.                         if (!(((z >= '0') && (z <= '9')) || ((z >= 'A') && (z <= 'F'))))
  1215.                         {
  1216.                             beep ();
  1217.                         }
  1218.                         else
  1219.                         {
  1220.                             if (z >= 'A')
  1221.                                 waddch (hexwin, tolower (z));
  1222.                             else
  1223.                                 waddch (hexwin, z);
  1224.                             wrefresh (hexwin);
  1225.  
  1226.                             if (z > '9') z -= 7;
  1227.  
  1228.                             h = (z & m) << 4;
  1229.  
  1230.                             while (2)
  1231.                             {
  1232.                                 z = EOF;
  1233.                                 z = getch ();
  1234.                                 if (z == EOF)
  1235.                                 {
  1236.                                     pbrk = 0;
  1237.                                     h = -1;
  1238.                                     break;
  1239.                                 }
  1240.                                 if ((z >= 'a') && (z <= 'z'))
  1241.                                     z = z - 0x20;
  1242.                                 if (!(((z >= '0') && (z <= '9')) || ((z >= 'A') && (z <= 'F'))))
  1243.                                 {
  1244.                                     beep ();
  1245.                                 }
  1246.                                 else
  1247.                                 {
  1248.                                     if (z >= 'A')
  1249.                                          waddch (hexwin, tolower (z));
  1250.                                      else
  1251.                                          waddch (hexwin, z);
  1252.                                     wrefresh (hexwin);
  1253.                                     if (z > '9') z -= 7;
  1254.  
  1255.                                     h |= z & m;
  1256.                                     break;
  1257.                                 }
  1258.                             }
  1259.  
  1260.                             if (h < 0)
  1261.                             {
  1262.                                 wmove (hexwin, r, hexc);
  1263.                                 if (record[r][c] < '\0')
  1264.                                 {
  1265.                                     wprintw (hexwin, "%x%x",
  1266.                                         (record[r][c] >> 4) & m,
  1267.                                         record[r][c] & m);
  1268.                                 }
  1269.                                 else
  1270.                                 {
  1271.                                     wprintw (hexwin, "%02x", record[r][c]);
  1272.                                 }
  1273.                                 wrefresh (hexwin);
  1274.                                 break;
  1275.                             }
  1276.  
  1277.                             record[r][c] = z = h;
  1278.                             mod = 1;
  1279.  
  1280.                             if (ebcdic) icc (&z, 1,"EA");
  1281.  
  1282.                             wmove (alphawin, r, c);
  1283.                             if (isascii (z) && isprint (z))
  1284.                                 waddch (alphawin, z);
  1285.                             else waddch (alphawin, '.');
  1286.                             wrefresh (alphawin);
  1287.  
  1288.                             if (c == 15)
  1289.                             {
  1290.                                 if (r == 15) beep ();
  1291.                                 else
  1292.                                 {
  1293.                                     c = 0;
  1294.                                     ++r;
  1295.                                 }
  1296.                             }
  1297.                             else
  1298.                             {
  1299.                                 c++;
  1300.                             }
  1301.                         }
  1302.                     }
  1303.  
  1304.                     if (r * 16 + c >= bytes)
  1305.                     {
  1306.                         beep ();
  1307.                         r = (bytes - 1) / 16;
  1308.                         c = (bytes - 1) % 16;
  1309.                     }
  1310.  
  1311.                     hexc = c * 3;
  1312.                     wmove (hexwin, r, hexc);
  1313.                     wrefresh (hexwin);
  1314.                 }
  1315.                 break;
  1316.  
  1317.             case 'W':     /* write record */
  1318.                 stay = 1;
  1319.                 status = lseek (fid, position, 0);
  1320.                 if (status != position)
  1321.                 {
  1322.                     move (22, 0);
  1323.                     clrtoeol ();
  1324.                     perror (filename);
  1325.                     errmsg ("error positioning in file", SLEEP_TIME);
  1326.                     beep ();
  1327.                 }
  1328.                 if (swab_opt) schwapp (record, 256);
  1329.                 if (write (fid, record, bytes) != bytes)
  1330.                 {
  1331.                     errmsg ("error writing to file", SLEEP_TIME);
  1332.                     reset (0);
  1333.                     exit (0);
  1334.                 }
  1335.                 if (swab_opt) schwapp (record, 256);
  1336.                 mod = 0;
  1337.                 errmsg ("Record written", SLEEP_TIME);
  1338.                 break;
  1339.  
  1340.             case    '\n':    /* newline - next page    */
  1341.             case    '\r':
  1342.                 if (mod)
  1343.                 {
  1344.                     errmsg ("No write since last change", SLEEP_TIME);
  1345.                     stay = 1;
  1346.                 }
  1347.                 else
  1348.                 {
  1349.                     ++recno;
  1350.                     if (!rawfile && (((long )recno) * 256) >= size)
  1351.                     {
  1352.                         recno--;
  1353.                         beep ();
  1354.                         errmsg ("No more records in file", SLEEP_TIME);
  1355.                         stay = 1;
  1356.                     }
  1357.                     else stay = 0;
  1358.                 }
  1359.                 break;
  1360.  
  1361.             default:
  1362.                 if (isascii (zp) && isprint (zp))
  1363.                 {
  1364.                     sprintf (outbuf, "Unknown command: %d", zp);
  1365.                     errmsg (outbuf, 0);
  1366.                 }
  1367.                 else
  1368.                 {
  1369.                     sprintf (outbuf, "Unknown command: %d", zp + '@');
  1370.                     errmsg (outbuf, 0);
  1371.                 }
  1372.                 beep ();
  1373.                 stay = 1;
  1374.                 break;
  1375.         }     /* end switch zp */
  1376.         refresh ();
  1377.     }
  1378.  
  1379.     reset (0);
  1380.     if (fid > 0) return (close (fid));
  1381.     else return (0);
  1382. }
  1383. /*S show - display a record on the terminal */
  1384. /*H show */
  1385. /*E*/
  1386. /*checked typing of parameters as declared in fucntion */
  1387. /* versus declarations at call */
  1388. show (bytes, record, filename, size, recno, position,
  1389.       m,reclen, dump, ebcdic, swab_opt, block, honly)
  1390. int bytes;
  1391. char record[16][16];
  1392. char *filename;
  1393. long size;
  1394. int recno;
  1395. long position;
  1396. char m;
  1397. int reclen;
  1398. int dump;
  1399. int ebcdic;
  1400. int swab_opt;
  1401. int block;
  1402. int honly;
  1403. {
  1404.     int        i;
  1405.     int        j;
  1406.     char    s;
  1407.     char    temp[16];
  1408.     char    *look = NULL;
  1409.  
  1410.     int        row = 0;
  1411.     int        col = 0;
  1412.  
  1413.     if (dump)
  1414.         printf ("\n\n");
  1415.     if (!dump)
  1416.         move (0, 0);
  1417.     sprintf (outbuf, "FILE: %s ", filename);
  1418.     outstr (outbuf);
  1419.     if (block_spec) outstr ("(block special)");
  1420.     else if (char_spec) outstr ("(character special)");
  1421.     else if (fifo_spec) outstr ("(fifo (named pipe))");
  1422.     else if (dir_spec)
  1423.     {
  1424.         sprintf (outbuf, "(directory - %ld)", size);
  1425.         outstr (outbuf);
  1426.     }
  1427.     else 
  1428.     {
  1429.         sprintf (outbuf, "(%ld)", size);
  1430.         outstr (outbuf);
  1431.     }
  1432.     if (ebcdic) outstr (" - EBCDIC");
  1433.     else outstr (" - ASCII");
  1434.     if (swab_opt) outstr (" - SWAP");
  1435.     if (block) 
  1436.     {
  1437.         sprintf (outbuf, " - BLOCK (%d)", block);
  1438.         outstr (outbuf);
  1439.     }
  1440.     if (reclen) 
  1441.     {
  1442.         sprintf (outbuf, " - RECORD (%d)", reclen);
  1443.         outstr (outbuf);
  1444.     }
  1445.     if (!dump)
  1446.     {
  1447.         clrtoeol ();
  1448.         move (1,0);
  1449.         printw ("PAGE: %d (%ld)", recno, position);
  1450.         clrtoeol ();
  1451.         row = 2;
  1452.     }
  1453.     else
  1454.     {
  1455.         printf ("\nPAGE: %d (%ld)\n", recno, position);
  1456.     }
  1457.  
  1458.     if (honly)
  1459.     {
  1460.         look = (char *) record;
  1461.         for (j=0;j<256;++j)
  1462.         {
  1463.             if (*look++ != '\0')
  1464.             {
  1465.                 look = NULL;
  1466.                 break;
  1467.             }
  1468.         }
  1469.     }
  1470.  
  1471.     if (!dump) move (row, col);
  1472.  
  1473.     outstr ("    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf");
  1474.     outstr ("    0123456789abcdef");
  1475.  
  1476.     if (!dump)
  1477.     {
  1478.         row += 2;
  1479.         move (row, col);
  1480.     }
  1481.     else
  1482.     {
  1483.         printf ("\n\n");
  1484.     }
  1485.     for (i=0; i<=bytes/16; ++i)
  1486.     {
  1487.         if (honly && look != NULL)
  1488.         {
  1489.             i = 16;
  1490.             continue;
  1491.         }
  1492.          if (i*16+1 > bytes)
  1493.          {
  1494.             if (!dump) move (++row, 0);
  1495.              continue;
  1496.          }
  1497.  
  1498.         sprintf (outbuf, "%02x: ", i);
  1499.         outstr (outbuf);
  1500.  
  1501.         for (j=0; j<16; ++j)
  1502.         {
  1503.             if (i*16+j < bytes)
  1504.             {
  1505.                 if (record[i][j] < '\0')
  1506.                 {
  1507.                     sprintf (outbuf, "%x%x ",
  1508.                         (record[i][j] >> 4) & m, record[i][j] & m);
  1509.                     outstr (outbuf);
  1510.                 }
  1511.                 else
  1512.                 {
  1513.                     sprintf (outbuf, "%02x ", record[i][j]);
  1514.                     outstr (outbuf);
  1515.                 }
  1516.                 s = ' ';
  1517.                 if (reclen > 0 && (position+i*16+j+1)%reclen == 0)
  1518.                     s = ':';
  1519.                 if (block > 0 && (position+i*16+j+1)%block == 0)
  1520.                 {
  1521.                     if (s == ' ')
  1522.                         s = '/';
  1523.                     else
  1524.                         s = '%';
  1525.                 }
  1526.                 if (s != ' ')
  1527.                 {
  1528.                     sprintf (outbuf, "\b%c", s);
  1529.                     outstr (outbuf);
  1530.                 }
  1531.             }
  1532.             else
  1533.             {
  1534.                 outstr ("   "); /* set at 3 spaces */
  1535.             }
  1536.         }
  1537.  
  1538.         outstr ("     ");    /* set at tab + 1 space */
  1539.  
  1540.         copyrec (record[i], temp, 16);
  1541.  
  1542.         if (ebcdic) icc (temp, 16, "EA");
  1543.  
  1544.         for (j = 0; j < 16 && i*16+j < bytes; ++j)
  1545.         {
  1546.             if (temp[j] < ' ') outch ('.');
  1547.             else
  1548.             {
  1549.                 sprintf (outbuf, "%c", temp[j]);
  1550.                 outstr (outbuf);
  1551.             }
  1552.         }
  1553.  
  1554.         if (!dump)
  1555.         {
  1556.             move (++row, col);
  1557.         }
  1558.         else
  1559.         {
  1560.             printf ("\n");
  1561.         }
  1562.     }
  1563.  
  1564.     /* moved debug output so it would display + other related changes */
  1565.     if (!dump) clrtobot ();
  1566.     if (debug && !dump)
  1567.     {
  1568.         getyx (stdscr, row, col);
  1569.         move (23,0);
  1570.         printw ("show: %d|%ld|%s|%ld|%d|%ld|%#x|%d|%d|%d|%d|%d|%d",
  1571.             bytes, record, filename, size, recno, position,
  1572.             m, reclen, dump, ebcdic, swab_opt, block, honly);
  1573.         move (row, col);
  1574.     }
  1575.     if (!dump) 
  1576.     {
  1577.         touchwin (stdscr);
  1578.         refresh ();
  1579.     }
  1580.     
  1581.     return;
  1582. }
  1583. /*S breakp - set pbrk on interrupt */
  1584. /*H breakp */
  1585. /*E*/
  1586. int breakp (i)
  1587. int i;
  1588. {
  1589.     int s;
  1590.     extern int pbrk;
  1591.     s = (int) signal (SIGINT, breakp);
  1592.     pbrk = i;
  1593. }
  1594. /*S bread - buffered read */
  1595. /*H bread */
  1596. /*E*/
  1597. int bread (fid, record, want, block)
  1598. int fid, want, block;
  1599. char *record;
  1600. {
  1601.     int i, j, k;
  1602.     int what, bytes, orig;
  1603.     static char buffer[10240];
  1604.     static int left, xarrow;
  1605.     static int flag = 1;
  1606.  
  1607.     if (flag)
  1608.     {
  1609.         left = 0;
  1610.         xarrow = 0;
  1611.         flag = 0;
  1612.     }
  1613.  
  1614.     if (block == 0)
  1615.         return (read (fid, record, want));
  1616.  
  1617.     if (block & 1) ++block;
  1618.  
  1619.     orig = what = want;
  1620.     while (1)
  1621.     {
  1622.         if (left < want)
  1623.         {
  1624.             if (left)
  1625.             {
  1626.                 copyrec (&buffer[xarrow], record, left);
  1627.                 record += left;
  1628.                 want -= left;
  1629.             }
  1630.  
  1631.             xarrow = 0;
  1632.             left = 0;
  1633.  
  1634.             if ((bytes = read (fid, buffer, block)) < 0)
  1635.             {
  1636.                 what = bytes;
  1637.                 break;
  1638.             }
  1639.  
  1640.             if (bytes == 0)
  1641.             {
  1642.                 what = orig - want;
  1643.                 break;
  1644.             }
  1645.  
  1646.             left = bytes;
  1647.         }
  1648.         else
  1649.         {
  1650.             copyrec (&buffer[xarrow], record, want);
  1651.             xarrow += want;
  1652.             left -= want;
  1653.             break;
  1654.         }
  1655.     }
  1656.  
  1657.     return (what);
  1658. }
  1659. /*S schwapp - swap bytes in place */
  1660. /*H schwapp */
  1661. /*E*/
  1662. void
  1663. schwapp (ptr, nch)
  1664. register char *ptr;
  1665. register int nch;
  1666. {
  1667.     register int i;
  1668.     register char c;
  1669.     register char *ptra = ptr + 1;
  1670.  
  1671.     if (nch & 1) --nch;
  1672.  
  1673.     for (i = 0; i < nch; i += 2, ptr += 2, ptra += 2)
  1674.     {
  1675.         c = *ptr;
  1676.         *ptr = *ptra;
  1677.         *ptra = c;
  1678.     }
  1679.     return;
  1680. }
  1681. /*S copyrec - transfer bytes from f to t for nbytes bytes */
  1682. /*H copyrec */
  1683. /*E*/
  1684. void
  1685. copyrec (f, t, nbytes)
  1686. register char *f;
  1687. register char *t;
  1688. register int nbytes;
  1689. {
  1690.     register int i;
  1691.  
  1692.     for (i = 0; i < nbytes; i++, f++, t++) *t = *f;
  1693.  
  1694.     return;
  1695. }
  1696. /*S ebcdic codes corresponding to ascii - translation table */
  1697. /*Page Eject*/
  1698. char xebcdic_codes[] = {
  1699. 0, 0x1, 0x2, 0x3, 0x37, 0x2d, 0x2e, 0x2f, 0x16,
  1700. 0x5, 0x25, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11,
  1701. 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f,
  1702. 0x27, 0x1c, 0x1d, 0x1e, 0x1f, 0x40, 0x5a, 0x7f, 0x7b,
  1703. 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b,
  1704. 0x60, 0x4b, 0x61, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
  1705. 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e,
  1706. 0x6f, 0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
  1707. 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
  1708. 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
  1709. 0xe9, 0xad, 0xe0, 0xbd, 0x9a, 0x6d, 0x79, 0x81, 0x82,
  1710. 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92,
  1711. 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0xa2, 0xa3,
  1712. 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0,
  1713. 0x5f, 0x7 };
  1714. /*S icc - internal code conversion */
  1715. /*H icc */
  1716. /*E*/
  1717. void
  1718. icc (buf, nch, type)
  1719. register char *buf;
  1720. register int nch;
  1721. char *type;
  1722. {
  1723.     register int i;
  1724.     register int j;
  1725.  
  1726.     if (!strcmp (type, "AE"))
  1727.     {
  1728.         for (i = 0; i < nch; i++, buf++)
  1729.         {
  1730.             *buf = xebcdic_codes[*buf];
  1731.         }
  1732.     }
  1733.     else if (!strcmp (type, "EA"))
  1734.     {
  1735.         for (i = 0; i < nch; i++, buf++)
  1736.         {
  1737.             for (j = 0; j < 128; j++)
  1738.             {
  1739.                 if (*buf == xebcdic_codes[j])
  1740.                 {
  1741.                     *buf = j;
  1742.                     break;
  1743.                 }
  1744.             }
  1745.         }
  1746.     }
  1747.  
  1748.     return;
  1749. }
  1750. /*S ckfile - check on existence, accessibility, and type of file */
  1751. /*H ckfile */
  1752. /*E*/
  1753. ckfile (filename, sizep)
  1754. char    *filename;
  1755. long    *sizep;
  1756. {
  1757.     register int fid = 0;
  1758.  
  1759.     if (access (filename, 0) < 0)
  1760.     {
  1761.         sprintf (outbuf, "file not found (%s)", filename);
  1762.         errmsg (outbuf, SLEEP_TIME);
  1763.         fid = -1;
  1764.     }
  1765.  
  1766.     if (block || pause_opt || dump)
  1767.     {
  1768.         fid = open (filename, O_RDONLY, 0);
  1769.     }
  1770.     else
  1771.     {
  1772.         fid = open (filename, O_RDWR, 0);
  1773.     }
  1774.  
  1775.     if (fid < 0)
  1776.     {
  1777.         sprintf (outbuf, "error opening file %s", filename);
  1778.         errmsg (outbuf, SLEEP_TIME);
  1779.         perror (filename);
  1780.         fid = -1;
  1781.     }
  1782.     else
  1783.     {
  1784.         sprintf (outbuf, "File %s opened successfully ", filename);
  1785.         errmsg (outbuf, 0);
  1786.         if (fstat (fid, &sb) == -1)
  1787.         {
  1788.             fprintf (stderr, "Can't stat\n");
  1789.             perror (filename);
  1790.             fid = -1;
  1791.         }
  1792.         else
  1793.         {
  1794.             block_spec = (sb.st_mode & S_IFMT) == S_IFBLK;
  1795.             char_spec = (sb.st_mode & S_IFMT) == S_IFCHR;
  1796.             fifo_spec = (sb.st_mode & S_IFMT) == S_IFIFO;
  1797.             dir_spec = (sb.st_mode & S_IFMT) == S_IFDIR;
  1798.             rawfile = block_spec || char_spec || fifo_spec;
  1799.  
  1800.             if (rawfile) *sizep = -1;
  1801.             else
  1802.             {
  1803.                 if (sb.st_size == 0)
  1804.                 {
  1805.                     fprintf (stderr,
  1806.                         "file %s is empty (zero bytes)\n",
  1807.                         filename);
  1808.                     fid = -1;
  1809.                 }
  1810.                 *sizep = sb.st_size;
  1811.             }
  1812.         }
  1813.     }
  1814.  
  1815.     return fid;
  1816. }
  1817. /*S dohelp - display help text */
  1818. /*H dohelp */
  1819. /*E*/
  1820. dohelp ()
  1821. {
  1822.     static char *helptxt[] = {
  1823.     "?    - display this help text",    "h   - edit hexadecimal portion",
  1824.     "!    - execute command in the shell",    "a   - edit ascii portion",
  1825.     "q,DEL - quit the program",        "DEL - exit edit->command mode",
  1826.     "^q   - quit without writing changes",    NULL,
  1827.     "-x   - toggle command line option",    "f   - display first page of file",
  1828.     "       ({a|e}->{e|a}, s->!s)",        "l   - display last page of file",
  1829.     "<cr> - display next page",        NULL,
  1830.     "\\    - display previous page",    "nnn - direct addressing",
  1831.     "/    - search for ASCII string",     NULL,
  1832.     "^f   - select named file",        "r   - reread the current page",
  1833.     "^n   - select next file",        "u   - undo all changes to page",
  1834.     "^p   - select previous file",        "w   - write out changed page",
  1835.     "^r   - redraw the screen",        NULL,
  1836.     "^x   - turn on debug",            NULL,
  1837.     "----------------------------------------------------------------", NULL,
  1838.     "direct addressing: nnnS, where nnn = some number, and", NULL,
  1839.     "            S = type suffix", "b = block (512)",
  1840.     NULL, "k = kilobyte (1024)",
  1841.     NULL, "l = long word (4)",
  1842.     NULL, "p = page (256)",
  1843.     NULL, "w = word (2)",
  1844.     NULL, "<cr> = byte",
  1845.     };
  1846.  
  1847.     static int nmsg = sizeof helptxt / sizeof (char *);
  1848.     register int row = 0;
  1849.     register int i;
  1850.  
  1851.     register WINDOW *helpwin;
  1852.     extern WINDOW *newwin ();
  1853.  
  1854.     helpwin = newwin (LINES, COLS, 0, 0);
  1855.     wclear (helpwin);
  1856.  
  1857.     wrefresh (helpwin);
  1858.  
  1859.     wmove (helpwin, 0, 1);
  1860.     waddstr (helpwin,
  1861. "---------------------------------- HELP ----------------------------------");
  1862.  
  1863.     for (row = 1, i = 0; i < nmsg; i+=2)
  1864.     {
  1865.         if (helptxt[i])
  1866.         {
  1867.             wmove (helpwin, row, 1);
  1868.             waddstr (helpwin, helptxt[i]);
  1869.         }
  1870.         if (i+1 <= nmsg && helptxt[i+1])
  1871.         {
  1872.             wmove (helpwin, row, 41);
  1873.             waddstr (helpwin, helptxt[i+1]);
  1874.         }
  1875.         row++;
  1876.     }
  1877.  
  1878.     wmove (helpwin, 23, 0);
  1879.     wstandout (helpwin);
  1880.     waddstr (helpwin, " <Press any key> ");
  1881.     wstandend (helpwin);
  1882.     wclrtoeol (helpwin);
  1883.     wrefresh (helpwin);
  1884.     wgetch (helpwin);
  1885.     /*
  1886.     wclear (helpwin);
  1887.     wmove (helpwin, 0, 0);
  1888.     wrefresh (helpwin);
  1889.     */
  1890.     delwin (helpwin);
  1891.  
  1892.     return;
  1893. }
  1894. /*S reset - reset terminal to original state */
  1895. /*H reset */
  1896. /*E*/
  1897. reset (sig)
  1898. int sig;
  1899. {
  1900.     if (windowed)
  1901.     {
  1902.         move (23, 0);
  1903.         refresh ();
  1904. #ifndef MOD_HAX
  1905.         ioctl (0, TCSETA, &aswas);
  1906. #endif
  1907.         endwin ();
  1908.     }
  1909.     fprintf (stderr, "\n");
  1910.     if (sig)
  1911.     {
  1912.         fprintf (stderr, "killed with signal %d\n", sig);
  1913.         exit (sig);
  1914.     }
  1915.     return (0);
  1916. }
  1917. /*S arrow - determine if current character is a cursor control key */
  1918. /*H arrow */
  1919. /*E*/
  1920. arrow (k, r, c)
  1921. register int k;
  1922. register int *r;
  1923. register int *c;
  1924. {
  1925.     register ret = 1;
  1926.  
  1927.     /* watch out for conflict of VI_* amd KEY_* definitions */
  1928.     if (k == KEY_UP || k == VI_UP)
  1929.     {
  1930.         if (*r == 0) beep ();
  1931.         else (*r)--;
  1932.     }
  1933.     else if (k == KEY_DOWN || k == VI_DOWN)
  1934.     {
  1935.         if (*r == 15) beep ();
  1936.         else (*r)++;
  1937.     }
  1938.     else if (k == KEY_LEFT || k == VI_LEFT)
  1939.     {
  1940.         if (*c == 0)
  1941.         {
  1942.             if (*r == 0) beep ();
  1943.             else
  1944.             {
  1945.                 *c = 15;
  1946.                 (*r)--;
  1947.             }
  1948.         }
  1949.         else (*c)--;
  1950.     }
  1951.     else if (k == KEY_RIGHT || k == VI_RIGHT)
  1952.     {
  1953.         if (*c == 15)
  1954.         {
  1955.             if (*r == 15) beep ();
  1956.             else
  1957.             {
  1958.                 *c = 0;
  1959.                 (*r)++;
  1960.             }
  1961.         }
  1962.         else (*c)++;
  1963.     }
  1964.     else if (k == KEY_HOME || k == VI_HOME)
  1965.     {
  1966.         *r = *c = 0;
  1967.     }
  1968.     else
  1969.     {
  1970.         ret = 0;
  1971.     }
  1972.  
  1973.     return ret;
  1974. }
  1975. /*S dbg_msg - print a debug message */
  1976. /*H dbg_msg */
  1977. /*E*/
  1978. dbg_msg (msg)
  1979. register char *msg;
  1980. {
  1981.     if (debug && !dump)
  1982.     {
  1983.         errmsg (msg, SLEEP_TIME);
  1984.     }
  1985.  
  1986.     return;
  1987. }
  1988. /*S instr - get a character string from the terminal */
  1989. /*H instr */
  1990. /*E*/
  1991. char *
  1992. instr ()
  1993. {
  1994.     static char buf[512];
  1995.  
  1996.     register int c;
  1997.     register char *p = buf;
  1998.     register int col = 0;
  1999.  
  2000.     move (22, 0);
  2001.     clrtoeol ();
  2002.     refresh ();
  2003.  
  2004.     while ((c = getch ()) != '\r')
  2005.     {
  2006.         if (isascii (c) && isprint (c))
  2007.         {
  2008.             move (22, col);
  2009.             addch (c);
  2010.             *p++ = c;
  2011.             col++;
  2012.         }
  2013.         else if (c == '\b')
  2014.         {
  2015.             p--;
  2016.             col--;
  2017.             move (22, col);
  2018.             addch (' ');
  2019.             move (22, col);
  2020.         }
  2021.         refresh ();
  2022.     }
  2023.  
  2024.     refresh ();
  2025.  
  2026.     *p = '\0';
  2027.  
  2028.     return buf;
  2029. }
  2030. /*S getnum - retrieve a number from the terminal */
  2031. /*H getnum */
  2032. /*E*/
  2033. long
  2034. getnum (frst_char, hex)
  2035. register int frst_char;
  2036. register int hex;
  2037. {
  2038.     static char buf[64];
  2039.  
  2040.     register int c;
  2041.     register char *p = buf;
  2042.     register int col = 0;
  2043.  
  2044.     register long retval = 0;
  2045.  
  2046.     move (22, 0);
  2047.     clrtoeol ();
  2048.     if (frst_char)
  2049.     {
  2050.         addch (frst_char);
  2051.         *p++ = frst_char;
  2052.         col++;
  2053.         refresh ();
  2054.     }
  2055.  
  2056.     while ((c = getch()) != '\r')
  2057.     {
  2058.         if (isascii (c))
  2059.         {
  2060.             if ((hex && isxdigit (c)) || isdigit (c))
  2061.             {
  2062.                 move (22, col);
  2063.                 addch (c);
  2064.                 *p++ = c;
  2065.                 col++;
  2066.             }
  2067.             else if (c == '\b')
  2068.             {
  2069.                 p--;
  2070.                 col--;
  2071.                 move (22, col);
  2072.                 addch (' ');
  2073.                 move (22, col);
  2074.             }
  2075.             else
  2076.             {
  2077.                 break;    /* some character typing the value */
  2078.             }
  2079.             refresh ();
  2080.         }
  2081.     }
  2082.  
  2083.     *p = '\0';
  2084.  
  2085.     retval = atol (buf);
  2086.  
  2087.     mvprintw (22, 0, "%ld", retval);
  2088.     switch (c)
  2089.     {
  2090.         case    'b':    /* block - 512 bytes            */
  2091.             retval *= 512;
  2092.             break;
  2093.         case    'k':    /* 1024 bytes                */
  2094.             retval *= 1024;
  2095.             break;
  2096.         case    'l':    /* long word - 4 bytes            */
  2097.             retval *= 4;
  2098.             break;
  2099.         case    'p':    /* page - 256 bytes            */
  2100.             retval *= 256;
  2101.             break;
  2102.         case    'w':    /* word - 2 bytes            */
  2103.             retval *= 2;
  2104.             break;
  2105.         case    '\r':    /* just clear it for display        */
  2106.             c = '\0';
  2107.             break;
  2108.     }
  2109.  
  2110.     printw ("%c -> %ld byte offset", c, retval);
  2111.     clrtoeol ();
  2112.  
  2113.     refresh ();
  2114.  
  2115.     return retval;
  2116. }
  2117. /*S search - look for an ascii string in the file */
  2118. /*H search */
  2119. /*E*/
  2120. search (fid)
  2121. register int fid;
  2122. {
  2123.     long    curpos = position;
  2124.     long    currec = recno;
  2125.  
  2126.     char    lrecord[sizeof record + 1];
  2127.  
  2128.     register int i;
  2129.     register int matched = 0;
  2130.     register int srch_len;
  2131.  
  2132.     register char *cp = instr ();
  2133.     register char *rp;
  2134.  
  2135.     int row, col;
  2136.  
  2137.     srch_len = strlen (cp);
  2138.     copyrec (record, lrecord, sizeof record);
  2139.     lrecord[256] = '\0';
  2140.  
  2141.     pbrk = 0;
  2142.  
  2143.     wmove (errwin, 0, 0);
  2144.     wstandout (errwin);
  2145.     wmove (errwin, 0, 40);
  2146.     wstandend (errwin);
  2147.     wmove (errwin, 0, 1);
  2148.     waddstr (errwin, "..searching record ");
  2149.     getyx (errwin, row, col);
  2150.  
  2151.     do
  2152.     {
  2153.         mvwprintw (errwin, row, col, "%ld", currec);
  2154.         touchwin (errwin);
  2155.         wrefresh (errwin);
  2156.  
  2157.         for (i = 0, rp = lrecord, matched = 0;
  2158.              !matched && i < 256;
  2159.              rp++, i++)
  2160.         {
  2161.             if (*cp == *rp && !strncmp (cp, rp, srch_len))
  2162.             {
  2163.                 matched = 1;
  2164.                 break;
  2165.             }
  2166.         }
  2167.  
  2168.         if (!matched)
  2169.         {
  2170.             bytes = bread (fid, lrecord, 256, block);
  2171.             currec++;
  2172.             lrecord[256] = '\0';
  2173.         }
  2174.     }    while (!pbrk && bytes && !matched);
  2175.  
  2176.     if (matched)
  2177.     {
  2178.         recno = currec;
  2179.         stay = 0;
  2180.         copyrec (record, unch_rec, sizeof record);
  2181.         werase (errwin);
  2182.         touchwin (errwin);
  2183.         wrefresh (errwin);
  2184.     }
  2185.     else
  2186.     {
  2187.         sprintf (outbuf, "String %s not found", cp);
  2188.         errmsg (outbuf, SLEEP_TIME);
  2189.         stay = 1;
  2190.     }
  2191.  
  2192.     return;
  2193. }
  2194. /* simplified call to errmsg(), by using sprintf to load format */
  2195. /* sleep_time is not implemented and awaits cleaning up of the signals (?) */
  2196. errmsg (fmt, sleep_time)
  2197. unsigned sleep_time;
  2198. char *fmt;
  2199. {
  2200.     int y, x;
  2201.  
  2202.     if (windowed)
  2203.     {
  2204.         getyx (stdscr, y, x);
  2205.         wmove (errwin, 0, 0);
  2206.         wstandout (errwin);
  2207.         wprintw (errwin, fmt);
  2208.         wstandend (errwin);
  2209.         wclrtoeol (errwin);
  2210.         touchwin (errwin);
  2211.         wrefresh (errwin);
  2212.         move (y, x);
  2213.     }
  2214.     else
  2215.     {
  2216.         fprintf (stderr, fmt);
  2217.         fprintf (stderr, "\n");
  2218.     }
  2219.     /* signal problem ?? if sleep called
  2220.     if (sleep_time)
  2221.         sleep (sleep_time);
  2222.     */
  2223.     return;
  2224. }
  2225. /* simplified call to outstr(), by using sprintf to load format */
  2226. outstr (fmt)
  2227. char *fmt;
  2228. {
  2229.     if (dump) printf (fmt);
  2230.     else printw (fmt);
  2231.  
  2232.     return;
  2233. }
  2234. outch (ch)
  2235. register char ch;
  2236. {
  2237.     if (dump) putchar (ch);
  2238.     else addch (ch);
  2239.  
  2240.     return;
  2241. }
  2242. AlBeRtEiNsTeIn
  2243.