1 /*----------------------------------------------------------------------------*/
2 /* Program: hex.c							      */
3 /* Date:    27-nov-1988							      */
4 /* Desc:    Hex editor source						      */
5 /* Author:  Dominic Alston						      */
6 /* Version: 2.4								      */
7 /* Revision history:							      */
8 /*	25-jan-1989  dom: Added terminal independant code		      */
9 /*	30-jan-1989  dom: Redesigned screen, added features		      */
10 /*	03-feb-1989  dom: Modified code.				      */
11 /*	04-feb-1989  dom: Added own mmi routines			      */
12 /*	05-feb-1989  dom: Version 2 Increment 0 release finished.	      */
13 /*	06-feb-1989  dom: Fixed goto out of band chars being accepted	      */
14 /*	20-feb-1989  dom: Added version print and readonly feature	      */
15 /*	23-feb-1989  dom: Added screen refresh.				      */
16 /*----------------------------------------------------------------------------*/
17 
18 #include <sys/types.h>
19 #include <curses.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <signal.h>
27 #include <sys/stat.h>
28 
29 #define VERSION_STAMP "2.4"
30 #define PAGESIZE 1280
31 #define BUFSIZE 256
32 #define READING 0
33 #define WRITING 1
34 #define GOTO 2
35 #define DBUFF_SIZE 32
36 #define FBUFF_SIZE 16
37 #define X_PRODUCT 30
38 #define Y_PRODUCT 0
39 #define X_MENU1 0
40 #define Y_MENU1 2
41 #define X_MENU2 0
42 #define Y_MENU2 3
43 #define X_STATUS 0
44 #define Y_STATUS 5
45 #define X_FORMAT 76
46 #define X_POSITION 19
47 #define X_PROMPT 0
48 #define Y_PROMPT 6
49 #define X_INPUT 9
50 #define X_FIND 9
51 #define Y_FIND 6
52 #define X_HEX 0
53 #define Y_HEX 7
54 #define X_CHAR 52
55 #define Y_CHAR 7
56 #define X_EXIT 0
57 #define Y_EXIT 23
58 #define X_VERB 36
59 #define Y_VERB 5
60 #define CTRL(c) ((c) & 037)
61 #define _KEY_EXIT 'q'
62 #define ENTER '\n'
63 #define KEY_ESC '\033'
64 #define KEY_TAB '\t'
65 
66 static int ch;			/* buffer for single character read	      */
67 static char page[PAGESIZE];	/* buffer for screen display		      */
68 static char *hptr;		/* pointer to page for hex display	      */
69 static char *cptr;		/* pointer to page for character display      */
70 static char buf[BUFSIZE];	/* buffer for input i/o			      */
71 static char *bptr;		/* pointer to buf			      */
72 static char pos[9];		/* buffer for character format of position    */
73 static char find_buff[FBUFF_SIZE]; /* buffer holding the string for searching */
74 static int find_length;		/* size of string searched for		      */
75 static char disp_buff[DBUFF_SIZE]; /* buffer holding the search string during */
76 static int disp_length;
77 static char hexchars[] = "0123456789ABCDEF";
78 static char head1[] = "			     Hexpert [v2.4 (c)1988 Dominic Alston]		       ";
79 static char r_head2[] =
80 	"Options: <Up-arrow>  =Page-up	  <g>=Goto-position  <c> =Char-find  <q>=Exit	";
81 static char r_head3[] =
82 	"	  <Down-arrow>=Page-down  <h>=Hex-find	     <^l>=Refresh	       ";
83 static char head2[] =
84 	"Options: <Up-arrow>  =Page-up	  <g>=Goto-position  <c>=Char-find  <q> =Exit";
85 static char head3[] =
86 	"	  <Down-arrow>=Page-down  <e>=Edit-buffer    <h>=Hex-find   <^l>=Refresh";
87 static char head4[] =
88 	"Status-  Position: 00000000   Mode: View   File: ";
89 static char head5[] =
90 	"Options: <Enter>=Write-buffer	<Tab>=Toggle hex/char edit			";
91 static char head6[] =
92 	"	  <Esc>	 =Restore buffer & goto view mode				";
93 static char head7[] =
94 	"Options: <Enter>=Do-search	  <Left-arrow>= Move-left			";
95 static char head8[] =
96 	"	  <Esc>	 =Goto view mode  <Right-arrow>=Move-right			";
97 static char edit1[] =
98 	"Options: <Enter>=Goto-position	  <Left-arrow>=Move-left			";
99 static char edit2[] =
100 	"	  <Esc>	 =Goto view mode  <Right-mode>=Move-right			";
101 static char msg1[] = "pattern not found!";
102 static char usage_bnr[]=
103 	"Usage: %s [-vr] 'file'\n";
104 static char version_bnr[]=
105 	"HEXPERT V%s, Dominic Alston..\n";
106 static char error1[] = "internal error - hex unpaired!";
107 static int x,y;		/* screen co-ordinates				      */
108 static int input;	/* file descriptor for input file		      */
109 static int mode;	/* current mode of use				      */
110 static int readonly;	/* true if input file is read only		      */
111 static int bytes_written;
112 static int bytes_read;
113 static char hex_find;	/* true if find mode is currently hex		      */
114 static off_t position;	/* displacement of current buffer in input file	      */
115 static off_t lastbyte;	/* displacement of end of file	(Mod 256)	      */
116 static struct stat filedata; /* statistics of the input file,gives file size  */
117 static int bool_hexfind=FALSE;
118 
119 
120 static void initialise(char *filename);
121 static void display(void);
122 static void closedown(void);
123 static void toplevel(void);
124 static int get_position(void);
125 static void pos_print(void);
126 static void editbuffer(void);
127 static void toplev_headings(void);
128 static void char_ed(void);
129 static void hex_ed(void);
130 static void hex_to_buf(void);
131 static int get_string(void);
132 static void set_string(void);
133 static void buftoh(char *out_string, char *in_string, int in_size);
134 static void htobuf(char *out_string, char *in_string, int in_size);
135 static void buftobuf(char *out_string, char *in_string, int in_size);
136 static void find_string(void);
137 static int search(char *sbuf, off_t *start, int size);
138 static void init_term(void);
139 static void reset_term(void);
140 static int get_str(WINDOW *wnd, int row, int col, char *str, char filler, int str_size);
141 static void ctrlc_ast(int sig);
142 static void put_prompt(void);
143 static void edit_headings(void);
144 
145 int
main(int argc,char * argv[])146 main(int argc, char *argv[])
147 {
148 	int c;
149 	char *filenm = 0;
150 
151 	while ((c=getopt(argc,argv,"vr:"))!=EOF) {
152 		switch(c)
153 		{
154 		case 'v':
155 			fprintf(stderr,version_bnr,
156 			    VERSION_STAMP);
157 			exit(-1);
158 		case 'r':
159 			readonly=TRUE;
160 			filenm=optarg;
161 			break;
162 		default:
163 			fprintf(stderr,usage_bnr,argv[0]);
164 			exit(-1);
165 		}
166 	}
167 	if (argc==1) {
168 		fprintf(stderr,usage_bnr,argv[0]);
169 		exit(-1);
170 	} else
171 		initialise(filenm==0?argv[1]:filenm);
172 	toplevel();
173 	closedown();
174 	exit(0);
175 }
176 
177 static void
initialise(char * filename)178 initialise(char *filename)
179 {
180 	register int i,j;
181 	char *ptr;
182 
183 	/* Open file for read & write, if this fails			      */
184 	/* open file for reading, if fail exit.				      */
185 	if ((input=open(filename,O_RDWR))==-1) {
186 		if ((input=open(filename,O_RDONLY))==-1) {
187 			perror(filename);
188 			exit(-1);
189 		} else
190 			readonly=TRUE;
191 	}
192 	init_term();		/* init curses terminfo			      */
193 	signal(SIGINT,ctrlc_ast);    /* signal handler for contol c	      */
194 	/* Read the file statistics to find  the			      */
195 	/* file size and put it in 'lastbyte',				      */
196 	/* after adjusting to a multiple of 256				      */
197 	if ((fstat(input,&filedata))==0)
198 		lastbyte=(filedata.st_size-1) & (off_t)0xffffff00;
199 	else
200 		lastbyte = 0;
201 	/* Clear the display buffer.					      */
202 	hptr=page;
203 	for (i=0; i<PAGESIZE; i++)
204 		*hptr++=' ';
205 	attron(A_REVERSE);
206 	addstr(head1);
207 	attroff(A_REVERSE);
208 	toplev_headings();
209 	mvaddstr(Y_STATUS, X_STATUS,head4);
210 	/* Display the input file name.					      */
211 	i=strlen(filename);
212 	ptr=(char *)filename;
213 	if (i>33)
214 		i=33;
215 	for (j=0; j<i; j++)
216 		addch(*ptr++);
217 	/* Read and display the first 256 bytes				      */
218 	if (readonly) {
219 		attron(A_BOLD);
220 		mvaddstr(Y_STATUS,72,"Readonly");
221 		attroff(A_BOLD);
222 	}
223 	refresh();
224 	position = 0;
225 	lseek(input,position,0);
226 	display();
227 	mode = READING;
228 	hex_find = FALSE;
229 	find_length = 0;
230 	put_prompt();
231 	refresh();
232 }
233 
234 static void
display(void)235 display(void)
236 {
237 	int num;
238 	register int i;
239 	int j;
240 	int jlimit;
241 
242 	hptr = page;
243 	cptr = (hptr + 52);
244 	bptr = buf;
245 	pos_print();
246 	move(Y_HEX, X_HEX);
247 	if (((num=read(input,buf,BUFSIZE))!=EOF) && (num!=0)) {
248 		if (num<BUFSIZE) {
249 			for (i=0; i<PAGESIZE; i++)
250 				*hptr++ = ' ';
251 			hptr=page;
252 		}
253 		for (i=0; i<num; i+=16) {
254 			jlimit=((num-i)>=16)?16:num-i;
255 			for (j=0; j<jlimit; j++) {
256 				*hptr++=hexchars[(*bptr>>4) & 0xf];
257 				*hptr++=hexchars[*bptr & 0xf];
258 				*hptr++=' ';
259 				*cptr++=((*bptr)>0x1f &&
260 				    (*bptr)<0x7f?*bptr:'.');
261 				bptr++;
262 			}
263 			*((cptr-jlimit)+80)='\n';
264 			hptr+=32;
265 			cptr=(hptr+52);
266 		}
267 	} else
268 		for(i=0; i<PAGESIZE; i++)
269 			*hptr++=' ';
270 	bytes_read=num;
271 	move(Y_HEX,X_HEX);
272 	hptr=page;
273 	for (i=0; i<PAGESIZE; i++)
274 		mvaddch(Y_HEX+(i/80), X_HEX+(i%80),*hptr++);
275 	bytes_written=i;
276 	if (bytes_written!=PAGESIZE)
277 		closedown();
278 	put_prompt();
279 	refresh();
280 }
281 
282 static void
closedown(void)283 closedown(void)
284 {
285 	reset_term();
286 	exit(0);
287 }
288 
289 static void
toplevel(void)290 toplevel(void)
291 {
292 
293 	while ((ch=getch())!=_KEY_EXIT) {
294 		clrtoeol();
295 		refresh();
296 		switch(ch) {
297 		case CTRL('l'):
298 			clearok(curscr,TRUE);
299 			doupdate();
300 			break;
301 		case KEY_HOME:
302 			if (position!=0) {
303 				position=0;
304 				lseek(input,position,0);
305 				display();
306 			} else
307 				beep();
308 			break;
309 		case KEY_DOWN:
310 			if (position != lastbyte) {
311 				if ((position += 256) > lastbyte)
312 					position = lastbyte;
313 				lseek(input,position,0);
314 				display();
315 			} else
316 				beep();
317 			break;
318 		case KEY_UP:
319 			if (position != 0) {
320 				position -= 256;
321 				if (position < 0)
322 					position = 0;
323 				lseek(input,position,0);
324 				display();
325 			} else
326 				beep();
327 			break;
328 		case 'g':
329 		case 'G':
330 			mode=GOTO;
331 			if (get_position()) {
332 				lseek(input,position,0);
333 				display();
334 			} else
335 				pos_print();
336 			toplev_headings();
337 			mode=READING;
338 			break;
339 		case 'e':
340 		case 'E':
341 			if (readonly) {
342 				beep();
343 				move(6,9);
344 				refresh();
345 			} else
346 				editbuffer();
347 			break;
348 		case 'c':
349 		case 'C':
350 		case 'h':
351 		case 'H':
352 			if ((ch=='c') || (ch=='C'))
353 				hex_find=FALSE;
354 			else
355 				hex_find=TRUE;
356 			if (get_string()==1)
357 				find_string();
358 			toplev_headings();
359 			break;
360 		default:
361 			beep();
362 			break;
363 		}
364 	}
365 }
366 
367 static int
get_position(void)368 get_position(void)
369 {
370 	char num[9];
371 	char *ptr1,*ptr2;
372 	int status;
373 	off_t posit;
374 	register int i;
375 
376 	edit_headings();
377 	posit=0;
378 	ptr1=num;
379 	ptr2=pos;
380 	for (i=0; i<9; i++)
381 		(*(ptr1++))=(*(ptr2++));
382 	move(Y_STATUS,10);
383 	disp_length=7;
384 	if ((status=get_str(stdscr,Y_STATUS,X_POSITION,num,'0',8))==-1)
385 		return(FALSE);
386 	for (i=0; i<8; i++) {
387 		posit=(posit<<4)+(num[i] & 0xf);
388 		if (num[i]>'9')
389 			posit+=9;
390 	}
391 	if (posit<0)
392 		posit=0;
393 	if (posit<=lastbyte)
394 		position=posit;
395 	else
396 		position=lastbyte;
397 	return(TRUE);
398 }
399 
400 static void
pos_print(void)401 pos_print(void)
402 {
403 	char *ptr;
404 
405 	ptr=pos+7;
406 	*ptr--=hexchars[(position & 0xf)];
407 	*ptr--=hexchars[((position>>4) & 0xf)];
408 	*ptr--=hexchars[((position>>8) & 0xf)];
409 	*ptr--=hexchars[((position>>12) & 0xf)];
410 	*ptr--=hexchars[((position>>16) & 0xf)];
411 	*ptr--=hexchars[((position>>20) & 0xf)];
412 	*ptr--=hexchars[((position>>24) & 0xf)];
413 	*ptr--=hexchars[((position>>28) & 0xf)];
414 	*(pos+9)=0;
415 	mvaddstr(Y_STATUS,X_POSITION,pos);
416 }
417 
418 static void
editbuffer(void)419 editbuffer(void)
420 {
421 	/* Display edit headings	*/
422 	mvaddstr(Y_MENU1, X_MENU1,head5);
423 	mvaddstr(Y_MENU2, X_MENU2,head6);
424 	mvaddstr(Y_VERB, X_VERB,"Edit");
425 	hex_ed();
426 	mode = READING;
427 	toplev_headings();
428 }
429 
430 /* read_headings: Display read headings */
431 static void
toplev_headings(void)432 toplev_headings(void)
433 {
434 	if (readonly) {
435 		mvaddstr(Y_MENU1, X_MENU1,r_head2);
436 		mvaddstr(Y_MENU2, X_MENU2,r_head3);
437 	} else {
438 		mvaddstr(Y_MENU1, X_MENU1,head2);
439 		mvaddstr(Y_MENU2, X_MENU2,head3);
440 	}
441 	mvaddstr(Y_VERB, X_VERB,"View");
442 	move(Y_PROMPT, X_INPUT);
443 	refresh();
444 }
445 
446 static void
char_ed(void)447 char_ed(void)  /* Entered from hex_ed() when 'TAB' read. */
448 {
449 	char *ptr;
450 	char *eptr;
451 	unsigned char c1,c2;
452 	int xx;
453 
454 	/* get byte by mapping on to physical scale from screen scale	      */
455 	ptr=page+(y-7)*80+x;
456 	move(y,x);
457 	refresh();
458 	do {
459 		ch=getch();
460 		if ((ch)>=0x20 && (ch)<0x7f) {
461 			addch(ch);
462 			refresh();
463 			*ptr = ch;
464 			c1 = ch & 0xf;
465 			c2 = (ch >> 4) & 0xf;
466 			xx = (x - 52) * 3;
467 			eptr = (ptr - x) + xx;
468 			*eptr++ = hexchars[c2];
469 			*eptr	= hexchars[c1];
470 			move(y,xx);
471 			addch(*--eptr);
472 			addch(*++eptr);
473 			refresh();
474 			if (x == 67) {
475 				if (y < 22) {
476 					ptr +=65;
477 					x = 52;
478 					y++;
479 				} else {
480 					ptr = page + 52;
481 					x = 52;
482 					y = 7;
483 				}
484 			} else {
485 				ptr++;
486 				x++;
487 			}
488 		}
489 		else if (ch==KEY_RIGHT)
490 			if (x==67) {
491 				if (y<22) {
492 					ptr+=65;
493 					x=52;
494 					y++;
495 				} else {
496 					ptr=page+52;
497 					x=52;
498 					y=7;
499 				}
500 			} else {
501 				ptr++;
502 				x++;
503 			}
504 		else if (ch == KEY_LEFT)
505 			if (x == 52) {
506 				if (y > 7) {
507 					ptr -= 65;
508 					x = 67;
509 					y--;
510 				} else {
511 					ptr += 1215;
512 					x = 67;
513 					y = 22;
514 				}
515 			} else {
516 				ptr--;
517 				x--;
518 			}
519 		else if (ch == KEY_UP)
520 			if (y > 7) {
521 				ptr -=80;
522 				y--;
523 			} else {
524 				ptr +=1200;
525 				y = 22;
526 			}
527 		else if (ch == KEY_DOWN)
528 			if (y < 22) {
529 				ptr +=80;
530 				y++;
531 			} else {
532 				ptr -=1200;
533 				y = 7;
534 			}
535 		else if (ch == KEY_ESC) {
536 			lseek(input,position,0);
537 			display();
538 		} else if ((ch == ENTER) || (ch == KEY_TAB))
539 			/* do nothing */ ;
540 		else
541 			beep();
542 		move(y,x);
543 		refresh();
544 	} while ((ch!=ENTER) && (ch!=KEY_TAB) && (ch!=KEY_ESC));
545 	if (ch==ENTER) {
546 		hex_to_buf();
547 		lseek(input,position,0);
548 		write(input,buf,bytes_read);
549 	}
550 	mode=READING;
551 }
552 
553 static void
hex_ed(void)554 hex_ed(void)
555 {
556 	char *ptr;
557 
558 	ptr=page;
559 	x=X_HEX;
560 	y=Y_HEX;
561 	move(y,x);
562 	refresh();
563 	do {
564 		ch=getch();
565 		if (isxdigit(ch)) {
566 			addch(toupper(ch));
567 			refresh();
568 			*ptr = ch;
569 			{
570 				char *eptr,c1,c2;
571 				int xx;
572 
573 				if ((x%3) == 1)
574 					eptr = ptr - 1;
575 				else
576 					eptr = ptr;
577 				c1 = *eptr++;
578 				c2 = *eptr;
579 				if (c1 > '9')
580 					c1 = (c1 + 9) & 0xf;
581 				else
582 					c1 = c1 & 0xf;
583 				if (c2 > '9')
584 					c2 = (c2 + 9) & 0xf;
585 				else
586 					c2 = c2 & 0xf;
587 				c1 = (c1 << 4) + c2;
588 				xx = (x/3) + 52;
589 				move(y,xx);
590 				refresh();
591 				if ((c1>=0x20) && (c1<0x7f))
592 					addch(c1);
593 				else
594 					addch('.');
595 				refresh();
596 			}
597 			ptr++;
598 			x++;
599 			if (((x+1)%3)==0) {
600 				if (x==47) {
601 					if (y<22) {
602 						ptr+=33;
603 						x=0;
604 						y++;
605 					} else {
606 						ptr=page;
607 						x=0;
608 						y=7;
609 					}
610 				} else {
611 					ptr++;
612 					x++;
613 				}
614 			}
615 		} else if (ch==KEY_RIGHT) {
616 			ptr++;
617 			x++;
618 			if (((x+1)%3)==0) {
619 				if (x==47) {
620 					if (y<22) {
621 						ptr+=33;
622 						x=0;
623 						y++;
624 					} else {
625 						ptr=page;
626 						x=0;
627 						y=7;
628 					}
629 				} else {
630 					ptr++;
631 					x++;
632 				}
633 			}
634 		}
635 		else if (ch==KEY_LEFT)
636 			if (x==0) {
637 				if (y>7) {
638 					ptr -= 34;
639 					x = 46;
640 					y--;
641 				} else {
642 					ptr += 1246;
643 					x = 46;
644 					y = 22;
645 				}
646 			} else {
647 				ptr--;
648 				x--;
649 				if (((x+1)%3)==0)
650 				{
651 					ptr--;
652 					x--;
653 				}
654 			}
655 		else if (ch == KEY_UP)
656 			if (y > 7) {
657 				ptr -= 80;
658 				y--;
659 			} else {
660 				ptr += 1200;
661 				y = 22;
662 			}
663 		else if (ch == KEY_DOWN)
664 			if (y < 22) {
665 				ptr += 80;
666 				y++;
667 			} else {
668 				ptr -= 1200;
669 				y = 7;
670 			}
671 		else if (ch == KEY_ESC) {
672 			lseek(input,position,0);
673 			display();
674 		}
675 		else if (ch==ENTER)
676 			;
677 		else if (ch==KEY_TAB) {
678 			x = (x/3) + 52;
679 			char_ed();
680 			x = (x-52) * 3;
681 			ptr = page + (y-7)*80 + x;
682 		} else
683 			beep();
684 		move(y,x);
685 		refresh();
686 	} while (ch!=ENTER && ch!=KEY_ESC);
687 	if (ch==ENTER) {
688 		hex_to_buf();
689 		lseek(input,position,0);
690 		write(input,buf,bytes_read);
691 	}
692 }
693 
694 static void
hex_to_buf(void)695 hex_to_buf(void)
696 {
697 	char c1,c2;
698 	int i;
699 	int j;
700 
701 	hptr = page;
702 	bptr = buf;
703 	for (i=0;i<16;i++) {
704 		for (j=0;j<16;j++) {
705 			c1 = *hptr++;
706 			if (c1 > '9')
707 				c1 = (c1 + 9) & 0xf;
708 			else
709 				c1 = c1 & 0xf;
710 			c2 = *hptr++;
711 			if (c2 > '9')
712 				c2 = (c2 + 9) & 0xf;
713 			else
714 				c2 = c2 & 0xf;
715 			*bptr++ = (c1 << 4) + c2;
716 			hptr++;
717 		}
718 		hptr += 32;
719 	}
720 }
721 
722 static int
get_string(void)723 get_string(void)
724 {
725 	mvaddstr(Y_MENU1, X_MENU1,head7);
726 	mvaddstr(Y_MENU2, X_MENU2,head8);
727 	mvaddstr(Y_VERB, X_VERB,"Find");
728 	attron(A_BOLD);
729 	mvaddstr(6,0,"search criteria: ");
730 	attroff(A_BOLD);
731 	if ((bool_hexfind && !hex_find) || (!bool_hexfind && hex_find)) {
732 		if (hex_find)
733 			bool_hexfind=TRUE;
734 		else if (!hex_find)
735 			bool_hexfind=FALSE;
736 		find_length=0;
737 		disp_buff[0]=0;
738 	}
739 	if (hex_find) {
740 		buftoh(disp_buff,find_buff,find_length);
741 		disp_length=find_length*2;
742 	} else
743 		buftobuf(disp_buff,find_buff,disp_length=find_length);
744 	if ((disp_length=get_str(stdscr,6,17,disp_buff,'.',
745 		 hex_find?DBUFF_SIZE:FBUFF_SIZE))==-1) {
746 		put_prompt();
747 		return(FALSE);
748 	} else if (disp_length==0 && hex_find)
749 		disp_length=find_length*2;
750 	else if (disp_length==0 && !hex_find)
751 		disp_length=find_length;
752 	set_string();
753 	return(TRUE);
754 }
755 
756 /* set_string: set up the string for return */
757 static void
set_string(void)758 set_string(void)
759 {
760 	if (hex_find) {
761 		htobuf(find_buff,disp_buff,disp_length);
762 		find_length=disp_length/2;
763 	} else
764 		buftobuf(find_buff,disp_buff,find_length=disp_length);
765 }
766 
767 /* buftoh: Converts input buffer to hexadecimal display in output string.
768  *	   String length is used since zero is legitimate.
769  */
770 static void
buftoh(char * out_string,char * in_string,int in_size)771 buftoh(char *out_string, char *in_string, int in_size)
772 {
773 	register int i;
774 
775 	for (i=0; i < in_size; i++) {
776 		char c = *in_string++;
777 		*out_string++ = hexchars[(c >> 4) & 0xf]; /* [c/16]; */
778 		*out_string++ = hexchars[ c & 0xf]; /* [c%16]; */
779 	}
780 }
781 
782 /* htobuf: converts hexadecimal display to binary. String length is used
783  *	   and only hexadecimal pairs are handled.
784  */
785 static void
htobuf(char * out_string,char * in_string,int in_size)786 htobuf(char *out_string, char *in_string, int in_size)
787 {
788 	char i;
789 	int h_value, c_value;
790 	int byte_val = 0;
791 
792 	if (in_size%2 != 0) {
793 		put_prompt();
794 		addstr(error1);
795 		beep();
796 		refresh();
797 		return;
798 	}
799 	for (i=0; i < in_size; i++) {
800 		if ((h_value = *in_string++) >= '0' && h_value <= '9')
801 			c_value = h_value -'0';
802 		else
803 			(c_value = 10 + (h_value & 0xf) - ('a' & 0xf));
804 		if (!(i%2))
805 			byte_val = c_value * 16;
806 		else
807 			*out_string++ = byte_val + c_value;
808 	}
809 }
810 
811 /* buftobuf: Copy buffer to buffer. Not quite strncopy since zero is valid
812  *	     and not a terminator.
813  */
814 static void
buftobuf(char * out_string,char * in_string,int in_size)815 buftobuf(char *out_string, char *in_string, int in_size)
816 {
817 	register int i;
818 
819 	for (i=0; i<in_size; i++)
820 		(*(out_string++))=(*(in_string++));
821 }
822 
823 /* find_string: Locates the string which has been specified by the user.
824  *		The search is carried out cyclically locating the string
825  *		specified at the beginning of the buffer. If the string is
826  *		not found we tell the user with a friendly message.
827  */
828 static void
find_string(void)829 find_string(void)
830 {
831 	off_t start_pos=position; /* hold start position to stop cyclic search */
832 	int inc_length;
833 	/* the number of start points for search in one buffer full */
834 	int num_read; /* number read in this read */
835 	int found_it=0;
836 
837 	position ++;  /* make sure we move ahead */
838 	inc_length=BUFSIZE-find_length;
839 	/* search to the end of the file */
840 	while (filedata.st_size>=position+find_length && found_it!=1) {
841 		lseek(input,position,0);
842 		num_read=read(input,buf,BUFSIZE);
843 		if (search(buf,&position,num_read-find_length))
844 			found_it=1;
845 	}
846 	/* if still not found then search from beginning		      */
847 	if (found_it!=1) {
848 		position=0;
849 		while (position<=start_pos && found_it!=1) {
850 			lseek(input,position,0);
851 			num_read=read(input,buf,BUFSIZE);
852 			if (search(buf,&position,position+inc_length<start_pos?
853 				(int)inc_length:(int)(start_pos-position)))
854 				found_it=1;
855 		}
856 	}
857 	if (found_it!=1) {
858 		put_prompt();
859 		addstr(msg1);
860 		beep();
861 		refresh();
862 		position = start_pos;
863 		lseek(input,position,0);
864 		return;
865 	}
866 	lseek(input, position, 0);
867 	display();
868 }
869 
870 /* search: Search for the field described by find_buff and find_length in
871  *	   the parameter buf incrementing start as far as size.
872  *	   Returning true if the string is found.
873  */
874 static int
search(char * sbuf,off_t * start,int size)875 search(char *sbuf, off_t *start, int size)
876 {
877 	int i, j;
878 
879 	i = 0;
880 	j = -1;
881 	while (i != find_length && j++ < size) { /* loop through buffer */
882 		for (i=0; i<find_length && *(find_buff+i)==*(sbuf+i); i++)
883 			/* loop through string (no body) */ ;
884 		sbuf++;
885 	}
886 	*start+=j;
887 	return (i==find_length);
888 }
889 
890 /* initialise term..							      */
891 static void
init_term(void)892 init_term(void)
893 {
894 	initscr();		/* init curses terminfo			      */
895 	keypad(stdscr,TRUE);	/* allow keypad use			      */
896 	noecho();		/* set terminal to noecho		      */
897 	cbreak();		/* raw input				      */
898 }
899 
900 /* reset term to the way it was						      */
901 static void
reset_term(void)902 reset_term(void)
903 {
904 	nocbreak();
905 	echo();
906 	endwin();
907 }
908 
909 /* get string routine							      */
910 static int
get_str(WINDOW * wnd,int row,int col,char * str,char filler,int str_size)911 get_str(WINDOW *wnd, int row, int col, char *str, char filler, int str_size)
912 {
913 	int ccol=0,c,erase_flg=0;
914 	register int i;
915 	int leave=FALSE;
916 	int status=0;
917 
918 	for (i=0; i<str_size; i++)	/* paste filler to field	      */
919 		mvwaddch(wnd,row,col+i,filler);
920 	/* print contents of str					      */
921 	for (i=0; i<disp_length; i++)
922 		mvwaddch(wnd,row,col+i,str[i]);
923 	wmove(wnd,row,col);			/* move to field start	      */
924 	wrefresh(wnd);				/* refresh whats been done    */
925 	while (!leave) {
926 		c=wgetch(wnd);
927 		switch(c) {
928 		case '\n':
929 		case '\r':
930 			leave=TRUE;
931 			break;
932 		case KEY_HOME:
933 			ccol=0;
934 			wmove(wnd,row,col+ccol);
935 			refresh();
936 			break;
937 		case KEY_BACKSPACE:
938 		case CTRL('h'):
939 			if (ccol>0){
940 				if (--ccol<0)
941 					ccol=0;
942 				mvwaddch(wnd,row,col+ccol,filler);
943 				wmove(wnd,row,col+ccol);
944 				*(str+ccol)=' ';
945 				wrefresh(wnd);
946 			} else
947 				beep();
948 			break;
949 		case KEY_ESC:			/* if escape pressed */
950 			status=(char)-1;
951 			leave=TRUE;
952 			break;
953 		case KEY_LEFT:
954 			erase_flg=1;
955 			if (ccol>0) {
956 				if (--ccol<0)
957 					ccol=0;
958 				wmove(wnd,row,col+ccol);
959 				wrefresh(wnd);
960 			} else
961 				beep();
962 			break;
963 		case KEY_RIGHT:
964 			if (ccol<str_size-1) {
965 				if (++ccol>str_size)
966 					ccol=str_size;
967 				wmove(wnd,row,col+ccol);
968 				wrefresh(wnd);
969 			} else
970 				beep();
971 			break;
972 		default:			/* other chars	     */
973 			if ((((hex_find || mode==GOTO) && isxdigit(c)) ||
974 				((!hex_find && mode!=GOTO) &&
975 				    (c>=0x20 && c<0x7f))) &&
976 			    ccol<str_size) {
977 				if (erase_flg==0){
978 					for (i=0; i<str_size; i++) {
979 						mvwaddch(wnd,row,col+i,
980 						    filler);
981 						str[i]=' ';
982 					}
983 				}
984 				mvwaddch(wnd,row,col+ccol,c);
985 				wrefresh(wnd);
986 				*(str+ccol)=c;
987 				if (++ccol>str_size)
988 					ccol=str_size;
989 			} else
990 				beep();
991 			break;
992 		}
993 		erase_flg=1;
994 	}
995 	if (status==0)
996 		status=ccol;
997 	return(status);
998 }
999 
1000 static void
ctrlc_ast(int sig)1001 ctrlc_ast(int sig)
1002 {
1003 	if (sig==SIGINT)
1004 		closedown();
1005 	else
1006 		signal(SIGINT,ctrlc_ast);
1007 }
1008 
1009 static void
put_prompt(void)1010 put_prompt(void)
1011 {
1012 	move(6,0);
1013 	clrtoeol();
1014 	attron(A_BOLD);
1015 	mvaddstr(Y_PROMPT, X_PROMPT,"command> ");
1016 	attroff(A_BOLD);
1017 }
1018 
1019 static void
edit_headings(void)1020 edit_headings(void)
1021 {
1022 	mvaddstr(Y_MENU1, X_MENU1,edit1);
1023 	mvaddstr(Y_MENU2, X_MENU2,edit2);
1024 	mvaddstr(Y_VERB, X_VERB,"Goto");
1025 }
1026