1 /* BVI  -  Binary Visual Editor
2  *
3  * 1996-02-28  V 1.0.0
4  * 1999-01-27  V 1.1.0
5  * 1999-04-22  V 1.1.1
6  * 1999-07-01  V 1.2.0 beta
7  * 1999-10-22  V 1.2.0 final
8  * 2000-05-10  V 1.3.0 alpha
9  * 2000-10-24  V 1.3.0 final
10  * 2002-01-03  V 1.3.1
11  * 2004-01-04  V 1.3.2
12  * 2006-04-04  V 1.3.3
13  * 2013-08-23  V 1.4.0alpha
14  * 2014-10-07  V 1.4.0
15  *
16  * NOTE: Edit this file with tabstop=4 !
17  *
18  * Copyright 1996-2014 by Gerhard Buergmann
19  * gerhard@puon.at
20  *
21  * This program is free software; you can redistribute it and/or modify it
22  * under the terms of the GNU General Public License as published by the
23  * Free Software Foundation; either version 2, or (at your option) any
24  * later version.
25  *
26  * This program is distributed in the hope that it will be useful, but
27  * WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29  * General Public License for more details.
30  *
31  * See file COPYING for information on distribution conditions.
32  */
33 
34 #include <sys/types.h>
35 
36 #include "bvi.h"
37 #include "set.h"
38 
39 #ifdef HAVE_LOCALE_H
40 #	include <locale.h>
41 #endif
42 
43 
44 char	*copyright  = "Copyright (C) 1996-2014 by Gerhard Buergmann";
45 
46 jmp_buf	env;        /* context for `longjmp' function   */
47 
48 int		loc;
49 int		maxx, maxy, x, xx, y;
50 int		screen, status, statsize;
51 off_t	size;
52 PTR		mem = NULL;
53 PTR		curpos;
54 PTR		maxpos;
55 PTR		pagepos;
56 PTR		spos;
57 char	*name = NULL;
58 char	*shell;
59 char	string[MAXCMD+1];
60 char	cmdstr[MAXCMD+1] = "";
61 FILE	*Ausgabe_Datei;
62 int		edits = 0;
63 int		AnzAdd, Anzahl, Anzahl3;
64 off_t	filesize, memsize, undosize;
65 
66 
67 long	precount = -1;
68 
69 int		block_flag = 0;
70 
71 
72 off_t	block_begin, block_end, block_size;
73 
74 
75 char	**files;		/* list of input files */
76 int		numfiles;		/* number of input files */
77 int		curfile;		/* number of the current file */
78 
79 int		arrnum = 0;
80 char	numarr[MAXCMD+1];		/* string for collecting number */
81 char	rep_buf[BUFFER];
82 
83 PTR		current;
84 PTR		last_motion;
85 PTR		current_start;
86 PTR		undo_start;
87 off_t	undo_count;
88 off_t	yanked = 0L;
89 char	*yank_buf = NULL;
90 char	*undo_buf = NULL;
91 PTR		markbuf[26];
92 
93 char	addr_form[15];
94 
95 char	*nobytes = "No bytes@in the buffer";
96 
97 static	char	progname[8];
98 static	char	line[MAXCMD+1];
99 static	int		mark;
100 static	int		wrstat = 1;
101 
102 
103 void
usage()104 usage()
105 {
106 
107 	fprintf(stderr, "Usage: %s [-R] [-c cmd | +cmd] [-f script]\n\
108 	   [-s skip] [-e end] [-n length] file ...\n\
109 	   file offset/size: 10k, 20m, 1g, 0x1000 hex, 0200 octal\n", progname);
110 
111 	exit(1);
112 }
113 
114 
115 int
main(argc,argv)116 main(argc, argv)
117 	int argc;
118 	char *argv[];
119 {
120 	int		ch;
121 	int		lflag;
122 	long	count;
123 	int		n = 1;
124 	int		script = -1;
125 	off_t	inaddr;
126 	char	*poi;
127 
128 
129 
130 #ifdef HAVE_LOCALE_H
131 	setlocale(LC_ALL, "");
132 #endif
133 	poi = strrchr(argv[0], DELIM);
134 
135 	if (poi) strncpy(progname, ++poi, 7);
136 		else strncpy(progname, argv[0], 7);
137 	strtok(progname, ".");
138 
139 	if (!strcasecmp(progname, "bview")) {
140 		params[P_RO].flags |= P_CHANGED;
141 		P(P_RO) = TRUE;
142 	} else if (!strcasecmp(progname, "bvedit")) {
143 		/* This should be the beginners version */
144 	}
145 
146 	while (n < argc) {
147 		switch (argv[n][0]) {
148 		case '-':
149 			if (argv[n][1] == 'R') {
150 				params[P_RO].flags |= P_CHANGED;
151 				P(P_RO) = TRUE;
152 			} else if (argv[n][1] == 'c') {
153 				if (argv[n + 1] == NULL) {
154 					usage();
155 				} else {
156 					strcpy(cmdstr, argv[++n]);
157 				}
158 			} else if (argv[n][1] == 'f') {
159 				if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
160 					usage();
161 				} else {
162 					script = ++n;
163 				}
164 
165 			} else if (argv[n][1] == 's') {
166 				if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
167 					usage();
168 				} else {
169 					block_begin = calc_size(argv[++n]);
170 					block_flag |= BLOCK_BEGIN;
171 				}
172 			} else if (argv[n][1] == 'e') {
173 				if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
174 					usage();
175 				} else {
176 					block_end = calc_size(argv[++n]);
177 					block_flag |= BLOCK_END;
178 				}
179 			} else if (argv[n][1] == 'n') {
180 				if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
181 					usage();
182 				} else {
183 					block_size = calc_size(argv[++n]);
184 					block_flag |= BLOCK_LEN;
185 				}
186 			} else if (argv[n][1] == 'w') {
187 				if (argv[n][2] == '\0') {
188 					usage();
189 				} else {
190 					params[P_LI].flags |= P_CHANGED;
191 					P(P_LI) = atoi(argv[n] + 2);
192 				}
193 			} else usage();
194 			n++;
195 			break;
196 		case '+':			/* +cmd */
197 			if (argv[n][1] == '\0') {
198 				strcpy(cmdstr, "$");
199 			} else {
200 				strcpy(cmdstr, &argv[n][1]);
201 			}
202 			n++;
203 			break;
204 		default:			/* must be a file name */
205 			name = strdup(argv[n]);
206 			files = &(argv[n]);
207 			numfiles = argc - n;
208 			n = argc;
209 			break;
210 		}
211 	}
212 	/* TODO default block_size - end of file up to max 64 KB with warning */
213 	switch (block_flag) {
214 	case BLOCK_BEGIN:
215 		/* Acc. to SF-Error 3036881 we should use the whole rest of the file */
216 		/*
217 		block_size = 1024;
218 		block_end = block_begin + block_size - 1;
219 		*/
220 		break;
221 	case BLOCK_END:
222 		block_begin = 0;
223 		block_size = block_end - block_begin + 1;
224 		break;
225 	case BLOCK_BEGIN|BLOCK_END:
226 		block_size = block_end - block_begin + 1;
227 		break;
228 	case BLOCK_LEN:
229 		block_begin = 0;
230 		block_end = block_begin + block_size - 1;
231 		break;
232 	case BLOCK_BEGIN|BLOCK_LEN:
233 		block_end = block_begin + block_size - 1;
234 		break;
235 	case BLOCK_END|BLOCK_LEN:
236 		block_begin = block_end + 1 - block_size;
237 		break;
238 	case BLOCK_BEGIN|BLOCK_END|BLOCK_LEN:
239 		if (block_end - block_begin != block_size + 1) {
240 			fprintf(stderr, "Ambigous block data\n");
241 			exit(1);
242 		}
243 		break;
244 	}
245 	if (block_flag && !numfiles) {
246 		fprintf(stderr, "Cannot read a range of a nonexisting file\n");
247 		exit(1);
248 	}
249 	if (numfiles > 1) fprintf(stderr, "%d files to edit\n", numfiles);
250 	curfile = 0;
251 
252 	/****** Initialisation of curses ******/
253 	initscr();
254 	attrset(A_NORMAL);
255 
256 	maxy = LINES;
257 	if (params[P_LI].flags & P_CHANGED) maxy = P(P_LI);
258 	P(P_SS) = maxy / 2;
259 	P(P_LI) = maxy;
260 	maxy--;
261 	keypad(stdscr, TRUE);
262 	scrollok(stdscr, TRUE);
263 	nonl();
264 	cbreak();
265 	noecho();
266 
267 	{
268        /* address column width */
269        /*  default is 8 + 2 blanks  */
270        /* if block_begin has 8 hex digits or more */
271        /* reserve 1 hex digit more than required  */
272        char tmp[sizeof(block_begin) * 2 + 3];
273        AnzAdd = sprintf(tmp, "%llX", (long long unsigned)block_begin) + 1;
274        if (AnzAdd < 8)
275            AnzAdd = 8;
276        if (AnzAdd > sizeof(block_begin) * 2)
277            AnzAdd = sizeof(block_begin) * 2;
278        sprintf(addr_form,  "%%0%dllX  ", AnzAdd);
279        AnzAdd = sprintf(tmp, addr_form, block_begin);
280 	}
281 
282 	Anzahl = ((COLS - AnzAdd - 1) / 16) * 4;
283 	P(P_CM) = Anzahl;
284 	maxx = Anzahl * 4 + AnzAdd + 1;
285 	Anzahl3 = Anzahl * 3;
286 	statsize = 35;
287 	status = Anzahl3 + Anzahl - statsize;
288 	screen = Anzahl * (maxy - 1);
289 
290 	signal(SIGINT, SIG_IGN);
291 	filesize = load(name);
292 
293 	bvi_init(argv[0]);
294 	params[P_TT].svalue = terminal;
295 	if (block_flag && (P(P_MM) == TRUE)) {
296 		P(P_MM) = FALSE;
297 		params[P_TT].flags |= P_CHANGED;
298 	}
299 	if (script > -1)
300 		read_rc(argv[script]);
301 	if (*cmdstr != '\0')
302 		docmdline(cmdstr);
303 
304 	/* main loop */
305 	do {
306 		setjmp(env);
307 		current = (PTR)(pagepos + y * Anzahl + xpos());
308 		if (wrstat) statpos();
309 		wrstat = 1;
310 		setcur();
311 		ch = vgetc();
312 		while (ch >= '0' && ch <= '9') {
313 			if (arrnum < MAXCMD) numarr[arrnum++] = ch;
314 			ch = vgetc();
315 		}
316 		numarr[arrnum] = '\0';
317 		if (arrnum != 0) precount = strtoll(numarr, (char **)NULL, 10);
318 			else precount = -1;
319 		lflag = arrnum = 0;
320 
321 		switch (ch) {
322 		case '^':	x = AnzAdd;
323 					loc = HEX;
324 					break;
325 		/*
326 		case '0':	x = AnzAdd + Anzahl3;
327 					loc = ASCII;
328 					break;
329 		*/
330 		case '$':	x = AnzAdd - 1 + Anzahl3 + Anzahl;
331 					loc = ASCII;
332 					break;
333 		case '\t':  toggle();
334 					break;
335 		case '~':	if (precount < 1) precount = 1;
336 					sprintf(rep_buf, "%ld~", precount);
337 					do_tilde((off_t)precount);
338 					lflag++;
339 					break;
340 		case KEY_HOME:
341 		case 'H':	if (precount > 0) {
342 						y = --precount;
343 						if (y > maxy - 1) {
344 							scrolldown(y - maxy + 1);
345 							y = maxy - 1; }
346 					} else y = 0;
347 					if (loc == HEX) x = AnzAdd;
348 						else	x = AnzAdd + Anzahl3;
349 					break;
350 		case 'M':	y = maxy / 2;
351 					if ((PTR)(pagepos + screen) > maxpos)
352 						y = (int)(maxpos - pagepos) / Anzahl / 2;
353 					if (loc == HEX) x = AnzAdd;
354 						else	x = AnzAdd + Anzahl3;
355 					break;
356 		case KEY_LL:
357 		case 'L':   if (precount < 1) precount = 1;
358 					n = maxy - 1;
359 					if ((PTR)((pagepos + screen)) > maxpos)
360 						n = (int)(maxpos - pagepos) / Anzahl;
361 					if (precount < n) y = n + 1 - precount;
362 					if (loc == HEX) x = AnzAdd;
363 						else	x = AnzAdd + Anzahl3;
364 					break;
365 		case BVICTRL('H'):
366 		case ASCII_DEL:
367 		case KEY_BACKSPACE:
368 		case KEY_LEFT:
369 		case 'h':	do {
370 						if (x > (AnzAdd + 2) && x < (Anzahl3 + AnzAdd + 1))
371 								x -= 3;
372 							else
373 								if (x > (Anzahl3 + AnzAdd - 2))  x--;
374 					} while (--precount > 0);
375 					if (x < AnzAdd + Anzahl3) loc = HEX;
376 						else loc = ASCII;
377 					break;
378 		case ' ':
379 		case KEY_RIGHT:
380 		case 'l':	do {
381 						/*
382 						if (x < (Anzahl3 + 6))  x += 3;
383 						*/
384 						if (x < (Anzahl3 + AnzAdd - 2))  x += 3;
385 							else if (x > (Anzahl3 + 3)
386 								&& x < (Anzahl3 + AnzAdd - 1 + Anzahl))
387 									x++;
388 					} while (--precount > 0);
389 					if (x < AnzAdd + Anzahl3) loc = HEX;
390 						else loc = ASCII;
391 					break;
392 		case '-':
393 		case KEY_UP :
394 		case 'k':	do {
395 						if (y > 0) y--;
396 							else scrollup(1);
397 					} while(--precount > 0);
398 					break;
399 		case '+':
400 		case CR:	if (loc == HEX) x = AnzAdd;
401 						else		x = AnzAdd + Anzahl3;
402 		case 'j':
403 		case BVICTRL('J'):
404 		case BVICTRL('N'):
405 		case KEY_DOWN:
406 					do {
407 						if ((PTR)((pagepos + (y + 1) * Anzahl)) > maxpos) break;
408 						if (y < (maxy - 1))	y++;
409 						else scrolldown(1);
410 					} while(--precount > 0);
411 					break;
412 		case '|':   if (precount < 1) break;
413 					if (loc == ASCII) x = AnzAdd - 1 + Anzahl3 + precount;
414 						else x = 5 + 3 * precount;
415 					if (x > AnzAdd - 1 + Anzahl3 + Anzahl) {
416 						x = AnzAdd - 1 + Anzahl3 + Anzahl;
417 						loc = ASCII; }
418 					break;
419 		case ':' :	clearstr();
420 					addch(ch);
421 					refresh();
422 					getcmdstr(cmdstr, 1);
423 					if (strlen(cmdstr))
424 						docmdline(cmdstr);
425 					break;
426 		case BVICTRL('B'):
427 		case KEY_PPAGE: 	/**** Previous Page ****/
428 					if (mem <= (PTR)(pagepos - screen))	pagepos -= screen;
429 						else	pagepos = mem;
430 					repaint();
431 					break;
432 		case BVICTRL('D'):
433 					if (precount > 1) P(P_SS) = precount;
434 					scrolldown(P(P_SS));
435 					break;
436 		case BVICTRL('U'):
437 					if (precount > 1) P(P_SS) = precount;
438 					scrollup(P(P_SS));
439 					break;
440 		case BVICTRL('E'):
441 					if (y > 0) y--;
442 					scrolldown(1);
443 					break;
444 		case BVICTRL('F'):
445 		case KEY_NPAGE: 	/**** Next Page *****/
446 					if (maxpos >= (PTR)(pagepos + screen))  {
447 						pagepos += screen;
448 						current += screen;
449 						if (current - mem >= filesize) {
450 							current = mem + filesize;
451 							setpage((PTR)(mem + filesize - 1L));
452 						}
453 						repaint();
454 					}
455 					break;
456 		case BVICTRL('G'):
457 					fileinfo(name);
458 					wrstat = 0;
459 					break;
460 		case BVICTRL('L'):   	/*** REDRAW SCREEN ***/
461 					new_screen();
462 					break;
463 		case BVICTRL('Y'):
464 					if (y < maxy - 1) y++;
465 					scrollup(1);
466 					break;
467 		case 'A':   smsg("APPEND MODE");
468 					current = (PTR)(mem + filesize - 1L);
469 					setpage(current++);
470 					cur_forw(0);
471 					setcur();
472 					undosize = filesize;
473 					undo_count = edit(ch);
474 					break;
475 		case 'B':
476 		case 'b':	setpage(backsearch(current, ch));
477 					break;
478 		case 'e':	setpage(end_word(current));
479 					break;
480 		case ',':	do_ft(-1, 0);
481 					break;
482 		case ';':	do_ft(0, 0);
483 					break;
484 		case 'F':
485 		case 'f':
486 		case 't':
487 		case 'T':	do_ft(ch, 0);
488 					break;
489 		case 'G':   last_motion = current;
490 					if (precount > -1)	{
491 						if ((precount < P(P_OF)) ||
492 								(precount - P(P_OF)) > (filesize - 1L)) {
493 							beep();
494 						} else {
495 							setpage((PTR)(mem + precount - P(P_OF)));
496 						}
497 					} else {
498 						setpage((PTR)(mem + filesize - 1L));
499 					}
500 					break;
501 		case 'g':	last_motion = current;
502 					clearstr();
503 					outmsg("Goto Hex Address:");
504 					refresh();
505 					getcmdstr(cmdstr, 18);
506 					clearstr();
507 					if (cmdstr[0] == '^') {
508 						inaddr = P(P_OF);
509 					} else if (cmdstr[0] == '$') {
510 						inaddr = filesize + P(P_OF) - 1L;
511 					} else {
512 						off_t ltmp;
513 						sscanf(cmdstr, "%llx", (long long unsigned *)&ltmp);
514 						inaddr = ltmp;
515 					}
516 					if (inaddr < P(P_OF)) break;
517 					inaddr -= P(P_OF);
518 					if (inaddr < filesize)  {
519 						setpage(mem + inaddr);
520 					} else {
521 						if (filesize == 0L) break;
522 						sprintf(string, "Max. address of current file : %06llX", (long long unsigned)(filesize - 1L + P(P_OF)));
523 						emsg(string);
524 					}
525 					break;
526 		case '?':
527 		case '/':	/**** Search String ****/
528 		case '#':
529 		case '\\':  clearstr();
530 					addch(ch);
531 					refresh();
532 					if (getcmdstr(line, 1)) break;
533 					last_motion = current;
534 					hl_spat = P(P_HL);
535 					searching(ch, line, current, maxpos - 1, P(P_WS));
536 					if (hl_spat) {
537 						repaint();
538 					}
539 					break;
540 		case ESC:		/* un-highlight */
541 					hl_spat = FALSE;
542 					repaint();
543 					break;
544 		case 'n': 		/**** Search Next ****/
545 		case 'N':   last_motion = current;
546 					hl_spat = P(P_HL);
547 					searching(ch, "", current, maxpos - 1, P(P_WS));
548 					if (hl_spat) {
549 						repaint();
550 					}
551 					break;
552 		case 'm':	do_mark(vgetc(), current);
553 					break;
554 		case '\'':
555 		case '`':   if ((ch == '`' && loc == ASCII) ||
556 									(ch == '\'' && loc == HEX))
557 						toggle();
558 					mark = vgetc();
559 					if (mark == '`' || mark == '\'') {
560 						setpage(last_motion);
561 						last_motion = current;
562 					} else {
563 						if (mark < 'a' || mark > 'z') {
564 							beep(); break;
565 						} else if (markbuf[mark - 'a'] == NULL) {
566 								beep(); break;
567 						}
568 						setpage(markbuf[mark - 'a']);
569 					}
570 					break;
571 		case 'D':	if (precount < 1) precount = 1;
572 					sprintf(rep_buf, "%ldD", precount);
573 					trunc_cur();
574 					break;
575 		case 'o':	/* overwrite: this is an overwriting put */
576 					if (precount < 1) precount = 1;
577 					sprintf(rep_buf, "%ldo", precount);
578 					do_over(current, yanked, yank_buf);
579 					break;
580 		case 'P':
581 					if (precount < 1) precount = 1;
582 					if ((undo_count = alloc_buf(yanked, &undo_buf)) == 0L)
583 						break;
584 					sprintf(rep_buf, "%ldP", precount);
585 					if (do_append((off_t)yanked, yank_buf)) break;
586 					/* we save it not for undo but for the dot command
587 					memcpy(undo_buf, yank_buf, yanked);
588 					*/
589 					repaint();
590 					break;
591 		case 'r':
592 		case 'R':   if (filesize == 0L) break;
593 					if (precount < 1) precount = 1;
594 					sprintf(rep_buf, "%ld%c", precount, ch);
595 					undo_count = edit(ch);
596 					lflag++;
597 					break;
598 		case 'u':	do_undo();
599 					break;
600 		case 'W':
601 		case 'w':	// loc = ASCII;
602 					setpage(wordsearch(current, ch));
603 					break;
604 		case 'y':	count = range(ch);
605 					if (count > 0) {
606 /*
607   sprintf(string, "$%ld$", (long)yanked);
608   msg(string);
609   vgetc();
610 */
611 						if ((yanked = alloc_buf((off_t)count, &yank_buf)) == 0L) {
612 							break;
613 						}
614 						memcpy(yank_buf, current, yanked);
615 					} else if (count < 0) {
616 						if ((yanked = alloc_buf(-(off_t)count, &yank_buf)) == 0L) {
617 							break;
618 						}
619 						memcpy(yank_buf, current, yanked);
620 					} else {
621 						break;
622 					}
623 /*
624 					sprintf(string, "%ld bytes yanked", labs(count));
625 					msg(string);
626 */
627 					break;
628 		case 'z':	do_z(vgetc());
629 					break;
630 		case 'Z':   if (vgetc() == 'Z') do_exit();
631 						else beep();
632 					break;
633 		case '.':
634 					if (!strlen(rep_buf)) {
635 						beep();
636 					} else {
637 						stuffin(rep_buf);
638 					}
639 					break;
640 		default :
641 			if P(P_MM) {
642 				if (precount < 1) precount = 1;
643 				switch (ch) {
644 				case 'I':
645 					sprintf(rep_buf, "%ldI", precount);
646 					current = mem;
647 					setpage(mem);
648 					repaint();
649 					undo_count = edit('i');
650 					lflag++;
651 					break;
652 /* undo does not work correctly !!! */
653 				case 's':
654 					sprintf(rep_buf, "%lds", precount);
655 					if (do_delete((off_t)precount, current)) break;
656 					precount = 1;
657 					undo_count = edit('i');
658 					lflag++;
659 					break;
660 				case 'a':
661 					if (cur_forw(1)) break;
662 					current++;
663 				case 'i':
664 					sprintf(rep_buf, "%ld%c", precount, ch);
665 					undo_count = edit(ch);
666 					lflag++;
667 					break;
668 				case 'p':
669 					sprintf(rep_buf, "%ldp", precount);
670 					do_put(current, yanked, yank_buf);
671 					break;
672 				case 'c':
673 				case 'd':
674 					count = range(ch);
675 					if (count > 0)
676 						do_delete((off_t)count, current);
677 					else if (count < 0)
678 						do_back(-(off_t)count, current);
679 					if (ch == 'c') {
680 						precount = 1;
681 						undo_count = edit('i');
682 						lflag++;
683 					}
684 					break;
685 				case 'x':
686 					sprintf(rep_buf, "%ldx", precount);
687 					do_delete((off_t)precount, current);
688 					break;
689 				case 'X':
690 					sprintf(rep_buf, "%ldX", precount);
691 					do_back((off_t)precount, current);
692 					break;
693 				default:
694 					flushinp();
695 					beep();
696 				}
697 			} else {
698 				switch (ch) {
699 				case 'x':
700 					if (precount < 1) precount = 1;
701 					if ((off_t)precount + current == maxpos) {
702 						sprintf(rep_buf, "%ldx", precount);
703 						do_delete((off_t)precount, current);
704 					} else {
705 						movebyte();
706 						flushinp();
707 						beep();
708 					}
709 					break;
710 				case 'd':
711 				case 'i':
712 				case 'I':
713 				case 'p':
714 				case 'X':
715 					movebyte();
716 				default:
717 					flushinp();
718 					beep();
719 				}
720 			}
721 		}
722 		if (lflag) lineout();
723 	} while (1);
724 }
725 
726 
727 off_t
calc_size(arg)728 calc_size(arg)
729 	char	*arg;
730 {
731 	off_t	val;
732 	extern int errno;
733 	char	*poi;
734 
735 	errno = 0;
736 	val = strtoll(arg, &poi, 0);
737 	if (val < 0) {
738 		fprintf(stderr, "negative begin/size/end not allowed\n");
739 		usage();
740 	}
741 	if (poi == arg || errno != 0) {
742 		/* cygwin gdb displays errno incorrectly as 0 */
743 		fprintf(stderr, "invalid begin/size/end (hex nr 0x#, octal 0#)\n");
744 		usage();
745 	}
746 	switch (*poi) {
747 	case 'k':
748 	case 'K':	val *= 1024;
749 			 	break;
750 	case 'm':
751 	case 'M':	val *= 1048576;
752 			 	break;
753 	case 'g':
754 	case 'G':   val *= 1024*1024*1024LL;
755 				break;
756 	case '\0':	break;
757 	default:	usage();
758 	}
759 	return (off_t)val;
760 }
761 
762 
763 void
trunc_cur()764 trunc_cur()
765 {
766 	undosize = filesize;
767 	undo_count = (off_t)(maxpos - current);
768 	undo_start = current;
769 	filesize = pagepos - mem + y * Anzahl + xpos();
770 	maxpos = (PTR)(mem + filesize);
771 	if (filesize == 0L) {
772 		emsg(nobytes);
773 	} else	cur_back();
774 	edits = U_TRUNC;
775 	repaint();
776 }
777 
778 
779 int
do_append(count,buf)780 do_append(count, buf)
781 	off_t	count;
782 	char	*buf;
783 {
784 	if (filesize + count > memsize) {
785 		if (enlarge(count + 100L)) return 1;
786 	}
787 	memcpy(mem + filesize, buf, count);
788 	undo_start = mem + filesize - 1L;
789 	setpage(undo_start + count);
790 	edits = U_APPEND;
791 	undosize = filesize;
792 	filesize += count;
793 	maxpos += count;
794 	return 0;
795 }
796 
797 
798 void
do_tilde(count)799 do_tilde(count)
800 	off_t	count;
801 {
802 	if (filesize == 0L) return;
803 	undo_start = current;
804 	if (current + count > maxpos) {
805 		beep();
806 		return;
807 	}
808 	if ((undo_count = alloc_buf(count, &undo_buf)) == 0L)
809 		return;
810 	memcpy(undo_buf, current, undo_count);
811 	while (count--) {
812 		if (isupper((int)(*current))) *current = tolower((int)(*current));
813 			else if (islower((int)(*current)))
814 				*current = toupper((int)(*current));
815 		current++;
816 		cur_forw(0);
817 	}
818 	edits = U_TILDE;
819 	setcur();
820 }
821 
822 
823 void
do_undo()824 do_undo()
825 {
826 	off_t	n, tempsize;
827 	char	temp;
828 	PTR		set_cursor;
829 	PTR		s;
830 	PTR		d;
831 
832 	if (undo_count == 0L) {
833 		emsg("Nothing to undo");
834 		return;
835 	}
836 	set_cursor = undo_start;
837 	switch (edits) {
838 		case U_EDIT:
839 		case U_TILDE:
840 			n = undo_count;
841 			s = undo_buf;
842 			d = undo_start;
843 			while (n--) {
844 				temp = *d;
845 				*d = *s;
846 				*s = temp;
847 				s++; d++;
848 			}
849 			break;
850 		case U_APPEND:
851 		case U_TRUNC:
852 			tempsize = filesize;
853 			filesize = undosize;
854 			undosize = tempsize;
855 			maxpos = (PTR)(mem + filesize);
856 			if (filesize)
857 				set_cursor = maxpos - 1L;
858 			else
859 				set_cursor = maxpos;
860 			break;
861 		case U_INSERT:
862 			filesize -= undo_count;
863 			maxpos -= undo_count;
864 			memcpy(undo_buf, undo_start, undo_count);
865 			memmove(undo_start, undo_start + undo_count,
866 				maxpos - undo_start);
867 			edits = U_DELETE;
868 			break;
869 		case U_BACK:
870 		case U_DELETE:
871 			filesize += undo_count;
872 			maxpos += undo_count;
873 			memmove(undo_start + undo_count, undo_start,
874 				maxpos - undo_start);
875 			memcpy(undo_start, undo_buf, undo_count);
876 			edits = U_INSERT;
877 			break;
878 		}
879 		setpage(set_cursor);
880 		if (edits == U_TRUNC && undosize > filesize) cur_back();
881 		repaint();
882 }
883 
884 
885 void
do_over(loc,n,buf)886 do_over(loc, n, buf)
887 	PTR		loc;
888 	off_t	n;
889 	PTR		buf;
890 {
891 	if (n < 1L) {
892 		emsg(nobytes);
893 		return;
894 	}
895 	if (loc + n > maxpos) {
896 		beep();
897 		return;
898 	}
899 	if ((undo_count = alloc_buf(n, &undo_buf)) == 0L)
900 		return;
901 	undo_start = loc;
902 	memcpy(undo_buf, loc, n);
903 	memcpy(loc, buf, n);
904 	edits = U_EDIT;
905 	setpage(loc + n - 1);
906 	repaint();
907 }
908 
909 
910 void
do_put(loc,n,buf)911 do_put(loc, n, buf)
912 	PTR		loc;
913 	off_t	n;
914 	PTR		buf;
915 {
916 	if (n < 1L) {
917 		emsg(nobytes);
918 		return;
919 	}
920 	if (loc > maxpos) {
921 		beep();
922 		return;
923 	}
924 	if (filesize + n > memsize) {
925 		if (enlarge(n + 1024)) return;
926 	}
927 	if ((undo_count = alloc_buf(n, &undo_buf)) == 0L)
928 		return;
929 	undo_start = loc + 1;
930 	edits = U_INSERT;
931 	filesize += n;
932 	maxpos += n;
933 	memmove(undo_start + n, undo_start, maxpos - loc);
934 	memcpy(undo_start, buf, n);
935 	setpage(loc + n);
936 	repaint();
937 }
938 
939 
940 /* argument sig not used, because only SIGINT will be catched */
941 void
jmpproc(sig)942 jmpproc(sig)
943 	int	sig;
944 {
945 	if (P(P_EB)) beep();
946 	repaint();
947 	clearstr();
948     signal(SIGINT, SIG_IGN);
949     longjmp(env, 0);
950 }
951 
952 
953 off_t
range(ch)954 range(ch)
955 	int		ch;
956 {
957 	int		ch1;
958 	long	count;
959 
960 	ch1 = vgetc();
961 	while (ch1 >= '0' && ch1 <= '9') {
962 		numarr[arrnum++] = ch1;
963 		ch1 = vgetc();
964 	}
965 	numarr[arrnum] = '\0';
966 	if (arrnum != 0) count = strtol(numarr, (char **)NULL, 10);
967 		else count = 1;
968 	arrnum = 0;
969 	sprintf(rep_buf, "%ld%c%s%c", precount, ch, numarr, ch1);
970 	switch (ch1) {
971 	case '/':	/**** Search String ****/
972 	case '\\':
973 		strcat(rep_buf, "\n");
974 		clearstr();
975 		addch(ch1);
976 		refresh();
977 		if (getcmdstr(line, 1)) break;
978 		end_addr = searching(ch1, line, current, maxpos - 1, FALSE);
979 		if (!end_addr) {
980 			beep();
981 			return 0;
982 		}
983 		return(end_addr - current);
984 	case '?':
985 	case '#':
986 		strcat(rep_buf, "\n");
987 		clearstr();
988 		addch(ch1);
989 		refresh();
990 		if (getcmdstr(line, 1)) break;
991 		start_addr = searching(ch1, line, current, maxpos - 1, FALSE);
992 		if (!start_addr) {
993 			beep();
994 			return 0;
995 		}
996 		return(start_addr - current);
997 	case 'f':
998 	case 't':
999 		precount = count;
1000 		end_addr = do_ft(ch1, 1);
1001 		if (!end_addr) {
1002 			beep();
1003 			return 0;
1004 		}
1005 		return (end_addr + 1 - current);
1006 	case 'F':
1007 	case 'T':
1008 		precount = count;
1009 		start_addr = do_ft(ch1, 1);
1010 		if (!start_addr) {
1011 			beep();
1012 			return 0;
1013 		}
1014 		return (start_addr - current);
1015 	case '$':
1016 		trunc_cur();
1017 		return 0;
1018 	case 'G':
1019 		if (count == -1) {
1020 			trunc_cur();
1021 			return 0;
1022 		} else if ((count < P(P_OF)) || (count
1023 				- (off_t)P(P_OF)) > (filesize - 1L)) {
1024 			beep();
1025 			return 0;
1026 		} else {
1027 			if (mem + count < current) {
1028 				return(mem + count - current);
1029 			} else {
1030 				return(count - (current - mem));
1031 			}
1032 		}
1033 	case ' ':
1034 		return precount;
1035 	case '`':
1036 	case '\'':
1037 		mark = vgetc();
1038 		if (mark < 'a' || mark > 'z') {
1039 			beep();
1040 			return 0;
1041 		}
1042 		end_addr = markbuf[mark - 'a'];
1043 		if (end_addr == NULL) {
1044 	        beep();
1045 			return 0;
1046 	    }
1047 		if (end_addr < current) {
1048 			return(end_addr - current);
1049 		} else {
1050 			return(end_addr - current + 1);
1051 		}
1052 	}
1053 	beep();
1054 	return 0;
1055 }
1056