/* 028 11-Jan-87 ovview.c Copyright (c) 1987 by Blue Sky Software. All rights reserved. */ #include #include #include #include #include "ov.h" #define H_bar (0xcd) #define V_bar (179) #define Vnextch(fh) ((curp < endp) ? *curp++ : vnextch(fh)) /* speed up */ #define Vprevch(fh) ((curp > bufp) ? *--curp : vprevch(fh)) /* buffer access */ extern unsigned char far *curp; /* current char position */ extern unsigned char far *bufp, far *endp; /* buffer begin/end pointers */ static int (*mark_func)(); /* pointer to marker function */ static int nlines; /* # lines displayed on screen */ static unsigned char ascmode; /* true means ascii mode display */ static unsigned char bitmask; /* for 7 or 8 bit display mode */ static int inf; /* handle for file being viewed */ static int margin; /* margin for right/left scrolling */ static long tos; /* top of screen offset in file */ static long markers[5]; /* marker positions */ /* function delcarations created by -Zg option - ALTCALL added NOTE: anything called by menu routine cannot be ALTCALL */ /*global*/ int view(void); /*global*/ int view_move(int ); static int view_exit(void), view_down(void), view_up(void), view_next(void); static int view_prev(void), view_tof(void), view_eof(void); static int view_right(void), view_left(void), view_set(void), view_goto(void); static int do_mark(void), setmark(void), gomark(void), ALTCALL view_line(void); static int ALTCALL fmt_asc_line(char *,int *), ALTCALL fmt_hex_line(char *,int *); static int view_7bit(void), view_8bit(void), view_asc(void), view_hex(void); static int ALTCALL align(void); static int ALTCALL backup(int ); static int ALTCALL peol(void); static int ALTCALL nsol(void); static int ALTCALL more2view(void); static struct key_ent { /* table mapping movement keys to function */ int key; int (*func)(); } key2func[] = { { DOWN, view_next }, { UP, view_prev }, { PGDN, view_down }, { PGUP, view_up }, { HOME, view_tof }, { END, view_eof }, { RIGHT, view_right }, { LEFT, view_left } }; #define NMOVKEYS (8) extern MENU_STATE curmenu; extern MENU top_file_menu[], *top_menu; static char setgo[] = "Set/Goto marker"; static MENU mark_menu[] = { { "1", setgo, do_mark, NULL }, { "2", setgo, do_mark, NULL }, { "3", setgo, do_mark, NULL }, { "4", setgo, do_mark, NULL }, { "5", setgo, do_mark, NULL }, { NULL, NULL, NULL, NULL } }; MENU top_view_menu[] = { { "Dwn", "Page down in the file", view_down, NULL }, { "Up", "Page up in the file", view_up, NULL }, { "Nxt", "Advance one line", view_next, NULL }, { "Prv", "Backup one line", view_prev, NULL }, { "TOF", "Goto Top Of File", view_tof, NULL }, { "EOF", "Goto End Of File", view_eof, NULL }, { "Rght", "Scroll right 8 characters", view_right, NULL }, { "Left", "Scroll left 8 characters", view_left, NULL }, { "Set", "Set marker at current position", view_set, mark_menu }, { "Goto", "Goto set marker position", view_goto, mark_menu }, { "Ascii", "View file as ASCII characters", view_asc, NULL }, { "Hex", "View file in hexadecimal", view_hex, NULL }, { "7bit", "View low 7 bits of each character", view_7bit, NULL }, { "8bit", "View all 8 bits of each character", view_8bit, NULL }, { "Quit", "Return to file display", view_exit, top_file_menu }, { NULL, NULL, NULL, NULL } }; extern WINDOW cw; extern char *cantopen; extern FILE_ENT files[]; extern unsigned char view_display, restricted; int ALTCALL vbuf_init(int ); /* declarations for buffer routines */ int ALTCALL vbuf_free(void); unsigned long ALTCALL vtell(void); int ALTCALL vseek(int ,long ), ALTCALL vnextch(int ), ALTCALL vprevch(int ); #define view_seek(off) vseek(inf,off) /****************************************************************************** ** V I E W ** *****************************************************************************/ view() { /* view the current file at the terminal */ int i; register char *fn; register FILE_ENT *fp; /* don't try to view file if its empty */ fp = &files[cw.curidx]; /* a couple of quick pointers */ if (fp->size == 0) show_error(0,8,1,"This file is empty!"); bitmask = 0xff; /* defaults: 8 bit, ascii, left edge */ ascmode = TRUE; margin = 0; /* open the file to be viewed, error out if can't open */ if ((inf = open((fn = fname(fp)),O_RDONLY|O_BINARY)) == -1) { free(fn); show_error(1,8,3,cantopen,fp->name,": "); } savescreen(); /* save current display image */ restricted = TRUE; /* disable special file commands */ view_display = TRUE; /* yes, we are viewing */ for (i = 0; i < 5; i++) /* set markers to TOF */ markers[i] = 0L; vbuf_init(inf); /* initialize view buffer system */ center_text(FIRST_VROW-1,fn); /* show file name */ free(fn); view_down(); /* display the first screen of file data */ top_menu = top_view_menu; /* setup the view menu as the main menu */ } /****************************************************************************** ** V I E W _ E X I T ** *****************************************************************************/ static int view_exit() { /* exit the view display, return to file display */ close(inf); /* close file */ vbuf_free(); /* release memory */ top_menu = top_file_menu; /* restore file menu as main */ restricted = FALSE; /* all commands are enabled */ view_display = FALSE; /* not viewing */ restorescreen(); /* redisplay prior screen image */ } /****************************************************************************** ** V I E W _ D O W N ** *****************************************************************************/ static int view_down() { /* page down into the view buffer/file */ register int i; if (!more2view()) /* nothing to do if no more data to view */ return; nlines = 0; /* no lines displayed yet */ tos = vtell(); /* remember where top of screen is */ /* display up to a screen full of file data, clear the screen as we go */ for (i = 0; i < VIEW_ROWS; i++) { gotorc(i+FIRST_VROW,0); /* position to line */ if (view_line()) /* display a single line */ nlines++; /* count lines displayed */ } } /****************************************************************************** ** V I E W _ U P ** *****************************************************************************/ static int view_up() { /* page up into the view buffer */ long curoff; /* back two screen's worth, or to the top line in memory and use view_down() to display the screen - only display if we really backed up (might be at TOF) */ curoff = vtell(); /* where we were */ view_seek(tos); /* quickly to top of screen */ if (backup(VIEW_ROWS)) /* try to backup another screen */ view_down(); /* display prior screen if backed up */ else view_seek(curoff); /* must be tof, back to where we were */ } /****************************************************************************** ** V I E W _ N E X T ** *****************************************************************************/ static int view_next() { /* display the next line in the buffer/file */ long curoff; if (!more2view()) /* nothing to do if no more data to view */ return; /* set the new top of screen location */ if (ascmode) { /* ascii mode display? */ curoff = vtell(); /* save where we are */ view_seek(tos); /* to top of screen */ nsol(); /* to start of next line */ tos = vtell(); /* its the new top of screen */ view_seek(curoff); /* back to bottom of screen */ } else /* hex mode */ tos += 16; /* tos is just the next hex line */ /* scroll the screen up one line to make room for the new line at bottom */ delete_line(FIRST_VROW,VIEW_ROWS-1); gotorc(FIRST_VROW+VIEW_ROWS-1,0); /* cursor to the last display line */ view_line(); /* display the line */ } /****************************************************************************** ** V I E W _ P R E V ** *****************************************************************************/ static int view_prev() { /* display the previous line in the buffer */ long curoff; curoff = vtell(); /* where we are now */ view_seek(tos); /* old top of screen */ if (backup(1)) { /* can we backup another line */ tos = vtell(); /* if so, its new tos */ insert_line(FIRST_VROW+1,VIEW_ROWS-1); /* insert a blank line */ gotorc(FIRST_VROW,0); /* cursor to first line */ view_line(); /* display the line */ view_seek(curoff); /* back to old bottom */ if (nlines < VIEW_ROWS) /* is a full screen displayed? */ nlines++; /* no, one more displyed now */ else backup(1); /* yes, back one line */ } else /* couldn't backup, must be tof */ view_seek(curoff); } /****************************************************************************** ** V I E W _ T O F ** *****************************************************************************/ static int view_tof() { /* backup and display the top of the file */ view_seek(0L); /* just go to top of file */ view_down(); /* and display a screen */ } /****************************************************************************** ** V I E W _ E O F ** *****************************************************************************/ static int view_eof() { /* display the end of the file */ view_seek(files[cw.curidx].size); /* seek to eof */ backup(VIEW_ROWS); /* backup a screen full */ view_down(); /* display a screen full */ } /****************************************************************************** ** V I E W _ M O V E ** *****************************************************************************/ view_move(mov_cmd) /* move around the view buffer/file in response to */ int mov_cmd; /* single key commands when viewing a file */ { register int i; /* basically, we just map the special keys to the same functions performed by the menu options */ for (i = 0; i < NMOVKEYS; i++) if (mov_cmd == key2func[i].key) { (*key2func[i].func)(); break; } } /***************************************************************************** V I E W _ S E T / G O T O / M A R K *****************************************************************************/ static int view_set() { /* prepare to set a marker to current position */ mark_func = setmark; /* use the setmark routine later */ } static int view_goto() { /* prepare to goto a marker position */ mark_func = gomark; /* use the gomark routine later */ } static int do_mark() { /* set or goto a marker position */ (*mark_func)(); } static int setmark() { /* set a marker position */ markers[curmenu.current_selection] = tos; } static int gomark() { /* goto a marker position */ tos = markers[curmenu.current_selection]; /* where tos should be */ align(); /* start at begining of line */ view_down(); /* display screen full */ } /***************************************************************************** V I E W _ L I N E *****************************************************************************/ static int ALTCALL view_line() { /* display a single line of the file */ int col, ch; char line[SCREEN_COLS+1]; if (ascmode) /* format the line as ascii or hex data */ ch = fmt_asc_line(line,&col); else ch = fmt_hex_line(line,&col); disp_str(line); /* make one call to display line */ if (col < margin+SCREEN_COLS-1) /* clear if < full line displayed */ clr_eol(); return(ch != EOF || col); /* return true if something displayed */ } /***************************************************************************** F M T _ A S C _ L I N E ****************************************************************************/ static int ALTCALL fmt_asc_line(op,colp) /* format an ascii line for display */ char *op; int *colp; { register int ch, col = 0; int i, endcol = margin + SCREEN_COLS; while ((ch = Vnextch(inf)) != EOF && (ch = ch & bitmask) != '\n') if (ch == '\t') { for (i = 8 - (col & 7); i; i--, col++) if (col >= margin && col < endcol) *op++ = ' '; } else if (ch != '\r' && ch != '\0') { if (col >= margin && col < endcol) *op++ = ch; col++; } *op = '\0'; /* null terminate it for disp_str */ *colp = col; /* tell caller the # cloumns */ return(ch); /* and if EOF was reached */ } /****************************************************************************** F M T _ H E X _L I N E *****************************************************************************/ static int ALTCALL fmt_hex_line(op,colp) /* format a hex line for later display */ register char *op; int *colp; { int ch, ach, j; register int i; char offstr[9], *ap; static char bin2hex[] = "0123456789ABCDEF"; /* test if there is anything to format */ if (vnextch(inf) == EOF) { *colp = 0; *op = '\0'; return(EOF); } else vprevch(inf); /* format data offset into buffer */ ultoa(vtell(),offstr,16); /* offset to hex */ j = strlen(offstr); for (i = 6 - j; i > 0; i--) /* zero fill */ *op++ = '0'; if (j <= 6) /* don't use more than 6 digits */ strcpy(op,offstr); else strcpy(op,offstr+j-6); strupr(op); /* ultoa leaves A-F in lower case */ strcat(op," "); /* go beyond the offset */ op += strlen(op); ap = op + 53; /* where ascii data starts */ *ap++ = V_bar; /* might as well do it now */ /* setup data in hex (and ascii) */ for (i = 16; i; i--) { /* at most 16 bytes to fmt */ ch = Vnextch(inf); /* next char from file */ if (ch == EOF) /* done? */ break; *op++ = bin2hex[(ch >> 4) & 0x0f]; /* hexalate it */ *op++ = bin2hex[ch & 0x0f]; *op++ = ' '; if (((i+3) & 3) == 0) /* extra spacer every 4 bytes */ *op++ = ' '; if ((ach = ch & bitmask) < ' ') /* do the ascii char, '.' if ctrl ch */ *ap++ = '.'; else *ap++ = ach; } /* blank fill if EOF was reached */ for ( ; i; i--) { /* i is # chars to blank fill */ strncpy(op," ",3); op += 3; if (((i+3) & 3) == 0) *op++ = ' '; *ap++ = ' '; } *op++ = ' '; /* up to ascii data */ *ap++ = V_bar; /* closing bar at end */ *ap = '\0'; /* The Terminator */ *colp = 74; /* tell call how many columns */ return(ch); /* and if EOF was reached */ } /***************************************************************************** V I E W _ R I G H T / L E F T *****************************************************************************/ static int view_right() { /* scroll right 8 characters */ margin += 8; view_current(); disp_margin(); } static int view_left() { /* scroll left 8 characters */ if (margin >= 8) { margin -= 8; view_current(); disp_margin(); } } static int disp_margin() { /* display the viewing margins */ char marstr[11]; if (margin) { itoa(margin,marstr,10); disp_msg(2,"COL: ",marstr); } else /* must have just gone to 0 */ clr_msg(); } /***************************************************************************** V I E W _ n B I T *****************************************************************************/ static int view_7bit() { /* display data using low order 7 bits */ if (bitmask != 0x7f) { bitmask = 0x7f; view_current(); } } static int view_8bit() { /* display data using all 8 bits per char */ if (bitmask != 0xff) { bitmask = 0xff; view_current(); } } static int view_current() { /* redisplay the current screen */ view_seek(tos); view_down(); } /***************************************************************************** V I E W _ A S C *****************************************************************************/ static int view_asc() { /* set ascii mode display */ if (!ascmode) { /* only need to change if in hex mode */ ascmode = TRUE; /* set ascii mode */ align(); /* make sure were at begining of line */ view_down(); /* redisplay in ascii format */ } } /***************************************************************************** V I E W _ H E X *****************************************************************************/ static int view_hex() { /* set hex mode display */ if (ascmode) { /* only need to change if in ascii mode */ ascmode = FALSE; /* set hex mode */ align(); /* make sure were at begining of line */ view_down(); /* redisplay in ascii format */ } } /***************************************************************************** A L I G N *****************************************************************************/ static int ALTCALL align() { /* align tos to be at the start of a line */ if (ascmode) { /* ascii mode? */ view_seek(tos); /* backup to current top of screen */ if (backup(1)) /* make sure were at the start of */ nsol(); /* the current line */ } else { /* hex mode */ tos &= ~((long) 0x0f); /* force a paragraph boundry */ view_seek(tos); /* backup to current top of screen */ } } /***************************************************************************** B A C K U P *****************************************************************************/ static int ALTCALL backup(todo) /* backup todo lines from current position */ int todo; { register int i; int part, bytes; unsigned long off, lines; /* backup in hex mode */ if (!ascmode) { /* different if in hex mode */ off = vtell(); /* current loc in file */ lines = off >> 4; /* # full hex display lines above */ part = (bytes = off & (long) 0x0f) > 0; /* may be partial line if at eof */ if (todo > lines + part) { /* more todo than are? */ view_seek(0L); /* just goto tof */ return(lines + part); /* went back this # lines */ } else { view_seek(off - (((todo - part) << 4)+bytes)); /* backup todo lines */ return(todo); } } /* backup in ascii mode */ /* special case backing up from EOF - there may or may not be a \n at the end of the last line */ if (vnextch(inf) == EOF) { /* at end of file? */ vprevch(inf); /* always backup at least one char */ i = 1; /* we will backup 1 line here */ if (peol() == '\n') /* goto start of prev line */ vnextch(inf); } else { /* not at EOF, setup for loop down below */ i = 0; vprevch(inf); } /* backup todo ascii lines, 1 line may have been done above */ for ( ; i < todo; i++) { if (peol() == EOF) /* goto end of prev line */ break; if (peol() == '\n') /* end of prev prev line */ vnextch(inf); /* start of prev line */ } return(i); /* tell caller how many ascii lines backed up */ } static int ALTCALL peol() { /* move to end of prev line */ register int ch; while ((ch = Vprevch(inf)) != '\n' && ch != EOF) ; /* end of prev line */ return(ch); } static int ALTCALL nsol() { /* move to start of next line */ register int ch; while ((ch = Vnextch(inf)) != '\n' && ch != EOF) ; /* start of next line */ return(ch); } /***************************************************************************** M O R E 2 V I E W *****************************************************************************/ static int ALTCALL more2view() { /* return true if more data to view */ return(vtell() < files[cw.curidx].size); }