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 *)<mp);
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