Tweak was incorrectly handling the terminal default colour scheme.
[sgt/tweak] / actions.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 #include "tweak.h"
7
8 static void act_exit (void);
9 static void act_save (void);
10 static void act_exitsave (void);
11 static void act_top (void);
12 static void act_pgup (void);
13 static void act_up (void);
14 static void act_home (void);
15 static void act_left (void);
16 static void act_right (void);
17 static void act_end (void);
18 static void act_down (void);
19 static void act_pgdn (void);
20 static void act_bottom (void);
21 static void act_togins (void);
22 static void act_chmode (void);
23 extern void act_self_ins (void); /* this one must be external */
24 static void act_delete (void);
25 static void act_delch (void);
26 static void act_mark (void);
27 static void act_cut (void);
28 static void act_copy (void);
29 static void act_paste (void);
30 static void act_susp (void);
31 static void act_goto (void);
32 static void act_togstat (void);
33 static void act_search (void);
34 static void act_search_backwards (void);
35 static void act_recentre (void);
36 static void act_width (void);
37 static void act_offset (void);
38 #ifdef TEST_BUFFER
39 static void act_diagnostics (void);
40 #endif
41
42 static Search *last_search = NULL;
43
44 keyact parse_action (char *name) {
45 char *names[] = {
46 "exit", "top-of-file", "page-up", "move-up",
47 "begin-line", "move-left", "move-right", "end-line",
48 "move-down", "page-down", "bottom-of-file", "toggle-insert",
49 "change-mode", "delete-left", "delete-right", "mark-place",
50 "cut", "copy", "paste", "suspend", "goto-position",
51 "toggle-status", "search", "search-back", "save-file",
52 "exit-and-save", "screen-recentre", "new-width", "new-offset"
53 #ifdef TEST_BUFFER
54 , "diagnostics"
55 #endif
56 };
57 keyact actions[] = {
58 act_exit, act_top, act_pgup, act_up, act_home, act_left,
59 act_right, act_end, act_down, act_pgdn, act_bottom,
60 act_togins, act_chmode, act_delete, act_delch, act_mark,
61 act_cut, act_copy, act_paste, act_susp, act_goto,
62 act_togstat, act_search, act_search_backwards, act_save,
63 act_exitsave, act_recentre, act_width, act_offset
64 #ifdef TEST_BUFFER
65 , act_diagnostics
66 #endif
67 };
68 int i;
69
70 for (i=0; i<sizeof(names)/sizeof(*names); i++)
71 if (!strcmp(name, names[i]))
72 return actions[i];
73 return NULL;
74 }
75
76 static int begline(int x) {
77 int y = x + width-offset;
78 y -= (y % width);
79 y -= width-offset;
80 if (y < 0)
81 y = 0;
82 return y;
83 }
84
85 static int endline(int x) {
86 int y = x + width-offset;
87 y -= (y % width);
88 y += width-1;
89 y -= width-offset;
90 if (y < 0)
91 y = 0;
92 return y;
93 }
94
95 static void act_exit(void) {
96 static char question[] = "File is modified. Save before quitting? [yn] ";
97 if (modified) {
98 int c;
99
100 display_moveto (display_rows-1, 0);
101 display_clear_to_eol ();
102 display_set_colour (COL_MINIBUF);
103 display_write_str (question);
104 display_refresh();
105 do {
106 #if defined(unix) && !defined(GO32)
107 if (update_required) {
108 update();
109 display_moveto (display_rows-1, 0);
110 display_clear_to_eol ();
111 display_set_colour (COL_MINIBUF);
112 display_write_str (question);
113 display_refresh();
114 }
115 safe_update = TRUE;
116 #endif
117 c = display_getkey();
118 #if defined(unix) && !defined(GO32)
119 safe_update = FALSE;
120 #endif
121 if (c >= 'a' && c <= 'z')
122 c += 'A'-'a';
123 } while (c != 'Y' && c != 'N' && c != '\007');
124 if (c == 'Y') {
125 act_save();
126 if (modified)
127 return; /* couldn't save, so don't quit */
128 draw_scr(); /* update the ** on status line! */
129 } else if (c == '\007') {
130 return; /* don't even quit */
131 }
132 }
133 finished = TRUE;
134 }
135
136 static void act_save(void) {
137 static int backed_up = FALSE;
138
139 if (!backed_up) {
140 if (!backup_file()) {
141 display_beep();
142 strcpy (message, "Unable to back up file!");
143 return;
144 }
145 backed_up = TRUE;
146 }
147 if (!save_file()) {
148 display_beep();
149 strcpy (message, "Unable to save file!");
150 return;
151 }
152 modified = FALSE;
153 }
154
155 static void act_exitsave(void) {
156 act_save();
157 draw_scr(); /* update ** on status line */
158 act_exit();
159 }
160
161 static void act_top (void) {
162 cur_pos = top_pos = 0;
163 edit_type = !!edit_type;
164 }
165
166 static void act_pgup(void) {
167 cur_pos -= (scrlines-1)*width;
168 if (cur_pos < 0) {
169 cur_pos = 0;
170 edit_type = !!edit_type;
171 }
172 if (top_pos > cur_pos)
173 top_pos = begline(cur_pos);
174 }
175
176 static void act_up(void) {
177 cur_pos -= width;
178 if (cur_pos < 0) {
179 cur_pos = 0;
180 edit_type = !!edit_type;
181 }
182 if (top_pos > cur_pos)
183 top_pos = begline(cur_pos);
184 }
185
186 static void act_home(void) {
187 cur_pos = begline(cur_pos);
188 if (cur_pos < 0)
189 cur_pos = 0;
190 if (top_pos > cur_pos)
191 top_pos = begline(cur_pos);
192 edit_type = !!edit_type;
193 }
194
195 static void act_left(void) {
196 if (edit_type == 2) {
197 edit_type = 1;
198 return;
199 } else {
200 cur_pos--;
201 edit_type = 2*!!edit_type;
202 if (cur_pos < 0) {
203 cur_pos = 0;
204 edit_type = !!edit_type;
205 }
206 if (top_pos > cur_pos)
207 top_pos = begline(cur_pos);
208 }
209 }
210
211 static void act_right(void) {
212 int new_top;
213
214 if (edit_type == 1) {
215 if (cur_pos < file_size)
216 edit_type = 2;
217 return;
218 } else {
219 cur_pos++;
220 if (cur_pos > file_size)
221 cur_pos = file_size;
222 new_top = cur_pos - (scrlines-1) * width;
223 if (new_top < 0)
224 new_top = 0;
225 new_top = begline(new_top);
226 if (top_pos < new_top)
227 top_pos = new_top;
228 edit_type = !!edit_type;
229 }
230 }
231
232 static void act_end(void) {
233 int new_top;
234
235 cur_pos = endline(cur_pos);
236 edit_type = !!edit_type;
237 if (cur_pos >= file_size)
238 cur_pos = file_size;
239 new_top = cur_pos - (scrlines-1) * width;
240 if (new_top < 0)
241 new_top = 0;
242 new_top = begline(new_top);
243 if (top_pos < new_top)
244 top_pos = new_top;
245 }
246
247 static void act_down(void) {
248 int new_top;
249
250 cur_pos += width;
251 if (cur_pos >= file_size) {
252 cur_pos = file_size;
253 edit_type = !!edit_type;
254 }
255 new_top = cur_pos - (scrlines-1) * width;
256 if (new_top < 0)
257 new_top = 0;
258 new_top = begline(new_top);
259 if (top_pos < new_top)
260 top_pos = new_top;
261 }
262
263 static void act_pgdn(void) {
264 int new_top;
265
266 cur_pos += (scrlines-1) * width;
267 if (cur_pos >= file_size) {
268 cur_pos = file_size;
269 edit_type = !!edit_type;
270 }
271 new_top = cur_pos - (scrlines-1) * width;
272 if (new_top < 0)
273 new_top = 0;
274 new_top = begline(new_top);
275 if (top_pos < new_top)
276 top_pos = new_top;
277 }
278
279 static void act_bottom (void) {
280 int new_top;
281
282 cur_pos = file_size;
283 edit_type = !!edit_type;
284 new_top = cur_pos - (scrlines-1) * width;
285 if (new_top < 0)
286 new_top = 0;
287 new_top = begline(new_top);
288 if (top_pos < new_top)
289 top_pos = new_top;
290 }
291
292 static void act_togins(void) {
293 if (look_mode || fix_mode) {
294 display_beep();
295 sprintf(message, "Can't engage Insert mode when in %s mode",
296 (look_mode ? "LOOK" : "FIX"));
297 insert_mode = FALSE; /* safety! */
298 } else
299 insert_mode = !insert_mode;
300 }
301
302 static void act_chmode(void) {
303 if (ascii_enabled)
304 edit_type = !edit_type; /* 0 -> 1, [12] -> 0 */
305 else if (edit_type == 0) /* just in case */
306 edit_type = 1;
307 }
308
309 void act_self_ins(void) {
310 int insert = insert_mode;
311 unsigned char c;
312
313 if (look_mode) {
314 display_beep();
315 strcpy (message, "Can't modify file in LOOK mode");
316 return;
317 }
318
319 if (edit_type) {
320 if (last_char >= '0' && last_char <= '9')
321 last_char -= '0';
322 else if (last_char >= 'A' && last_char <= 'F')
323 last_char -= 'A'-10;
324 else if (last_char >= 'a' && last_char <= 'f')
325 last_char -= 'a'-10;
326 else {
327 display_beep();
328 strcpy(message, "Not a valid character when in hex editing mode");
329 return;
330 }
331 }
332
333 if ( (!insert || edit_type == 2) && cur_pos == file_size) {
334 display_beep();
335 strcpy(message, "End of file reached");
336 return;
337 }
338
339 switch (edit_type) {
340 case 0: /* ascii mode */
341 c = last_char;
342 break;
343 case 1: /* hex, first digit */
344 if (insert)
345 c = 0;
346 else
347 buf_fetch_data(filedata, &c, 1, cur_pos);
348 c &= 0xF;
349 c |= 16 * last_char;
350 break;
351 case 2: /* hex, second digit */
352 buf_fetch_data(filedata, &c, 1, cur_pos);
353 c &= 0xF0;
354 c |= last_char;
355 insert = FALSE;
356 break;
357 }
358
359 if (insert) {
360 buf_insert_data(filedata, &c, 1, cur_pos);
361 file_size++;
362 modified = TRUE;
363 } else if (cur_pos < file_size) {
364 buf_overwrite_data(filedata, &c, 1, cur_pos);
365 modified = TRUE;
366 } else {
367 display_beep();
368 strcpy(message, "End of file reached");
369 }
370 act_right();
371 }
372
373 static void act_delete(void) {
374 if (!insert_mode || (edit_type!=2 && cur_pos==0)) {
375 display_beep();
376 strcpy (message, "Can't delete while not in Insert mode");
377 } else if (cur_pos > 0 || edit_type == 2) {
378 act_left();
379 buf_delete (filedata, 1, cur_pos);
380 file_size--;
381 edit_type = !!edit_type;
382 modified = TRUE;
383 }
384 }
385
386 static void act_delch(void) {
387 if (!insert_mode) {
388 display_beep();
389 strcpy (message, "Can't delete while not in Insert mode");
390 } else if (cur_pos < file_size) {
391 buf_delete (filedata, 1, cur_pos);
392 file_size--;
393 edit_type = !!edit_type;
394 modified = TRUE;
395 }
396 }
397
398 static void act_mark (void) {
399 if (look_mode) {
400 display_beep();
401 strcpy (message, "Can't cut or paste in LOOK mode");
402 marking = FALSE; /* safety */
403 return;
404 }
405 marking = !marking;
406 mark_point = cur_pos;
407 }
408
409 static void act_cut (void) {
410 long marktop, marksize;
411
412 if (!marking || mark_point==cur_pos) {
413 display_beep();
414 strcpy (message, "Set mark first");
415 return;
416 }
417 if (!insert_mode) {
418 display_beep();
419 strcpy (message, "Can't cut while not in Insert mode");
420 return;
421 }
422 marktop = cur_pos;
423 marksize = mark_point - cur_pos;
424 if (marksize < 0) {
425 marktop += marksize;
426 marksize = -marksize;
427 }
428 if (cutbuffer)
429 buf_free (cutbuffer);
430 cutbuffer = buf_cut (filedata, marksize, marktop);
431 file_size -= marksize;
432 cur_pos = marktop;
433 if (cur_pos < 0)
434 cur_pos = 0;
435 if (top_pos > cur_pos)
436 top_pos = begline(cur_pos);
437 edit_type = !!edit_type;
438 modified = TRUE;
439 marking = FALSE;
440 }
441
442 static void act_copy (void) {
443 int marktop, marksize;
444
445 if (!marking) {
446 display_beep();
447 strcpy (message, "Set mark first");
448 return;
449 }
450 marktop = cur_pos;
451 marksize = mark_point - cur_pos;
452 if (marksize < 0) {
453 marktop += marksize;
454 marksize = -marksize;
455 }
456 if (cutbuffer)
457 buf_free (cutbuffer);
458 cutbuffer = buf_copy (filedata, marksize, marktop);
459 marking = FALSE;
460 }
461
462 static void act_paste (void) {
463 int cutsize, new_top;
464
465 cutsize = buf_length (cutbuffer);
466 if (!insert_mode) {
467 if (cur_pos + cutsize > file_size) {
468 display_beep();
469 strcpy (message, "Too close to end of file to paste");
470 return;
471 }
472 buf_delete (filedata, cutsize, cur_pos);
473 file_size -= cutsize;
474 }
475 buf_paste (filedata, cutbuffer, cur_pos);
476 modified = TRUE;
477 cur_pos += cutsize;
478 file_size += cutsize;
479 edit_type = !!edit_type;
480 new_top = cur_pos - (scrlines-1) * width;
481 if (new_top < 0)
482 new_top = 0;
483 new_top = begline(new_top);
484 if (top_pos < new_top)
485 top_pos = new_top;
486 }
487
488 static void act_susp (void) {
489 suspend();
490 }
491
492 static void act_goto (void) {
493 char buffer[80];
494 long position, new_top;
495 int error;
496
497 if (!get_str("Enter position to go to: ", buffer, FALSE))
498 return; /* user break */
499
500 position = parse_num (buffer, &error);
501 if (error) {
502 display_beep();
503 strcpy (message, "Unable to parse position value");
504 return;
505 }
506
507 if (position < 0 || position > file_size) {
508 display_beep();
509 strcpy (message, "Position is outside bounds of file");
510 return;
511 }
512
513 cur_pos = position;
514 edit_type = !!edit_type;
515 new_top = cur_pos - (scrlines-1) * width;
516 if (new_top < 0)
517 new_top = 0;
518 new_top = begline(new_top);
519 if (top_pos > cur_pos)
520 top_pos = begline(cur_pos);
521 if (top_pos < new_top)
522 top_pos = new_top;
523 }
524
525 static void act_togstat (void) {
526 if (statfmt == decstatus)
527 statfmt = hexstatus;
528 else
529 statfmt = decstatus;
530 }
531
532 static int search_prompt(char *withdef, char *withoutdef)
533 {
534 char buffer[80];
535 int len;
536
537 if (!get_str(last_search ? withdef : withoutdef, buffer, TRUE))
538 return 0; /* user break */
539 if (!last_search && !*buffer) {
540 strcpy (message, "Search aborted.");
541 return 0;
542 }
543
544 if (!*buffer) {
545 len = last_search->len;
546 } else {
547 len = parse_quoted (buffer);
548 if (len == -1) {
549 display_beep();
550 strcpy (message, "Invalid escape sequence in search string");
551 return 0;
552 }
553 if (last_search)
554 free_search(last_search);
555 last_search = build_search (buffer, len);
556 }
557
558 return 1;
559 }
560
561 static void act_search (void) {
562 int len, posn, dfapos;
563 DFA dfa;
564 static unsigned char sblk[SEARCH_BLK];
565 static char withdef[] = "Search forward (default=last): ";
566 static char withoutdef[] = "Search forward: ";
567
568 if (!search_prompt(withdef, withoutdef))
569 return;
570
571 dfa = last_search->forward;
572 len = last_search->len;
573 dfapos = 0;
574
575 for (posn = cur_pos+1; posn < file_size; posn++) {
576 unsigned char *q;
577 int size = SEARCH_BLK;
578
579 if (size > file_size-posn)
580 size = file_size-posn;
581 buf_fetch_data (filedata, sblk, size, posn);
582 q = sblk;
583 while (size--) {
584 posn++;
585 dfapos = dfa[dfapos][*q++];
586 if (dfapos == len) {
587 int new_top;
588
589 cur_pos = posn - len;
590 edit_type = !!edit_type;
591 new_top = cur_pos - (scrlines-1) * width;
592 new_top = begline(new_top);
593 if (top_pos < new_top)
594 top_pos = new_top;
595 return;
596 }
597 }
598 }
599 strcpy (message, "Not found.");
600 }
601
602 static void act_search_backwards (void) {
603 int len, posn, dfapos;
604 DFA dfa;
605 static unsigned char sblk[SEARCH_BLK];
606 static char withdef[] = "Search backward (default=last): ";
607 static char withoutdef[] = "Search backward: ";
608
609 if (!search_prompt(withdef, withoutdef))
610 return;
611
612 dfa = last_search->reverse;
613 len = last_search->len;
614 dfapos = 0;
615
616 posn = cur_pos + len - 1;
617 if (posn >= file_size)
618 posn = file_size;
619
620 for (; posn >= 0; posn--) {
621 unsigned char *q;
622 int size = SEARCH_BLK;
623
624 if (size > posn)
625 size = posn;
626 buf_fetch_data (filedata, sblk, size, posn-size);
627 q = sblk + size;
628 while (size--) {
629 posn--;
630 dfapos = dfa[dfapos][*--q];
631 if (dfapos == len) {
632 int new_top;
633
634 cur_pos = posn;
635 edit_type = !!edit_type;
636 new_top = cur_pos - (scrlines-1) * width;
637 new_top = begline(new_top);
638 if (top_pos > new_top)
639 top_pos = new_top;
640 return;
641 }
642 }
643 }
644 strcpy (message, "Not found.");
645 }
646
647 static void act_recentre (void) {
648 top_pos = cur_pos - (display_rows-2)/2 * width;
649 if (top_pos < 0)
650 top_pos = 0;
651 top_pos = begline(top_pos);
652 }
653
654 static void act_width (void) {
655 char buffer[80];
656 char prompt[80];
657 long w;
658 long new_top;
659 int error;
660
661 sprintf (prompt, "Enter screen width in bytes (now %d): ", width);
662 if (!get_str (prompt, buffer, FALSE))
663 return;
664 w = parse_num (buffer, &error);
665 if (error) {
666 display_beep();
667 strcpy (message, "Unable to parse width value");
668 return;
669 }
670 if (w > 0) {
671 width = w;
672 fix_offset();
673 new_top = cur_pos - (scrlines-1) * width;
674 new_top = begline(new_top);
675 if (top_pos < new_top)
676 top_pos = new_top;
677 }
678 }
679
680 static void act_offset (void) {
681 char buffer[80];
682 char prompt[80];
683 long o;
684 long new_top;
685 int error;
686
687 sprintf (prompt, "Enter start-of-file offset in bytes (now %d): ",
688 realoffset);
689 if (!get_str (prompt, buffer, FALSE))
690 return;
691 o = parse_num (buffer, &error);
692 if (error) {
693 display_beep();
694 strcpy (message, "Unable to parse offset value");
695 return;
696 }
697 if (o >= 0) {
698 realoffset = o;
699 fix_offset();
700 new_top = cur_pos - (scrlines-1) * width;
701 new_top = begline(new_top);
702 if (top_pos < new_top)
703 top_pos = new_top;
704 }
705 }
706
707 #ifdef TEST_BUFFER
708 static void act_diagnostics(void)
709 {
710 extern void buffer_diagnostic(buffer *buf, char *title);
711
712 buffer_diagnostic(filedata, "filedata");
713 buffer_diagnostic(cutbuffer, "cutbuffer");
714 }
715 #endif