/* File hex/ascii viewer utility Copyright (c) Tudor Hulubei & Andrei Pitis, May 1994 This file is part of UIT (UNIX Interactive Tools) UIT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. UIT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details . You should have received a copy of the GNU General Public License along with UIT; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "tty.h" #include "termcap.h" #include "window.h" #include "config.h" #define max(a, b) ((a) >= (b) ? (a) : (b)) #define min(a, b) ((a) <= (b) ? (a) : (b)) #define MAX_KEYS 2048 #define BUILTIN_OPERATIONS 8 #define BUILTIN_CursorUp -1 #define BUILTIN_CursorDown -2 #define BUILTIN_PageUp -3 #define BUILTIN_PageDown -4 #define BUILTIN_Home -5 #define BUILTIN_End -6 #define BUILTIN_Refresh -7 #define BUILTIN_Exit -8 #define MAX_BUILTIN_NAME 15 char built_in[BUILTIN_OPERATIONS][MAX_BUILTIN_NAME] = { "", "", "", "", "", "", "", "" }; int SCREEN_X, SCREEN_Y; #define VIEWER_FIELDS 12 static char VIEWERFields[VIEWER_FIELDS][40] = { "TitleForeground", "TitleBackground", "TitleBrightness", "HeaderForeground", "HeaderBackground", "HeaderBrightness", "ScreenForeground", "ScreenBackground", "ScreenBrightness", "StatusForeground", "StatusBackground", "StatusBrightness" }; #ifdef HAVE_LINUX static int VIEWERColors[VIEWER_FIELDS] = { CYAN, BLUE, ON, CYAN, RED, ON, BLACK, CYAN, OFF, CYAN, BLUE, ON }; #else static int VIEWERColors[VIEWER_FIELDS] = { BLACK, WHITE, OFF, WHITE, BLACK, ON, WHITE, BLACK, OFF, BLACK, WHITE, OFF }; #endif #define TitleForeground VIEWERColors[0] #define TitleBackground VIEWERColors[1] #define TitleBrightness VIEWERColors[2] #define HeaderForeground VIEWERColors[3] #define HeaderBackground VIEWERColors[4] #define HeaderBrightness VIEWERColors[5] #define ScreenForeground VIEWERColors[6] #define ScreenBackground VIEWERColors[7] #define ScreenBrightness VIEWERColors[8] #define StatusForeground VIEWERColors[9] #define StatusBackground VIEWERColors[10] #define StatusBrightness VIEWERColors[11] #ifdef HAVE_LINUX int LinuxConsole = 1; int ColorMonitor = 1; #else int LinuxConsole = 0; int ColorMonitor = 0; #endif extern char tty_type[]; char homedirectory[PATH_MAX]; char configfile[PATH_MAX] = ""; char cSection[] = "[UITVIEW-Color]"; char bwSection[] = "[UITVIEW-Monochrome]"; char *header_text; configuration *config; int handle, regular_file; int current_line, lines; window *title_win, *header_win, *screen_win, *status_win; static char title_text[]= " UNIX Interactive Tools 4.2b - Hex/Ascii File Viewer"; static char UitViewModeHelp[256]; static char info_txt[] = " Offset 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F \ Ascii "; static char line_txt[] = " ------------------------------------------\ ---------------------------------- "; static char seek_txt[] = " Seek at: "; int filelength(void) { int temp, length; if (!regular_file) return 0x7FFFFFFF; temp = tell(handle); lseek(handle, 0, SEEK_END); length = tell(handle); lseek(handle, temp, SEEK_SET); return length; } void settitle(void) { char temp[256]; memset(temp, ' ', SCREEN_X); memcpy(temp, title_text, strlen(title_text)); tty_bright(TitleBrightness); tty_foreground(TitleForeground); tty_background(TitleBackground); window_cursormove(title_win, 0, 0); window_write(temp, SCREEN_X); } void setheader(void) { char temp[256]; memset(temp, ' ', SCREEN_X); memcpy(temp, header_text, min(strlen(header_text), SCREEN_X)); tty_bright(HeaderBrightness); tty_foreground(HeaderForeground); tty_background(HeaderBackground); window_cursormove(header_win, 0, 0); window_write(temp, SCREEN_X); } void setstatus(void) { char temp[256]; memset(temp, ' ', SCREEN_X); memcpy(temp, UitViewModeHelp, strlen(UitViewModeHelp)); tty_bright(StatusBrightness); tty_foreground(StatusForeground); tty_background(StatusBackground); window_cursormove(status_win, 0, 0); window_write(temp, SCREEN_X); } char char_to_print(char c) { return is_print(c) ? c : '.'; } void update_line(int line) { int r; unsigned char temp[256], ln[16]; memset(ln, 0, 16); memset(temp, ' ', SCREEN_X); lseek(handle, line * 16, SEEK_SET); if ((r = read(handle, ln, 16))) sprintf(temp, " %07X0 %02X %02X %02X %02X %02X %02X %02X %02X %02X\ %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c \n", line, ln[0], ln[1], ln[2], ln[3], ln[4], ln[5], ln[6], ln[7], ln[8], ln[9], ln[10], ln[11], ln[12], ln[13], ln[14], ln[15], char_to_print(ln[0]), char_to_print(ln[1]), char_to_print(ln[2]), char_to_print(ln[3]), char_to_print(ln[4]), char_to_print(ln[5]), char_to_print(ln[6]), char_to_print(ln[7]), char_to_print(ln[8]), char_to_print(ln[9]), char_to_print(ln[10]), char_to_print(ln[11]), char_to_print(ln[12]), char_to_print(ln[13]), char_to_print(ln[14]), char_to_print(ln[15])); if (r != 16) { memset(temp + 13 + r * 3, ' ', (16 - r) * 3 - 1); memset(temp + 13 + 16 * 3 - 1 + 2 + r, ' ', 16 - r + 2); } window_write((char *)temp, SCREEN_X); } void update_all(void) { int i; tty_foreground(ScreenForeground); tty_background(ScreenBackground); tty_bright(ScreenBrightness); for (i = current_line; i < current_line + 16; i++) { window_cursormove(screen_win, 3 + i - current_line, 0); update_line(i); } } void clean_up(void) { if (header_text) { free(header_text); header_text = NULL; } tty_end(); tty_clrscr(); } void fatal(char *postmsg) { clean_up(); fprintf(stderr, "Fatal error : %s !\n", postmsg); exit(1); } void panic(int signum) { tcflush(0, TCIOFLUSH); switch (signum) { case SIGHUP: clean_up(); /* :-) */ fprintf(stderr, "Got SIGHUP !\n"); break; case SIGINT: clean_up(); break; case SIGTERM: case SIGQUIT: clean_up(); fprintf(stderr, "Got %s !\nbye\n", (signum == SIGTERM) ? "SIGTERM" : "SIGQUIT"); break; case SIGSEGV: tty_end(); tty_clrscr(); fprintf(stderr, "Got SIGSEGV !\n"); fprintf(stderr, "Please report to tudor@ulise.cs.pub.ro\n"); break; } exit(1); } int main(int argc, char *argv[]) { struct stat s; int need_update; struct key_struct *ks; int key, repeat_count, size; char *home, *data = NULL, *section; char tmp[256], buf[256], offset[16]; int sectionptr = 0, i, j, index, cnt = 0; termcap_init(); tty_kbdinit(0); signal(SIGTERM, panic); signal(SIGINT , panic); signal(SIGQUIT, panic); signal(SIGSEGV, panic); signal(SIGHUP, panic); signal(SIGILL, SIG_IGN); signal(SIGTRAP, SIG_IGN); signal(SIGABRT, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGCONT, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGALRM, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGFPE, SIG_IGN); if (argc != 2) { fprintf(stderr, "Usage: uitview filename\n"); exit(1); } stat(argv[1], &s); if (!(S_ISREG(s.st_mode) || S_ISBLK(s.st_mode))) { fprintf(stderr, "%s is neither regular file nor block device.\n", argv[1]); exit(1); } handle = open(argv[1], O_RDONLY); if (handle == -1) { fprintf(stderr, "Cannot open file %s\n", argv[1]); exit(1); } regular_file = S_ISREG(s.st_mode); if (home = getenv("HOME")) { strcpy(homedirectory, home); strcpy(configfile, home); if (configfile[strlen(configfile) - 1] != '/') strcat(configfile, "/"); } strcat(configfile, ".uitrc."); strcat(configfile, tty_type); config = configuration_init(configfile); if (configuration_getstatus(config) == STATUS_OK) { sectionptr = configuration_getsectionptr(config,"[Setup]"); if (sectionptr == -1) puts("[Setup] section missing."); else { #ifdef HAVE_LINUX configuration_getfielddata(config, sectionptr, "LinuxConsole", &data, 1, DO_SEEK); LinuxConsole = data && strcmp(data, "ON") == 0; configuration_getfielddata(config, sectionptr, "ColorMonitor", &data, 1, DO_SEEK); ColorMonitor = data && strcmp(data, "ON") == 0; #endif } sectionptr = configuration_getsectionptr(config, "[UITVIEW-Setup]"); if (sectionptr == -1) fprintf(stderr, "[UITVIEW-Setup] section missing."); else { configuration_getfielddata(config, sectionptr, "UitViewModeHelp", &data, 1, DO_SEEK); if (data) strncpy(UitViewModeHelp, data, 256); } section = (LinuxConsole && ColorMonitor) ? cSection : bwSection; sectionptr = configuration_getsectionptr(config, section); if (sectionptr == -1) fprintf(stderr, "%s section missing.", section); else for (i = 0; i < VIEWER_FIELDS; i++) { configuration_getfielddata(config, sectionptr, VIEWERFields[i], &data, 1, DO_SEEK); if (!data || (index = tty_getcolorindex(data))== -1) fprintf(stderr, "Invalid %s (%s).\n", VIEWERFields[i], data); else VIEWERColors[i] = index; } sectionptr = configuration_getsectionptr(config, "[UITVIEW-Keys]"); if (sectionptr == -1) fprintf(stderr, "[UITVIEW-Keys] section missing."); else { char key_seq[16]; char *contents; for (i = 0; i < MAX_KEYS; i++) { configuration_getfielddata(config, sectionptr, key_seq, &contents, 1, NO_SEEK); if (*key_seq == 0) break; if (contents == NULL) continue; for (j = 0; j < BUILTIN_OPERATIONS; j++) if (strcmp(contents, built_in[j]) == 0) break; if (j < BUILTIN_OPERATIONS) { if (tty_key_convert(key_seq)) tty_key_list_insert(key_seq, (void *) -(j + 1)); } else fprintf(stderr, "Invalid builtin operation: %s\n", contents); } if (i == MAX_KEYS) fprintf(stderr, "Too many key sequences. Only %d are allowed.\n", MAX_KEYS); } configuration_end(config); } else { fprintf(stderr, "\nCannot open configuration file %s\n", configfile); fprintf(stderr, "See the manual page for details.\n"); fprintf(stderr, "If your TERM environment variable is, let's say,\n"); fprintf(stderr, "vt102, your configuration file name should be\n"); fprintf(stderr, ".uitrc.vt102 . Try renaming .uitrc.console ...\n"); exit(1); } tty_getsize(&SCREEN_X, &SCREEN_Y); if (SCREEN_Y < 24) { SCREEN_Y = 24; fprintf(stderr, "WARNING: can't use less than 24 columns.\n"); } header_text = (char *)malloc(strlen(argv[1]) + 10); sprintf(header_text, " File: %s", argv[1]); title_win = window_init(0, 0, 1, SCREEN_X); header_win = window_init(0, 1, 1, SCREEN_X); screen_win = window_init(0, 2, SCREEN_Y - 2, SCREEN_X); status_win = window_init(0, SCREEN_Y - 1, 1, SCREEN_X); tty_init(); offset[cnt] = 0; current_line = 0; restart: tty_foreground(ScreenForeground); tty_background(ScreenBackground); tty_bright(ScreenBrightness); tty_clrscr(); settitle(); setstatus(); setheader(); tty_foreground(ScreenForeground); tty_background(ScreenBackground); tty_bright(ScreenBrightness); window_cursormove(screen_win, 1, 0); window_write(info_txt, sizeof(info_txt)); window_cursormove(screen_win, 2, 0); window_write(line_txt, sizeof(line_txt)); window_cursormove(screen_win, 20, 0); window_write(seek_txt, sizeof(seek_txt)); size = filelength(); lines = size / 16 + (size % 16 ? 1 : 0); current_line = min(current_line, (lines / 16) * 16); update_all(); window_cursormove(screen_win, 20, strlen(seek_txt)); window_write(offset, cnt); while (1) { ks = tty_getkey(&repeat_count); key = (int)ks->aux_data; if (key == 0) key = ks->key_seq[0]; size = filelength(); lines = size / 16 + (size % 16 ? 1 : 0); switch (key) { case BUILTIN_CursorUp: need_update = 0; while (repeat_count--) { if (current_line == 0) break; current_line--, need_update = 1; } if (need_update) update_all(); break; case BUILTIN_CursorDown: need_update = 0; while (repeat_count--) { if (current_line >= lines - 16) break; current_line++, need_update = 1; } if (need_update) update_all(); break; case BUILTIN_PageUp: if (current_line == 0) break; current_line = max(0, current_line - 16); update_all(); break; case BUILTIN_PageDown: if (current_line >= lines - 16) break; current_line += 16; update_all(); break; case BUILTIN_Home: if (current_line) { current_line = 0; update_all(); } break; case BUILTIN_End: if (regular_file && current_line < lines - 16) { current_line = lines - 16; update_all(); } break; case BUILTIN_Refresh: goto restart; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': if (cnt < 8) { window_cursormove(screen_win, 20, strlen(seek_txt) + cnt); window_write((char *)&key, 1); offset[cnt++] = key; } else tty_beep(); break; case KEY_BACKSPACE: if (cnt) cnt --; window_cursormove(screen_win, 20, strlen(seek_txt) + cnt); window_write(" ", 1); break; case KEY_ENTER: if (cnt == 0) tty_beep(); else { offset[cnt] = 0; sscanf(offset, "%x", &cnt); window_cursormove(screen_win, 20, strlen(seek_txt)); window_write(" ", 8); if (cnt < 0) cnt = 0; if (cnt > size) cnt = size; current_line = cnt >> 4; update_all(); cnt = 0; } break; case BUILTIN_Exit: goto end; } window_cursormove(screen_win, 20, strlen(seek_txt) + cnt); } end: clean_up(); return 0; }