Makefile: simplify, and respect DESTDIR and CPPFLAGS
[rofl0r-hexedit0r.git] / interact.c
blob18ce2a08724d90a26c81f68bc829f70bdf6aa283
1 /* hexedit -- Hexadecimal Editor for Binary Files
2 Copyright (C) 1998 Pixel (Pascal Rigaux)
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
17 #include "hexedit.h"
20 static void goto_char(void);
21 static void goto_sector(void);
22 static void save_buffer(void);
23 static void escaped_command(void);
24 static void help(void);
25 static void short_help(void);
28 /*******************************************************************************/
29 /* interactive functions */
30 /*******************************************************************************/
32 static void forward_char(void)
34 if (!hexOrAscii || cursorOffset)
35 move_cursor(+1);
36 if (hexOrAscii) cursorOffset = (cursorOffset + 1) % 2;
39 static void backward_char(void)
41 if (!hexOrAscii || !cursorOffset)
42 move_cursor(-1);
43 if (hexOrAscii) cursorOffset = (cursorOffset + 1) % 2;
46 static void next_line(void)
48 move_cursor(+lineLength);
51 static void previous_line(void)
53 move_cursor(-lineLength);
56 static void forward_chars(void)
58 move_cursor(+blocSize);
61 static void backward_chars(void)
63 move_cursor(-blocSize);
66 static void next_lines(void)
68 move_cursor(+lineLength * blocSize);
71 static void previous_lines(void)
73 move_cursor(-lineLength * blocSize);
76 static void beginning_of_line(void)
78 cursorOffset = 0;
79 move_cursor(-(cursor % lineLength));
82 static void end_of_line(void)
84 cursorOffset = 0;
85 if (!move_cursor(lineLength - 1 - cursor % lineLength))
86 move_cursor(nbBytes - cursor);
89 static void scroll_up(void)
91 move_base(+page);
93 if (mark_set)
94 updateMarked();
97 static void scroll_down(void)
99 move_base(-page);
101 if (mark_set)
102 updateMarked();
105 static void beginning_of_buffer(void)
107 cursorOffset = 0;
108 set_cursor(0);
111 static void end_of_buffer(void)
113 INT s = getfilesize();
114 cursorOffset = 0;
115 if (mode == bySector) set_base(myfloor(s, page));
116 set_cursor(s);
119 static void suspend(void) { kill(getpid(), SIGTSTP); }
120 static void undo(void) { discardEdited(); readFile(); }
121 static void quoted_insert(void) { setTo(getch()); }
122 static void toggle(void) { hexOrAscii = (hexOrAscii + 1) % 2; }
124 static void recenter(void)
126 if (cursor) {
127 base = base + cursor;
128 cursor = 0;
129 readFile();
133 static void find_file(void)
135 if (!ask_about_save_and_redisplay()) return;
136 if (!findFile()) { displayMessageAndWaitForKey("No such file or directory"); return; }
137 openFile();
138 readFile();
141 static void redisplay(void) { clear(); }
143 static void delete_backward_char(void)
145 backward_char();
146 removeFromEdited(base + cursor, 1);
147 readFile();
148 cursorOffset = 0;
149 if (!tryloc(base + cursor)) end_of_buffer();
152 static void delete_backward_chars(void)
154 backward_chars();
155 removeFromEdited(base + cursor, blocSize);
156 readFile();
157 cursorOffset = 0;
158 if (!tryloc(base + cursor)) end_of_buffer();
161 static void truncate_file(void)
163 displayOneLineMessage("Really truncate here? (y/N)");
164 if (tolower(getch()) == 'y') {
165 if (biggestLoc > base+cursor && ftruncate(fd, base+cursor) == -1)
166 displayMessageAndWaitForKey(strerror(errno));
167 else {
168 removeFromEdited(base+cursor, lastEditedLoc - (base+cursor));
169 if (mark_set) {
170 if (mark_min >= base + cursor || mark_max >= base + cursor)
171 unmarkAll();
173 if (biggestLoc > base+cursor)
174 biggestLoc = base+cursor;
175 readFile();
180 static void firstTimeHelp(void)
182 int firstTime = TRUE;
184 if (firstTime) {
185 firstTime = FALSE;
186 short_help();
190 static void set_mark_command(void)
192 unmarkAll();
193 if ((mark_set = not(mark_set))) {
194 markIt(cursor);
195 mark_min = mark_max = base + cursor;
200 int setTo(int c)
202 int val;
204 if (cursor > nbBytes) return FALSE;
205 if (hexOrAscii) {
206 if (!isxdigit(c)) return FALSE;
207 val = hexCharToInt(c);
208 val = cursorOffset ? setLowBits(buffer[cursor], val) : setHighBits(buffer[cursor], val);
210 else val = c;
212 if (isReadOnly) {
213 displayMessageAndWaitForKey("File is read-only!");
214 } else {
215 setToChar(cursor, val);
216 forward_char();
218 return TRUE;
222 /****************************************************
223 ask_about_* or functions that present a prompt
224 ****************************************************/
227 int ask_about_save(void)
229 if (edited) {
230 displayOneLineMessage("Save changes (Yes/No/Cancel) ?");
232 switch (tolower(getch()))
234 case 'y': save_buffer(); break;
235 case 'n': discardEdited(); break;
237 default:
238 return FALSE;
240 return TRUE;
242 return -TRUE;
245 int ask_about_save_and_redisplay(void)
247 int b = ask_about_save();
248 if (b == TRUE) {
249 readFile();
250 display();
252 return b;
255 void ask_about_save_and_quit(void)
257 if (ask_about_save()) quit();
260 static void goto_char(void)
262 INT i;
264 displayOneLineMessage("New position ? ");
265 ungetstr("0x");
266 if (!get_number(&i) || !set_cursor(i)) displayMessageAndWaitForKey("Invalid position!");
269 static void goto_sector(void)
271 INT i;
273 displayOneLineMessage("New sector ? ");
274 if (get_number(&i) && set_base(i * SECTOR_SIZE))
275 set_cursor(i * SECTOR_SIZE);
276 else
277 displayMessageAndWaitForKey("Invalid sector!");
282 static void save_buffer(void)
284 int displayedmessage = FALSE;
285 typePage *p, *q;
286 for (p = edited; p; p = q) {
287 if (LSEEK_(fd, p->base) == -1 || write(fd, p->vals, p->size) == -1)
288 if (!displayedmessage) { /* It would be annoying to display lots of error messages when we can't write. */
289 displayMessageAndWaitForKey(strerror(errno));
290 displayedmessage = TRUE;
292 q = p->next;
293 freePage(p);
295 edited = NULL;
296 if (lastEditedLoc > fileSize) fileSize = lastEditedLoc;
297 lastEditedLoc = 0;
298 memset(bufferAttr, A_NORMAL, page * sizeof(*bufferAttr));
299 if (displayedmessage) {
300 displayMessageAndWaitForKey("Unwritten changes have been discarded");
301 readFile();
302 if (cursor > nbBytes) set_cursor(getfilesize());
304 if (mark_set) markSelectedRegion();
307 static void help(void)
309 char *args[3];
310 int status;
312 args[0] = "man";
313 args[1] = "hexedit";
314 args[2] = NULL;
315 endwin();
316 if (fork() == 0) {
317 execvp(args[0], args);
318 exit(1);
320 wait(&status);
321 refresh();
322 raw();
325 static void short_help(void)
327 displayMessageAndWaitForKey("Unknown command, press F1 for help");
332 /*******************************************************************************/
333 /* key_to_function */
334 /*******************************************************************************/
335 int key_to_function(int key)
337 oldcursor = cursor;
338 oldcursorOffset = cursorOffset;
339 oldbase = base;
340 /*printf("*******%d******\n", key);*/
342 switch (key)
344 case KEY_RIGHT:
345 case CTRL('F'):
346 forward_char();
347 break;
349 case KEY_LEFT:
350 case CTRL('B'):
351 backward_char();
352 break;
354 case KEY_DOWN:
355 case CTRL('N'):
356 next_line();
357 break;
359 case KEY_UP:
360 case CTRL('P'):
361 previous_line();
362 break;
364 case ALT('F'):
365 forward_chars();
366 break;
368 case ALT('B'):
369 backward_chars();
370 break;
372 case ALT('N'):
373 next_lines();
374 break;
376 case ALT('P'):
377 previous_lines();
378 break;
380 case CTRL('A'):
381 case KEY_HOME:
382 beginning_of_line();
383 break;
385 case CTRL('E'):
386 case KEY_END:
387 end_of_line();
388 break;
390 case KEY_NPAGE:
391 case CTRL('V'):
392 case KEY_F(6):
393 scroll_up();
394 break;
396 case KEY_PPAGE:
397 case ALT('V'):
398 case KEY_F(5):
399 scroll_down();
400 break;
402 case '<':
403 case ALT('<'):
404 beginning_of_buffer();
405 break;
407 case '>':
408 case ALT('>'):
409 end_of_buffer();
410 break;
412 case KEY_SUSPEND:
413 case CTRL('Z'):
414 suspend();
415 break;
417 case CTRL('U'):
418 case CTRL('_'):
419 undo();
420 break;
422 case CTRL('Q'):
423 quoted_insert();
424 break;
426 case CTRL('T'):
427 case '\t':
428 toggle();
429 break;
431 case '/':
432 case CTRL('S'):
433 search_forward();
434 break;
436 case CTRL('R'):
437 search_backward();
438 break;
440 case CTRL('G'):
441 case KEY_F(4):
442 goto_char();
443 break;
445 case ALT('L'):
446 recenter();
447 break;
449 case '\n':
450 case '\r':
451 case KEY_ENTER:
452 if (mode == bySector) goto_sector(); else goto_char();
453 break;
455 case CTRL('W'):
456 case KEY_F(2):
457 save_buffer();
458 break;
460 case CTRL('['): /* escape */
461 escaped_command();
462 break;
464 case KEY_F(1):
465 case ALT('H'):
466 help();
467 break;
469 case KEY_F(3):
470 case CTRL('O'):
471 find_file();
472 break;
474 case CTRL('L'):
475 redisplay();
476 break;
478 case CTRL('H'):
479 case KEY_BACKSPACE:
480 delete_backward_char();
481 break;
483 case CTRL('H') | 0x80: /* CTRL-ALT-H */
484 delete_backward_chars();
485 break;
487 case CTRL(' '):
488 case KEY_F(9):
489 set_mark_command();
490 break;
492 case CTRL('D'):
493 case ALT('W'):
494 case KEY_DC:
495 case KEY_F(7):
496 case 0x7F: /* found on a sun */
497 copy_region();
498 break;
500 case CTRL('Y'):
501 case KEY_IC:
502 case KEY_F(8):
503 yank();
504 break;
506 case ALT('Y'):
507 case KEY_F(11):
508 yank_to_a_file();
509 break;
511 case KEY_F(12):
512 case ALT('I'):
513 fill_with_string();
514 break;
516 case CTRL('C'):
517 quit();
518 break;
520 case ALT('T'):
521 truncate_file();
522 break;
524 case KEY_F(0):
525 case KEY_F(10):
526 case CTRL('X'):
527 ask_about_save_and_quit();
528 break;
530 default:
531 if ((key >= 256 || !setTo(key))) firstTimeHelp();
534 return TRUE;
539 static void escaped_command(void)
541 char tmp[BLOCK_SEARCH_SIZE];
542 int c, i;
544 c = getch();
545 switch (c)
547 case KEY_RIGHT:
548 case 'f':
549 forward_chars();
550 break;
552 case KEY_LEFT:
553 case 'b':
554 backward_chars();
555 break;
557 case KEY_DOWN:
558 case 'n':
559 next_lines();
560 break;
562 case KEY_UP:
563 case 'p':
564 previous_lines();
565 break;
567 case 'v':
568 scroll_down();
569 break;
571 case KEY_HOME:
572 case '<':
573 beginning_of_buffer();
574 break;
576 case KEY_END:
577 case '>':
578 end_of_buffer();
579 break;
581 case 'l':
582 recenter();
583 break;
585 case 'h':
586 help();
587 break;
589 case CTRL('H'):
590 delete_backward_chars();
591 break;
593 case 'w':
594 copy_region();
595 break;
597 case 'y':
598 yank_to_a_file();
599 break;
601 case 'i':
602 fill_with_string();
603 break;
605 case 't':
606 truncate_file();
607 break;
609 case '\e':
610 c = getch();
611 if (c == 'O') {
612 switch (c = getch())
614 case 'C':
615 forward_chars();
616 break;
618 case 'D':
619 backward_chars();
620 break;
622 case 'B':
623 next_lines();
624 break;
626 case 'A':
627 previous_lines();
628 break;
630 case 'H':
631 beginning_of_buffer();
632 break;
634 case 'F':
635 end_of_buffer();
636 break;
638 case 'P': /* F1 on a xterm */
639 help();
640 break;
642 case 'Q': /* F2 on a xterm */
643 save_buffer();
644 break;
646 case 'R': /* F3 on a xterm */
647 find_file();
648 break;
650 case 'S': /* F4 on a xterm */
651 goto_char();
652 break;
654 default:
655 firstTimeHelp();
657 } else firstTimeHelp();
658 break;
660 case '[':
661 for (i = 0;; i++) { tmp[i] = c = getch(); if (!isdigit(c)) break; }
662 tmp[i + 1] = '\0';
664 if (0);
665 else if (streq(tmp, "2~")) yank();
666 else if (streq(tmp, "5~")) scroll_down();
667 else if (streq(tmp, "6~")) scroll_up();
668 else if (streq(tmp, "7~")) beginning_of_buffer();
669 else if (streq(tmp, "8~")) end_of_buffer();
670 else if (streq(tmp, "010q" /* F10 on a sgi's winterm */)) ask_about_save_and_quit();
671 else if (streq(tmp, "193z")) fill_with_string();
672 else if (streq(tmp, "214z")) beginning_of_line();
673 else if (streq(tmp, "216z")) scroll_down();
674 else if (streq(tmp, "220z")) end_of_line();
675 else if (streq(tmp, "222z")) scroll_up();
676 else if (streq(tmp, "233z")) ask_about_save_and_quit();
677 else if (streq(tmp, "234z" /* F11 on a sun */)) yank_to_a_file();
678 else if (streq(tmp, "247z")) yank();
679 else if (streq(tmp, "11~" /* F1 on a rxvt */)) help();
680 else if (streq(tmp, "12~" /* F2 on a rxvt */)) save_buffer();
681 else if (streq(tmp, "13~" /* F3 on a rxvt */)) find_file();
682 else if (streq(tmp, "14~" /* F4 on a rxvt */)) goto_char();
683 else if (streq(tmp, "15~" /* F5 on a rxvt */)) scroll_down();
684 else if (streq(tmp, "17~" /* F6 on a rxvt */)) scroll_up();
685 else if (streq(tmp, "18~" /* F7 on a rxvt */)) copy_region();
686 else if (streq(tmp, "19~" /* F8 on a rxvt */)) yank();
687 else if (streq(tmp, "20~" /* F9 on a rxvt */)) set_mark_command();
688 else if (streq(tmp, "21~" /* F10 on a rxvt */)) ask_about_save_and_quit();
689 else if (streq(tmp, "23~" /* F11 on a rxvt */)) yank_to_a_file();
690 else if (streq(tmp, "24~" /* F12 on a rxvt */)) fill_with_string();
691 else firstTimeHelp();
692 break;
694 default:
695 firstTimeHelp();