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