1 /* misc.c by Adam Rogoyski <apoc@laker.net> Temperanc on EFNet irc
2 * Copyright (C) 1998, 1999 Adam Rogoyski
3 * --- GNU General Public License Disclamer ---
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 of the License, or
7 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14
15 #include "hexedit.h"
16
17 #ifdef HAVE_TERMIO_H
18 #include <termio.h>
19 #else
20 #ifdef HAVE_TERMIOS_H
21 #include <termios.h>
22 #else
23 #ifdef HAVE_SYS_TERMIOS_H
24 #include <sys/termios.h>
25 #endif
26 #endif
27 #endif
28
29
30 int
mappos(int pos)31 mappos (int pos)
32 /* This is used for cursor_x. It has a value of 0-F, depending on what
33 * byte you are on in the line, and this returns the corresponding screen
34 * cursor position */
35 {
36 if (Globals.spacing)
37 {
38 switch (pos)
39 {
40 case 0:
41 return 10;
42 case 1:
43 return 13;
44 case 2:
45 return 16;
46 case 3:
47 return 19;
48 case 4:
49 return 23;
50 case 5:
51 return 26;
52 case 6:
53 return 29;
54 case 7:
55 return 32;
56 case 8:
57 return 37;
58 case 9:
59 return 40;
60 case 10:
61 return 43;
62 case 11:
63 return 46;
64 case 12:
65 return 50;
66 case 13:
67 return 53;
68 case 14:
69 return 56;
70 case 15:
71 return 59;
72 }
73 }
74 else
75 {
76 switch (pos)
77 {
78 case 0:
79 return 10;
80 case 1:
81 return 12;
82 case 2:
83 return 14;
84 case 3:
85 return 16;
86 case 4:
87 return 19;
88 case 5:
89 return 21;
90 case 6:
91 return 23;
92 case 7:
93 return 25;
94 case 8:
95 return 28;
96 case 9:
97 return 30;
98 case 10:
99 return 32;
100 case 11:
101 return 34;
102 case 12:
103 return 37;
104 case 13:
105 return 39;
106 case 14:
107 return 41;
108 case 15:
109 return 43;
110 }
111 }
112 return 0;
113 }
114
115
116
117 int
mapcur(int cur)118 mapcur (int cur)
119 /* This takes the cursor position and returns what byte it is on that line
120 */
121 {
122 if (Globals.spacing)
123 {
124 switch (cur)
125 {
126 case 10:
127 case 11:
128 return 0;
129 case 13:
130 case 14:
131 return 1;
132 case 16:
133 case 17:
134 return 2;
135 case 19:
136 case 20:
137 return 3;
138 case 23:
139 case 24:
140 return 4;
141 case 26:
142 case 27:
143 return 5;
144 case 29:
145 case 30:
146 return 6;
147 case 32:
148 case 33:
149 return 7;
150 case 37:
151 case 38:
152 return 8;
153 case 40:
154 case 41:
155 return 9;
156 case 43:
157 case 44:
158 return 10;
159 case 46:
160 case 47:
161 return 11;
162 case 50:
163 case 51:
164 return 12;
165 case 53:
166 case 54:
167 return 13;
168 case 56:
169 case 57:
170 return 14;
171 case 59:
172 case 60:
173 return 15;
174 }
175 }
176 else
177 {
178 switch (cur)
179 {
180 case 10:
181 case 11:
182 return 0;
183 case 12:
184 case 13:
185 return 1;
186 case 14:
187 case 15:
188 return 2;
189 case 16:
190 case 17:
191 return 3;
192 case 19:
193 case 20:
194 return 4;
195 case 21:
196 case 22:
197 return 5;
198 case 23:
199 case 24:
200 return 6;
201 case 25:
202 case 26:
203 return 7;
204 case 28:
205 case 29:
206 return 8;
207 case 30:
208 case 31:
209 return 9;
210 case 32:
211 case 33:
212 return 10;
213 case 34:
214 case 35:
215 return 11;
216 case 37:
217 case 38:
218 return 12;
219 case 39:
220 case 40:
221 return 13;
222 case 41:
223 case 42:
224 return 14;
225 case 43:
226 case 44:
227 return 15;
228 }
229 }
230 return 0;
231 }
232
233
234 int
cursor_ascii_to_ebcdic(int cur)235 cursor_ascii_to_ebcdic (int cur)
236 {
237 if (!Globals.spacing)
238 {
239 switch (cur)
240 {
241 case 10:
242 return 10;
243 case 11:
244 return 11;
245 case 13:
246 return 12;
247 case 14:
248 return 13;
249 case 16:
250 return 14;
251 case 17:
252 return 15;
253 case 19:
254 return 16;
255 case 20:
256 return 17;
257 case 23:
258 return 19;
259 case 24:
260 return 20;
261 case 26:
262 return 21;
263 case 27:
264 return 22;
265 case 29:
266 return 23;
267 case 30:
268 return 24;
269 case 32:
270 return 25;
271 case 33:
272 return 26;
273 case 37:
274 return 28;
275 case 38:
276 return 29;
277 case 40:
278 return 30;
279 case 41:
280 return 31;
281 case 43:
282 return 32;
283 case 44:
284 return 33;
285 case 46:
286 return 34;
287 case 47:
288 return 35;
289 case 50:
290 return 37;
291 case 51:
292 return 38;
293 case 53:
294 return 39;
295 case 54:
296 return 40;
297 case 56:
298 return 41;
299 case 57:
300 return 42;
301 case 59:
302 return 43;
303 case 60:
304 return 44;
305 }
306 }
307 else
308 {
309 switch (cur)
310 {
311 case 10:
312 return 10;
313 case 11:
314 return 11;
315 case 12:
316 return 13;
317 case 13:
318 return 14;
319 case 14:
320 return 16;
321 case 15:
322 return 17;
323 case 16:
324 return 19;
325 case 17:
326 return 20;
327 case 19:
328 return 23;
329 case 20:
330 return 24;
331 case 21:
332 return 26;
333 case 22:
334 return 27;
335 case 23:
336 return 29;
337 case 24:
338 return 30;
339 case 25:
340 return 32;
341 case 26:
342 return 33;
343 case 28:
344 return 37;
345 case 29:
346 return 38;
347 case 30:
348 return 40;
349 case 31:
350 return 41;
351 case 32:
352 return 43;
353 case 33:
354 return 44;
355 case 34:
356 return 46;
357 case 35:
358 return 47;
359 case 37:
360 return 50;
361 case 38:
362 return 51;
363 case 39:
364 return 53;
365 case 40:
366 return 54;
367 case 41:
368 return 56;
369 case 42:
370 return 57;
371 case 43:
372 return 59;
373 case 44:
374 return 60;
375 }
376 }
377 return 0;
378 }
379
380
381
382 void
usage(char * prog)383 usage (char *prog)
384 {
385 printf ("[N]Curses Hexedit %s by Adam Rogoyski <apoc@laker.net>\n" \
386 "Copyright (C) 1998, 1999 Adam Rogoyski\n" \
387 "This is free software; see the source for copying conditions.\n" \
388 "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n" \
389 "PARTICULAR PURPOSE.\n\n" \
390 "Usage: %s [options] [file]\n" \
391 "Options:\n" \
392 " -h, --help Print this message and exit.\n"
393 " -8, --highbit Print high order 8-bit text.\n"
394 " -a, --alltext Print all text characters.\n"
395 " -b, --buffer Buffer the entire file in memory.\n"
396 " Much faster and enables insert/delete.\n"
397 #if defined (__linux__) || defined (__OpenBSD__) || defined(__FreeBSD__)
398 " -d, --disk Edit a fixed disk, i.e. /dev/hda (Read-only)\n"
399 " -f, --force Force editing of disk.\n"
400 " Needed to write to disks.\n"
401 #endif
402 " -n, --nocolor Force Gray scale, no colors.\n"
403 " -q, --quiet Quiet Mode, No annoying beeping\n"
404 " -r, --readonly Do not modifying of the file.\n"
405 " -v, --version Print the version number and exit.\n",
406 VERSION, prog);
407 }
408
409
410 void
die_horribly(const char * const message,const char * const pmsg)411 die_horribly (const char * const message, const char * const pmsg)
412 /* clear the screen reset the screen, and optionally print a message
413 * why hexedit terminated to standard error. Possibly print perror ().
414 */
415 {
416 erase ();
417 refresh ();
418 endwin ();
419
420 if (message)
421 fprintf (stderr, "%s\n", message);
422
423 if (pmsg)
424 perror (pmsg);
425
426 exit (EXIT_FAILURE);
427 }
428
429
430 void
handleInterrupt(int i)431 handleInterrupt (int i)
432 #define QUIT_BOX_WIDTH 60
433 #define QUIT_BOX_HEIGHT 6
434 #define YES_VALUE 1
435 #define NO_VALUE 2
436 #define NEW_FILE_VALUE 3
437 #define FIRST_VALUE YES_VALUE
438 #define LAST_VALUE NEW_FILE_VALUE
439 {
440 int done = 0;
441 int j = 0;
442 int value = YES_VALUE;
443 wchar_t in = 0;
444 static int semph = 0;
445 WINDOW *win = popupWindow (QUIT_BOX_WIDTH, QUIT_BOX_HEIGHT);
446
447 /* signal (SIGINT, SIG_IGN); */
448
449 if (semph)
450 return;
451 semph = 1;
452
453 box (win, 0, 0);
454 if (Globals.modified == READ_ONLY)
455 {
456 wmove (win, 2,
457 QUIT_BOX_WIDTH / 2 - strlen (" Really Quit? ") / 2);
458 wprintw (win, " Really Quit? ");
459 }
460 else
461 {
462 wmove (win, 2,
463 QUIT_BOX_WIDTH / 2 - strlen ("Quit without Saving?") / 2);
464 wprintw (win, "Quit without Saving?");
465 }
466 wmove (win, 4, QUIT_BOX_WIDTH / 2
467 - (strlen (" Yes No New File ") / 2));
468 wattrset (win, A_REVERSE);
469 wprintw (win, " Yes ");
470 wattroff (win, A_REVERSE);
471
472 wprintw (win, " No");
473
474 wprintw (win, " New File");
475 wrefresh (win);
476
477 wmove (Globals.whelp, 0, 0);
478 wprintw (Globals.whelp, "^G/^X/Escape Cancel Y Yes N No F New File");
479 for (j = strlen ("^G/^X/Escape Cancel Y Yes N No F New File");
480 j < COLS; j++)
481 wprintw (Globals.whelp, " ");
482 wrefresh (Globals.whelp);
483
484 value = YES_VALUE;
485 while (!done && (in = getch ()) != '\n')
486 {
487 switch (in)
488 {
489 case TAB:
490 case KEY_RIGHT:
491 (value == LAST_VALUE) ? value = FIRST_VALUE : value++;
492 break;
493
494 case KEY_LEFT:
495 (value == FIRST_VALUE) ? value = LAST_VALUE : value--;
496 break;
497
498 case 'n':
499 case 'N':
500 case CONTROL_G:
501 case CONTROL_X:
502 case ESCAPE_CHARACTER:
503 value = NO_VALUE;
504 done = 1;
505 break;
506
507 case 'y':
508 case 'Y':
509 value = YES_VALUE;
510 done = 1;
511 break;
512
513 case 'f':
514 case 'F':
515 value = NEW_FILE_VALUE;
516 done = 1;
517 break;
518 }
519
520 if (value == YES_VALUE)
521 {
522 wmove (win, 4, QUIT_BOX_WIDTH / 2
523 - (strlen (" Yes No New File ") / 2));
524 wattrset (win, A_REVERSE);
525 wprintw (win, " Yes ");
526 wattroff (win, A_REVERSE);
527 wprintw (win, " No New File ");
528 }
529 else if (value == NO_VALUE)
530 {
531 wmove (win, 4, QUIT_BOX_WIDTH / 2
532 - (strlen (" Yes No New File ") / 2));
533 wattroff (win, A_REVERSE);
534 wprintw (win, " Yes ");
535 wattrset (win, A_REVERSE);
536 wprintw (win, " No ");
537 wattroff (win, A_REVERSE);
538 wprintw (win, " New File ");
539 }
540 else if (value == NEW_FILE_VALUE)
541 {
542 wmove (win, 4, QUIT_BOX_WIDTH / 2
543 - (strlen (" Yes No New File ") / 2));
544 wattroff (win, A_REVERSE);
545 wprintw (win, " Yes No ");
546 wattrset (win, A_REVERSE);
547 wprintw (win, " New File ");
548 }
549 wrefresh (win);
550 }
551
552 if (value == YES_VALUE)
553 exitProgram ();
554 else if (value == NEW_FILE_VALUE)
555 {
556 FILE *fp = NULL;
557
558 load_new_file (&fp);
559 cursor_y = MAIN_TOP_LINE;
560 cursor_x = 10;
561 offset = 0x00;
562 Globals.modified = 0;
563 Globals.tabb = 0;
564 }
565 redraw ();
566 semph = 0;
567 /* signal (SIGINT, handleInterrupt); */
568 }
569
570
571 #ifndef __PDCURSES__
572 void
handleSigwinch(int i)573 handleSigwinch (int i)
574 {
575 char *tty = NULL;
576 int fd = 0;
577 int result = 0;
578 struct winsize win;
579
580 tty = ttyname (0);
581 if (!tty)
582 return;
583 fd = open (tty, O_RDWR);
584 if (fd == -1)
585 {
586 perror (tty);
587 return;
588 }
589 result = ioctl (fd, TIOCGWINSZ, &win);
590 if (result == -1)
591 {
592 perror ("ioctl TIOCGWINSZ");
593 return;
594 }
595 delwin (Globals.wmain);
596 delwin (Globals.wstatus);
597 delwin (Globals.whelp);
598 endwin ();
599 COLS = win.ws_col;
600 LINES = win.ws_row;
601 initscr ();
602 if (stdscr == NULL)
603 die_horribly ("Cannot initialize screen - curses!\n", NULL);
604 keypad (stdscr, TRUE);
605 scrollok (stdscr, FALSE);
606 cbreak ();
607 noecho ();
608 refresh ();
609 Globals.wmain = newwin (MAIN_HEIGHT, COLS, MAIN_TOP_LINE, 0);
610 if (Globals.wmain == NULL)
611 die_horribly ("Cannot open larger main window - curses!\n", NULL);
612 scrollok (Globals.wmain, FALSE);
613 #ifdef __PDCURSES__
614 leaveok(Globals.wmain, FALSE); /* Stupid macro */
615 #else
616 leaveok (Globals.wmain, FALSE);
617 #endif
618 Globals.wstatus = newwin (1, COLS, 0, 0);
619 if (Globals.wstatus == NULL)
620 {
621 fprintf (stderr, "Cannot open status window - curses!\n");
622 exit (EXIT_FAILURE);
623 }
624 scrollok (Globals.wstatus, FALSE);
625 wattrset (Globals.wstatus, color_term ? COLOR_PAIR(3) | A_BOLD
626 : A_REVERSE);
627 Globals.whelp = newwin (1, COLS, LINES - 1, 0);
628 if (Globals.whelp == NULL)
629 die_horribly ("Cannot open help window - curses!\n", NULL);
630 scrollok (Globals.whelp, FALSE);
631 if (newlines)
632 free (newlines);
633 newlines = malloc (BOTTOM_LINE * sizeof (int));
634 if (!newlines)
635 die_horribly (NOT_ENOUGH_MEMORY, NULL);
636
637 Globals.wmain->_cury = cursor_y - 1;
638 Globals.wmain->_curx = cursor_x;
639 stdscr->_cury = cursor_y;
640 stdscr->_curx = cursor_x;
641 if (cursor_y >= BOTTOM_LINE)
642 cursor_y = BOTTOM_LINE;
643 if (Globals.mode == FILE_MODE)
644 {
645 extern struct FileNames *fp;
646 extern struct FileNames **pages;
647 extern int current_page;
648 extern int num_pages;
649 char trunc_file[PATH_MAX + 1];
650 struct FileNames *p = *pages;
651 struct FileNames *pfront = *pages;
652 int i = 0;
653 int j = 0;
654 int n = 0;
655
656 if (p)
657 {
658 while (p->p)
659 {
660 p = p->p;
661 n++;
662 }
663 }
664 if (pages)
665 free (pages);
666 num_pages = ((n - 1) / (LINES - 2)) + 1;
667 pages = malloc (sizeof (struct FileNames *) * num_pages);
668 if (!pages)
669 die_horribly (NOT_ENOUGH_MEMORY, NULL);
670
671 memset (pages, 0x00, num_pages * sizeof (struct FileNames *));
672 *pages = pfront;
673 p = pfront;
674 for (i = 1; i < num_pages; i++)
675 {
676 for (j = 0; (j < (LINES - 2)) && p; j++)
677 p = p->p;
678 *(pages + i) = p;
679 }
680
681 i = 0;
682 p = pfront;
683 while (p != fp)
684 {
685 if (p == *(pages + i + 1))
686 i++;
687 p = p->p;
688
689 }
690 if (p == *(pages + i + 1))
691 i++;
692 current_page = i;
693 cursor_y = MAIN_TOP_LINE;
694 p = *(pages + current_page);
695 while (p != fp)
696 {
697 p = p->p;
698 cursor_y++;
699 }
700 refresh ();
701 wrefresh (Globals.wmain);
702 wrefresh (Globals.wstatus);
703 wrefresh (Globals.whelp);
704 printPage (*(pages + current_page));
705 memset (trunc_file, 0x00, PATH_MAX + 1);
706 strncpy (trunc_file, fp->filename, COLS - NAME_POS);
707 wmove (Globals.wmain, cursor_y - MAIN_TOP_LINE, NAME_POS);
708 wattrset (Globals.wmain, A_BOLD);
709 wprintw (Globals.wmain, "%s", trunc_file);
710 wattroff (Globals.wmain, A_BOLD);
711
712 statWindow (fp->filename);
713 helpWindow ("^C ^X Exit Program ^M Select File");
714 move (cursor_y, NAME_POS);
715 wrefresh (Globals.wmain);
716 wrefresh (Globals.wstatus);
717 wrefresh (Globals.whelp);
718 }
719 else
720 {
721 redraw ();
722 redraw ();
723 }
724 refresh ();
725 /* signal (SIGWINCH, handleSigwinch); */
726 }
727 #endif
728
729
730 void
exitProgram(void)731 exitProgram (void)
732 {
733 int i = 0;
734 struct Change *cp = NULL;
735
736 move (LINES - 1, 0);
737 wattroff (Globals.wmain, A_REVERSE);
738 for (i = 0; i < COLS; i++)
739 wprintw (stdscr, " ");
740 wrefresh (stdscr);
741 werase (Globals.whelp);
742 wrefresh (Globals.whelp);
743 delwin (Globals.wstatus);
744 delwin (Globals.wmain);
745 delwin (Globals.whelp);
746 delwin (stdscr);
747 free (filebuf);
748 free (newlines);
749
750 while (UndoStack.base)
751 {
752 cp = UndoStack.base->p;
753 free (UndoStack.base);
754 UndoStack.base = cp;
755 }
756 endwin ();
757 exit (EXIT_SUCCESS);
758 }
759
760
761 void
exitSave(int saved)762 exitSave (int saved)
763 {
764 if (saved)
765 exitProgram ();
766 redraw ();
767 }
768
769
770 char *
chompWhiteSpace(char * str)771 chompWhiteSpace (char *str)
772 {
773 int i = 0;
774 i = 0;
775 while (*(str + i))
776 {
777 if ((*(str + i) == ' ') || (*(str + i) == '\r')
778 || (*(str + i) == '\t') || (*(str + i) == '\n'))
779 {
780 *(str + i) = 0;
781 break;
782 }
783 else
784 i++;
785 }
786 return str;
787 }
788
789
790 int
isHexChar(wchar_t c)791 isHexChar (wchar_t c)
792 {
793 switch (c)
794 {
795 case '0':
796 case '1':
797 case '2':
798 case '3':
799 case '4':
800 case '5':
801 case '6':
802 case '7':
803 case '8':
804 case '9':
805 case 'a':
806 case 'b':
807 case 'c':
808 case 'd':
809 case 'e':
810 case 'f':
811 case 'A':
812 case 'B':
813 case 'C':
814 case 'D':
815 case 'E':
816 case 'F':
817 return 1;
818 default:
819 return 0;
820 }
821 return 0;
822 }
823
824
825 int
getHexValue(wchar_t c)826 getHexValue (wchar_t c)
827 {
828 switch (c)
829 {
830 case '0':
831 return 0x00;
832 case '1':
833 return 0x01;
834 case '2':
835 return 0x02;
836 case '3':
837 return 0x03;
838 case '4':
839 return 0x04;
840 case '5':
841 return 0x05;
842 case '6':
843 return 0x06;
844 case '7':
845 return 0x07;
846 case '8':
847 return 0x08;
848 case '9':
849 return 0x09;
850 case 'a':
851 case 'A':
852 return 0x0A;
853 case 'b':
854 case 'B':
855 return 0x0B;
856 case 'c':
857 case 'C':
858 return 0x0C;
859 case 'd':
860 case 'D':
861 return 0x0D;
862 case 'e':
863 case 'E':
864 return 0x0E;
865 case 'f':
866 case 'F':
867 return 0x0F;
868 }
869 return 0;
870 }
871
872 char
getAsciiValue(wchar_t c)873 getAsciiValue (wchar_t c)
874 {
875 switch (c)
876 {
877 case 0:
878 return '0';
879 case 1:
880 return '1';
881 case 2:
882 return '2';
883 case 3:
884 return '3';
885 case 4:
886 return '4';
887 case 5:
888 return '5';
889 case 6:
890 return '6';
891 case 7:
892 return '7';
893 case 8:
894 return '8';
895 case 9:
896 return '9';
897 case 10:
898 return 'A';
899 case 11:
900 return 'B';
901 case 12:
902 return 'C';
903 case 13:
904 return 'D';
905 case 14:
906 return 'E';
907 case 15:
908 return 'F';
909 }
910 return '\0';
911 }
912
913
914 void
switchModes(void)915 switchModes (void)
916 {
917 if (Globals.mode == HEX_MODE)
918 Globals.mode = ASCII_MODE;
919 else
920 Globals.mode = HEX_MODE;
921 redraw ();
922 }
923
924
925 int
isprintable(int c)926 isprintable (int c)
927 {
928 if (Globals.charset == EBCDIC_CHAR_SET)
929 return 1;
930
931 switch (Globals.print_mode)
932 {
933 case REGULAR_PRINT:
934 #ifdef HAVE_ISPRINT
935 return isprint (c);
936 #else
937 return ((c > 32) && (c < 127));
938 #endif
939
940 case HIGH_ASCII_PRINT:
941 #ifdef HAVE_ISPRINT
942 return (isprint (c) || ((c > 127)));
943 #else
944 return ((c > 32) && (c <= 255) && (c != 127));
945 #endif
946
947 case ALL_PRINT:
948 return (c > 0);
949
950 }
951 return 0;
952 }
953
954
955 void
do_beep()956 do_beep ()
957 {
958 if (Globals.beeping)
959 beep ();
960 }
961