Increase the size of the 'message' buffer, which is currently
[sgt/tweak] / actions.c
1 #include "tweak.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.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 fileoffset_t begline(fileoffset_t x) {
77 fileoffset_t 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 fileoffset_t endline(fileoffset_t x) {
86 fileoffset_t 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 fileoffset_t 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 fileoffset_t 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 fileoffset_t 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 fileoffset_t 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 fileoffset_t 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 fileoffset_t 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 fileoffset_t 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 fileoffset_t cutsize, new_top;
464
465 if (!cutbuffer)
466 return;
467 cutsize = buf_length (cutbuffer);
468 if (!insert_mode) {
469 if (cur_pos + cutsize > file_size) {
470 display_beep();
471 strcpy (message, "Too close to end of file to paste");
472 return;
473 }
474 buf_delete (filedata, cutsize, cur_pos);
475 file_size -= cutsize;
476 }
477 buf_paste (filedata, cutbuffer, cur_pos);
478 modified = TRUE;
479 cur_pos += cutsize;
480 file_size += cutsize;
481 edit_type = !!edit_type;
482 new_top = cur_pos - (scrlines-1) * width;
483 if (new_top < 0)
484 new_top = 0;
485 new_top = begline(new_top);
486 if (top_pos < new_top)
487 top_pos = new_top;
488 }
489
490 static void act_susp (void) {
491 suspend();
492 }
493
494 static void act_goto (void) {
495 char buffer[80];
496 fileoffset_t position, new_top;
497 int error;
498
499 if (!get_str("Enter position to go to: ", buffer, FALSE))
500 return; /* user break */
501
502 position = parse_num (buffer, &error);
503 if (error) {
504 display_beep();
505 strcpy (message, "Unable to parse position value");
506 return;
507 }
508
509 if (position < 0 || position > file_size) {
510 display_beep();
511 strcpy (message, "Position is outside bounds of file");
512 return;
513 }
514
515 cur_pos = position;
516 edit_type = !!edit_type;
517 new_top = cur_pos - (scrlines-1) * width;
518 if (new_top < 0)
519 new_top = 0;
520 new_top = begline(new_top);
521 if (top_pos > cur_pos)
522 top_pos = begline(cur_pos);
523 if (top_pos < new_top)
524 top_pos = new_top;
525 }
526
527 static void act_togstat (void) {
528 if (statfmt == decstatus)
529 statfmt = hexstatus;
530 else
531 statfmt = decstatus;
532 }
533
534 static int search_prompt(char *withdef, char *withoutdef)
535 {
536 char buffer[80];
537 int len;
538
539 if (!get_str(last_search ? withdef : withoutdef, buffer, TRUE))
540 return 0; /* user break */
541 if (!last_search && !*buffer) {
542 strcpy (message, "Search aborted.");
543 return 0;
544 }
545
546 if (!*buffer) {
547 len = last_search->len;
548 } else {
549 len = parse_quoted (buffer);
550 if (len == -1) {
551 display_beep();
552 strcpy (message, "Invalid escape sequence in search string");
553 return 0;
554 }
555 if (last_search)
556 free_search(last_search);
557 last_search = build_search (buffer, len);
558 }
559
560 return 1;
561 }
562
563 static void act_search (void) {
564 int len;
565 fileoffset_t posn, dfapos;
566 DFA dfa;
567 static unsigned char sblk[SEARCH_BLK];
568 static char withdef[] = "Search forward (default=last): ";
569 static char withoutdef[] = "Search forward: ";
570
571 if (!search_prompt(withdef, withoutdef))
572 return;
573
574 dfa = last_search->forward;
575 len = last_search->len;
576 dfapos = 0;
577
578 for (posn = cur_pos+1; posn < file_size; posn++) {
579 unsigned char *q;
580 int size = SEARCH_BLK;
581
582 if (size > file_size-posn)
583 size = file_size-posn;
584 buf_fetch_data (filedata, sblk, size, posn);
585 q = sblk;
586 while (size--) {
587 posn++;
588 dfapos = dfa[dfapos][*q++];
589 if (dfapos == len) {
590 fileoffset_t new_top;
591
592 cur_pos = posn - len;
593 edit_type = !!edit_type;
594 new_top = cur_pos - (scrlines-1) * width;
595 new_top = begline(new_top);
596 if (top_pos < new_top)
597 top_pos = new_top;
598 return;
599 }
600 }
601 }
602 strcpy (message, "Not found.");
603 }
604
605 static void act_search_backwards (void) {
606 int len;
607 fileoffset_t posn, dfapos;
608 DFA dfa;
609 static unsigned char sblk[SEARCH_BLK];
610 static char withdef[] = "Search backward (default=last): ";
611 static char withoutdef[] = "Search backward: ";
612
613 if (!search_prompt(withdef, withoutdef))
614 return;
615
616 dfa = last_search->reverse;
617 len = last_search->len;
618 dfapos = 0;
619
620 posn = cur_pos + len - 1;
621 if (posn >= file_size)
622 posn = file_size;
623
624 for (; posn >= 0; posn--) {
625 unsigned char *q;
626 int size = SEARCH_BLK;
627
628 if (size > posn)
629 size = posn;
630 buf_fetch_data (filedata, sblk, size, posn-size);
631 q = sblk + size;
632 while (size--) {
633 posn--;
634 dfapos = dfa[dfapos][*--q];
635 if (dfapos == len) {
636 fileoffset_t new_top;
637
638 cur_pos = posn;
639 edit_type = !!edit_type;
640 new_top = cur_pos - (scrlines-1) * width;
641 new_top = begline(new_top);
642 if (top_pos > new_top)
643 top_pos = new_top;
644 return;
645 }
646 }
647 }
648 strcpy (message, "Not found.");
649 }
650
651 static void act_recentre (void) {
652 top_pos = cur_pos - (display_rows-2)/2 * width;
653 if (top_pos < 0)
654 top_pos = 0;
655 top_pos = begline(top_pos);
656 }
657
658 static void act_width (void) {
659 char buffer[80];
660 char prompt[80];
661 fileoffset_t w;
662 fileoffset_t new_top;
663 int error;
664
665 sprintf (prompt, "Enter screen width in bytes (now %"OFF"d): ", width);
666 if (!get_str (prompt, buffer, FALSE))
667 return;
668 w = parse_num (buffer, &error);
669 if (error) {
670 display_beep();
671 strcpy (message, "Unable to parse width value");
672 return;
673 }
674 if (w > 0) {
675 width = w;
676 fix_offset();
677 new_top = cur_pos - (scrlines-1) * width;
678 new_top = begline(new_top);
679 if (top_pos < new_top)
680 top_pos = new_top;
681 }
682 }
683
684 static void act_offset (void) {
685 char buffer[80];
686 char prompt[80];
687 fileoffset_t o;
688 fileoffset_t new_top;
689 int error;
690
691 sprintf (prompt, "Enter start-of-file offset in bytes (now %"OFF"d): ",
692 realoffset);
693 if (!get_str (prompt, buffer, FALSE))
694 return;
695 o = parse_num (buffer, &error);
696 if (error) {
697 display_beep();
698 strcpy (message, "Unable to parse offset value");
699 return;
700 }
701 if (o >= 0) {
702 realoffset = o;
703 fix_offset();
704 new_top = cur_pos - (scrlines-1) * width;
705 new_top = begline(new_top);
706 if (top_pos < new_top)
707 top_pos = new_top;
708 }
709 }
710
711 #ifdef TEST_BUFFER
712 static void act_diagnostics(void)
713 {
714 extern void buffer_diagnostic(buffer *buf, char *title);
715
716 buffer_diagnostic(filedata, "filedata");
717 buffer_diagnostic(cutbuffer, "cutbuffer");
718 }
719 #endif