/* File: zap.c -- zu Kap. 3.5.5. Beispiele
   Fkt.: interaktives Aendern von Binaerfiles */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <fcntl.h>

char help[] = "\
d <von(hex)> <bis(hex)> : Ausgabe Speicher\n\
r <von(hex)> <bis(hex)> : Ersetze Zeichen\n\
e		        : Exit\n";

jmp_buf jmpbuf;

main(argc, argv)
char *argv[];

{
	int fd;
	void onintr(), zap();

	if(argc!=2){
		printf("usage: zap file\n");
		exit(1);
	}
	if((fd=open(argv[1],O_RDWR))<0){
		printf("can't open %s\n", argv[1]);
		exit(1);
	}
	setjmp(jmpbuf);
	signal(SIGINT,onintr);
	for(;;){
	fprintf(stderr, "Eingabe Kommando (d|r|e): ");
	switch(getchar()){
	case 'h':
	case 'H':
		fprintf(stderr,help);
		break;
	case 'd':
	case 'D':
		zap(fd,'d');
		break;
	case 'r':
	case 'R':
		zap(fd,'r');
		break;
	case 'q':
	case 'e':
	case 'E':
		exit(0);
	case '\n':
	case ' ':
		break;
	default:
		printf("format error\n");
		break;
	}
	while (getchar() != '\n');
	}
}

void onintr()
{
	longjmp(jmpbuf, 1);
}

void zap(fd,c)
{
	int j,pos1,pos2;
	register int i,anz;
	char buf[17];

	if(scanf("%x%x", &pos1, &pos2)!=2) {
		printf("input error\n");
		return;
	}
	pos2 -= pos1;
	pos2++;
	lseek(fd,(long)pos1,0);
	for(;pos2>0&&(anz=read(fd,buf,pos2>16?16:pos2))>0;pos2-=anz){
		if(c=='r'){
			lseek(fd,(long)-anz,1);
			for(i=0;i<anz;i++){
				printf("%.4x old: %.2x - input new: ", pos1,
					buf[i]<0?-buf[i]:buf[i]);
				pos1++;
				if(scanf("%x", &j)==1)
					buf[i]=j;
				else
					getchar();
			}
			write(fd, buf, anz);
		} else {
			printf("%.4x  ", pos1);
			pos1 += anz;
			for(i=0;i<anz;i++)
			   printf("%2.2x%s", buf[i]<0?-buf[i]:buf[i],
			  		 (i+1)%4?"":" ");
			for(;i<=16;i++)
				printf("  %s", (i+1)%4?"":" ");
			for(i=0;i<16;i++)
				if(buf[i] < 0x20 || buf[i] >0x7e)
					buf[i] = '.';
			buf[anz] = 0;
			printf("  %s\n", buf);
		}
	}
}
