707 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			707 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* Copyright (c) 1985 Ceriel J.H. Jacobs */
 | |
| 
 | |
| # ifndef lint
 | |
| static char rcsid[] = "$Header$";
 | |
| # endif
 | |
| 
 | |
| # define _COMMANDS_
 | |
| 
 | |
| # include "in_all.h"
 | |
| # include "commands.h"
 | |
| # include "output.h"
 | |
| # include "process.h"
 | |
| # include "help.h"
 | |
| # include "term.h"
 | |
| # include "prompt.h"
 | |
| # include "getline.h"
 | |
| # include "getcomm.h"
 | |
| # include "pattern.h"
 | |
| # include "display.h"
 | |
| # include "options.h"
 | |
| # include "machine.h"
 | |
| # include "keys.h"
 | |
| # include "main.h"
 | |
| # include "assert.h"
 | |
| # if USG_OPEN
 | |
| # include <fcntl.h>
 | |
| # include <errno.h>
 | |
| extern int errno;
 | |
| # endif
 | |
| # if BSD4_2_OPEN
 | |
| # include <sys/file.h>
 | |
| # include <errno.h>
 | |
| extern int errno;
 | |
| # endif
 | |
| # if POSIX_OPEN
 | |
| # include <sys/types.h>
 | |
| # include <fcntl.h>
 | |
| # include <errno.h>
 | |
| # endif
 | |
| 
 | |
| char	*strcpy(), *strcat();
 | |
| 
 | |
| static long lastcount;		/* Save last count for '.' command */
 | |
| static int lastcomm;		/* Save last command for '.' command */
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| STATIC int
 | |
| do_nocomm(cnt) long cnt; {	/* Do nothing */
 | |
| }
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| int
 | |
| do_chkm(cnt) long cnt; {	/* Change key map */
 | |
| 	register struct keymap *p;
 | |
| 
 | |
| 	if (!(p = othermap)) {
 | |
| 		error("No other keymap");
 | |
| 		return;
 | |
| 	}
 | |
| 	othermap = currmap;
 | |
| 	currmap = p;
 | |
| }
 | |
| 
 | |
| static int searchdir;		/* Direction of last search */
 | |
| 
 | |
| /*
 | |
|  * Perform searches
 | |
|  */
 | |
| 
 | |
| STATIC VOID
 | |
| do_search(str,cnt,dir) char *str; long cnt; int dir; {
 | |
| 	register char *p;
 | |
| 	register long lineno;
 | |
| 
 | |
| 	if (str) {
 | |
| 		/*
 | |
| 		 * We have to get a pattern, which we have to prompt for
 | |
| 		 * with the string "str".
 | |
| 		 */
 | |
| 		if ((p = readline(str)) == 0) {
 | |
| 			/*
 | |
| 			 * User cancelled command
 | |
| 			 */
 | |
| 			return;
 | |
| 		}
 | |
| 		if ((p = re_comp(p))) {
 | |
| 			/*
 | |
| 			 * There was an error in the pattern
 | |
| 			 */
 | |
| 			error(p);
 | |
| 			return;
 | |
| 		}
 | |
| 		searchdir = dir;
 | |
| 	}
 | |
| 	if (dir < 0) lineno = scr_info.firstline;
 | |
| 	else lineno = scr_info.lastline;
 | |
| 	for (;;) {
 | |
| 		p = 0;
 | |
| 		if ((lineno += dir) > 0) p = getline(lineno, 0);
 | |
| 		if (interrupt) return;
 | |
| 		if (!p) {	/* End of file reached */
 | |
| 			error("pattern not found");
 | |
| 			return;
 | |
| 		}
 | |
| 		if (re_exec(p) && --cnt <= 0) {
 | |
| 			/*
 | |
| 			 * We found the pattern, and we found it often enough.
 | |
| 			 * Pity that we still don't know where the match is.
 | |
| 			 * We only know the linenumber. So, we just hope the
 | |
| 			 * following will at least bring it on the screen ...
 | |
| 			 */
 | |
| 			(VOID) display(lineno,0,pagesize,0);
 | |
| 			(VOID) scrollb(2,0);
 | |
| 			redraw(0);
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 	/* NOTREACHED */
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_fsearch(cnt) long cnt; {	/* Forward search */
 | |
| 
 | |
| 	do_search("/", cnt, 1);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_bsearch(cnt) long cnt; {	/* Backward search */
 | |
| 
 | |
| 	do_search("?", cnt, -1);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Repeat last search in direction "dir"
 | |
|  */
 | |
| 
 | |
| STATIC int
 | |
| n_or_rn_search(cnt,dir) long cnt; int dir; {
 | |
| 	register char *p;
 | |
| 
 | |
| 	if (dir == 1) {
 | |
| 		p = "/\r";
 | |
| 	}
 | |
| 	else if (dir == -1) {
 | |
| 		p = "?\r";
 | |
| 	}
 | |
| 	else {
 | |
| 		error("No previous pattern");
 | |
| 		return;
 | |
| 	}
 | |
| 	if (!stupid) clrbline();
 | |
| 	putline(p);
 | |
| 	flush();
 | |
| 	do_search((char *) 0, cnt, dir);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_nsearch(cnt) long cnt; {	/* Repeat search in same direction */
 | |
| 	
 | |
| 	n_or_rn_search(cnt,searchdir);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_rnsearch(cnt) long cnt; {	/* Repeat search in opposite direction */
 | |
| 
 | |
| 	n_or_rn_search(cnt, -searchdir);
 | |
| }
 | |
| 
 | |
| STATIC int shell(esc_ch, cnt) long cnt;
 | |
| {
 | |
| 	register char *p;
 | |
| 	static char buf[2];
 | |
| 
 | |
| 	buf[0] = esc_ch;
 | |
| 	if (p = readline(buf)) {
 | |
| 		shellescape(p, esc_ch);
 | |
| 		if (cnt >= 0 && !hardcopy) {
 | |
| 			p = startcomm;
 | |
| 			startcomm = 0;
 | |
| 			ret_to_continue();
 | |
| 			putline(TI);
 | |
| 			if (!p) {
 | |
| 				/*
 | |
| 				 * Avoid double redraw.
 | |
| 				 * After a "startcomm", a redraw will
 | |
| 				 * take place anyway.
 | |
| 				 */
 | |
| 				redraw(1);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_shell(cnt) long cnt; {	/* Execute a shell escape */
 | |
| 	shell('!', cnt);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_pipe(cnt) long cnt; {	/* Execute a shell escape */
 | |
| 	shell('|', cnt);
 | |
| }
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| STATIC int
 | |
| do_writefile(cnt) long cnt; {	/* Write input to a file */
 | |
| 	register char *p;
 | |
| 	int fd;
 | |
| 
 | |
| 	if ((p = readline("Filename: ")) == 0 || !*p) {
 | |
| 		/*
 | |
| 		 * No file name given
 | |
| 		 */
 | |
| 		return;
 | |
| 	}
 | |
| # if USG_OPEN || BSD4_2_OPEN || POSIX_OPEN
 | |
| 	if ((fd = open(p,O_CREAT|O_EXCL|O_WRONLY,0644)) < 0) {
 | |
| 		if (errno == EEXIST) {
 | |
| 			error("File exists");
 | |
| 			return;
 | |
| 		}
 | |
| 		error("Could not open file");
 | |
| 		return;
 | |
| 	}
 | |
| # else
 | |
| 	if (!access(p,0)) {
 | |
| 		error("File exists");
 | |
| 		return;
 | |
| 	}
 | |
| 	if ((fd = creat(p,0644)) < 0) {
 | |
| 		error("Could not open file");
 | |
| 		return;
 | |
| 	}
 | |
| # endif
 | |
| 	wrt_fd(fd);
 | |
| 	(VOID) close(fd);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| wrt_fd(fd)
 | |
| {
 | |
| 	register long l = 1;
 | |
| 	register char *p = getline(l,0), *pbuf;
 | |
| 	char buf[1024];
 | |
| 
 | |
| 	while (p) {
 | |
| 		pbuf = buf;
 | |
| 		while (p && pbuf < &buf[1024]) {
 | |
| 			if (!*p) {
 | |
| 				*pbuf++ = '\n';
 | |
| 				p = getline(++l,0);
 | |
| 			}
 | |
| 			else *pbuf++ = *p++ & 0177;
 | |
| 		}
 | |
| 		if (write(fd, buf, pbuf - buf) < 0) {
 | |
| 			error("Write failed");
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_absolute(cnt) long cnt; {	/* Go to linenumber "cnt" */
 | |
| 
 | |
| 	if (!getline(cnt,0)) {	/* Not there or interrupt */
 | |
| 		if (!interrupt) {
 | |
| 			/*
 | |
| 			 * User did'nt give an interrupt, so the line number
 | |
| 			 * was too high. Go to the last line.
 | |
| 			 */
 | |
| 			do_lline(cnt);
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 	(VOID) display(cnt,0,pagesize,1);
 | |
| }
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| STATIC int
 | |
| do_visit(cnt) long cnt; {	/* Visit a file */
 | |
| 	register char *p;
 | |
| 	static char fn[128];	/* Keep file name */
 | |
| 
 | |
| 	if ((p = readline("Filename: ")) == 0) {
 | |
| 		return;
 | |
| 	}
 | |
| 	if (*p) {
 | |
| 		(VOID) strcpy(fn,p);
 | |
| 		visitfile(fn);
 | |
| 	}
 | |
| 	else {
 | |
| 		/*
 | |
| 		 * User typed a return. Visit the current file
 | |
| 		 */
 | |
| 		if (!(p = filenames[filecount])) {
 | |
| 			error("No current file");
 | |
| 			return;
 | |
| 		}
 | |
| 		visitfile(p);
 | |
| 	}
 | |
| 	(VOID) display(1L, 0, pagesize, 1);
 | |
| }
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| STATIC int
 | |
| do_error(cnt) long cnt; {	/* Called when user types wrong key sequence */
 | |
| 
 | |
| 	error(currmap->k_help);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Interface routine for displaying previous screen,
 | |
|  * depending on cflag.
 | |
|  */
 | |
| 
 | |
| STATIC int
 | |
| prev_screen(sz,really) int sz, really; {
 | |
| 	register int retval;
 | |
| 
 | |
| 	retval = scrollb(sz - 1, really && cflag);
 | |
| 	if (really && !cflag) {
 | |
| 		/*
 | |
| 		 * The previous call did not display anything, but at least we
 | |
| 		 * know where to start
 | |
| 		 */
 | |
| 		return display(scr_info.firstline, scr_info.nf, sz, 1);
 | |
| 	}
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Interface routine for displaying the next screen,
 | |
|  * dependent on cflag.
 | |
|  */
 | |
| 
 | |
| STATIC int
 | |
| next_screen(sz,really) int sz, really; {
 | |
| 
 | |
| 	register int t;
 | |
| 	register struct scr_info *p = &scr_info;
 | |
| 
 | |
| 	if (cflag) {
 | |
| 		return scrollf(sz-1,really);
 | |
| 	}
 | |
| 	t = p->tail->cnt - 1;
 | |
| 	if (p->lastline == p->firstline) {
 | |
| 		t += p->nf;
 | |
| 	}
 | |
| 	return display(p->lastline, t, sz, really);
 | |
| }
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| STATIC int
 | |
| do_redraw(cnt) long cnt; {
 | |
| 
 | |
| 	redraw(1);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| page_size(cnt) unsigned cnt; {
 | |
| 
 | |
| 	if (cnt) {
 | |
| 		if (cnt > maxpagesize) return maxpagesize;
 | |
| 		if (cnt < MINPAGESIZE) return MINPAGESIZE;
 | |
| 		return (int) cnt;
 | |
| 	}
 | |
| 	return pagesize;
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_forward(cnt) long cnt; {	/* Display next page */
 | |
| 	register int i;
 | |
| 
 | |
| 	i = page_size((unsigned) cnt);
 | |
| 	if (status & EOFILE) {
 | |
| 		/*
 | |
| 		 * May seem strange, but actually a visit to the next file
 | |
| 		 * has already been done here
 | |
| 		 */
 | |
| 		(VOID) display(1L,0,i,1);
 | |
| 		return;
 | |
| 	}
 | |
| 	(VOID) next_screen(i,1);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_backward(cnt) long cnt; {
 | |
| 	register int i, temp;
 | |
| 
 | |
| 	i = page_size((unsigned) cnt);
 | |
| 	if (!(status & START)) {
 | |
| 		(VOID) prev_screen(i,1);
 | |
| 		return;
 | |
| 	}
 | |
| 	if (stdf < 0) {
 | |
| 		(VOID) display(1L,0,i,1);
 | |
| 		return;
 | |
| 	}
 | |
| 	/*
 | |
| 	 * The next part is a bit clumsy.
 | |
| 	 * We want to display the last page of the previous file (for which
 | |
| 	 * a visit has already been done), but the pagesize may temporarily
 | |
| 	 * be different because the command had a count
 | |
| 	 */
 | |
| 	temp = pagesize;
 | |
| 	pagesize = i;
 | |
| 	do_lline(cnt);
 | |
| 	pagesize = temp;
 | |
| }
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| STATIC int
 | |
| do_firstline(cnt) long cnt; {	/* Go to start of input */
 | |
| 
 | |
| 	do_absolute(1L);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_lline(cnt) long cnt; {	/* Go to end of input */
 | |
| 	register int i = 0;
 | |
| 	register int j = pagesize - 1;
 | |
| 
 | |
| 	if ((cnt = to_lastline()) < 0) {
 | |
| 		/*
 | |
| 		 * Interrupted by the user
 | |
| 		 */
 | |
| 		return;
 | |
| 	}
 | |
| 	/*
 | |
| 	 * Display the page such that only the last line of the page is
 | |
| 	 * a "~", independant of the pagesize
 | |
| 	 */
 | |
| 	while (!(display(cnt,i,j,0) & EOFILE)) {
 | |
| 		/*
 | |
| 		 * The last line could of course be very long ...
 | |
| 		 */
 | |
| 		i+= j;
 | |
| 	}
 | |
| 	(VOID) scrollb(j - scr_info.tail->cnt, 0);
 | |
| 	redraw(0);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_lf(cnt) long cnt; {		/* Display next line, or go to line */
 | |
| 
 | |
| 	if (cnt) {		/* Go to line */
 | |
| 		do_absolute(cnt);
 | |
| 		return;
 | |
| 	}
 | |
| 	(VOID) scrollf(1,1);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_upline(cnt) long cnt; {	/* Display previous line, or go to line */
 | |
| 
 | |
| 	if (cnt) {		/* Go to line */
 | |
| 		do_absolute(cnt);
 | |
| 		return;
 | |
| 	}
 | |
| 	(VOID) scrollb(1,1);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_skiplines(cnt) long cnt; {	/* Skip lines forwards */
 | |
| 
 | |
| 	/* Should be interruptable ... */
 | |
| 	(VOID) scrollf((int) (cnt + maxpagesize - 1), 0);
 | |
| 	redraw(0);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_bskiplines(cnt) long cnt; {	/* Skip lines backwards */
 | |
| 
 | |
| 	/* Should be interruptable ... */
 | |
| 	(VOID) scrollb((int) (cnt + pagesize - 1), 0);
 | |
| 	redraw(0);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_fscreens(cnt) long cnt; {	/* Skip screens forwards */
 | |
| 
 | |
| 	do {
 | |
| 		if ((next_screen(pagesize,0) & EOFILE) || interrupt) break;
 | |
| 	} while (--cnt >= 0);
 | |
| 	redraw(0);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_bscreens(cnt) long cnt; {	/* Skip screens backwards */
 | |
| 
 | |
| 	do {
 | |
| 		if ((prev_screen(pagesize,0) & START) || interrupt) break;
 | |
| 	} while (--cnt >= 0);
 | |
| 	redraw(0);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| scro_size(cnt) unsigned cnt; {
 | |
| 
 | |
| 	if (cnt >= maxpagesize) return maxpagesize;
 | |
| 	if (cnt) return (int) cnt;
 | |
| 	return scrollsize;
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_f_scroll(cnt) long cnt; {	/* Scroll forwards */
 | |
| 
 | |
| 	(VOID) scrollf(scro_size((unsigned) cnt),1);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_b_scroll(cnt) long cnt; {	/* Scroll backwards */
 | |
| 
 | |
| 	(VOID) scrollb(scro_size((unsigned) cnt),1);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_previousfile(cnt) long cnt; {/* Visit previous file */
 | |
| 
 | |
| 	if (nextfile(- (int) cnt)) {
 | |
| 		error("No (Nth) previous file");
 | |
| 		return;
 | |
| 	}
 | |
| 	redraw(0);
 | |
| }
 | |
| 
 | |
| STATIC int
 | |
| do_nextfile(cnt) long cnt; {	/* Visit next file */
 | |
| 
 | |
| 	if (nextfile((int) cnt)) {
 | |
| 		error("No (Nth) next file");
 | |
| 		return;
 | |
| 	}
 | |
| 	redraw(0);
 | |
| }
 | |
| 
 | |
| STATIC int do_lcomm();
 | |
| 
 | |
| /*
 | |
|  * The next array is initialized, sorted on the first element of the structs,
 | |
|  * so that we can perform binary search
 | |
|  */
 | |
| struct commands commands[] = {
 | |
| {"",	    0,	    do_error,	    ""},
 | |
| {"",	    0,	    do_nocomm,	    ""},
 | |
| {"bf",	    STICKY|NEEDS_COUNT,
 | |
| 		    do_previousfile,"Visit previous file"},
 | |
| {"bl",	    NEEDS_SCREEN|STICKY,
 | |
| 		    do_upline,	    "Scroll one line up, or go to line"},
 | |
| {"bot",	    STICKY,
 | |
| 		    do_lline,	    "Go to last line of the input"},
 | |
| {"bp",	    BACK|NEEDS_SCREEN|TOPREVFILE|STICKY,
 | |
| 		    do_backward,    "display previous page"},
 | |
| {"bps",	    SCREENSIZE_ADAPT|BACK|NEEDS_SCREEN|TOPREVFILE|STICKY,
 | |
| 		    do_backward,    "Display previous page, set pagesize"},
 | |
| {"bs",	    BACK|NEEDS_SCREEN|STICKY,
 | |
| 		    do_b_scroll,    "Scroll backwards"},
 | |
| {"bse",	    0,	    do_bsearch,	    "Search backwards for pattern"},
 | |
| {"bsl",	    BACK|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
 | |
| 		    do_bskiplines,  "Skip lines backwards"},
 | |
| {"bsp",	    BACK|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
 | |
| 		    do_bscreens,    "Skip screens backwards"},
 | |
| {"bss",	    SCROLLSIZE_ADAPT|BACK|NEEDS_SCREEN|STICKY,
 | |
| 		    do_b_scroll,    "Scroll backwards, set scrollsize"},
 | |
| {"chm",	    0,	    do_chkm,	    "Switch to other keymap"},
 | |
| {"exg",	    STICKY, exgmark,	    "Exchange current page with mark"},
 | |
| {"ff",	    STICKY|NEEDS_COUNT,
 | |
| 		    do_nextfile,    "Visit next file"},
 | |
| {"fl",	    NEEDS_SCREEN|STICKY,
 | |
| 		    do_lf,	    "Scroll one line down, or go to line"},
 | |
| {"fp",	    TONEXTFILE|AHEAD|STICKY,
 | |
| 		    do_forward,	    "Display next page"},
 | |
| {"fps",	    SCREENSIZE_ADAPT|TONEXTFILE|AHEAD|STICKY,
 | |
| 		    do_forward,	    "Display next page, set pagesize"},
 | |
| {"fs",	    AHEAD|NEEDS_SCREEN|STICKY,
 | |
| 		    do_f_scroll,    "Scroll forwards"},
 | |
| {"fse",	    0,	    do_fsearch,	    "Search forwards for pattern"},
 | |
| {"fsl",	    AHEAD|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
 | |
| 		    do_skiplines,   "Skip lines forwards"},
 | |
| {"fsp",	    AHEAD|NEEDS_SCREEN|STICKY|NEEDS_COUNT,
 | |
| 		    do_fscreens,    "Skip screens forwards"},
 | |
| {"fss",	    SCROLLSIZE_ADAPT|AHEAD|NEEDS_SCREEN|STICKY,
 | |
| 		    do_f_scroll,    "Scroll forwards, set scrollsize"},
 | |
| {"hlp",	    0,	    do_help,	    "Give description of all commands"},
 | |
| {"mar",	    0,	    setmark,	    "Set a mark on the current page"},
 | |
| {"nse",	    STICKY, do_nsearch,	    "Repeat the last search"},
 | |
| {"nsr",	    STICKY, do_rnsearch, "Repeat last search in other direction"},
 | |
| {"pip",     ESC,    do_pipe,	    "pipe input into shell command"},
 | |
| {"qui",	    0,	    quit,	    "Exit from yap"},
 | |
| {"red",	    0,	    do_redraw,	    "Redraw screen"},
 | |
| {"rep",	    0,	    do_lcomm,	    "Repeat last command"},
 | |
| {"shl",	    ESC,    do_shell,	    "Execute a shell escape"},
 | |
| {"tom",	    0,	    tomark,	    "Go to mark"},
 | |
| {"top",	    STICKY, do_firstline,   "Go to the first line of the input"},
 | |
| {"vis",	    0,	    do_visit,	    "Visit a file"},
 | |
| {"wrf",	    0,	    do_writefile,   "Write input to a file"},
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Lookup string "s" in the commands array, and return index.
 | |
|  * return 0 if not found.
 | |
|  */
 | |
| 
 | |
| int
 | |
| lookup(s) char *s; {
 | |
| 	register struct commands *l, *u, *m;
 | |
| 
 | |
| 	l = &commands[2];
 | |
| 	u = &commands[sizeof(commands) / sizeof(*u) - 1];
 | |
| 	do {
 | |
| 		/*
 | |
| 		 * Perform binary search
 | |
| 		 */
 | |
| 		m = l + (u - l) / 2;
 | |
| 		if (strcmp(s, m->c_cmd) > 0) l = m + 1;
 | |
| 		else u = m;
 | |
| 	} while (l < u);
 | |
| 	if (!strcmp(s, u->c_cmd)) return u - commands;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /*ARGSUSED*/
 | |
| STATIC int
 | |
| do_lcomm(cnt) long cnt; {	/* Repeat last command */
 | |
| 
 | |
| 	if (!lastcomm) {
 | |
| 		error("No previous command");
 | |
| 		return;
 | |
| 	}
 | |
| 	do_comm(lastcomm, lastcount);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Execute a command, with optional count "count".
 | |
|  */
 | |
| 
 | |
| VOID
 | |
| do_comm(comm, count) register int comm; register long count; {
 | |
| 
 | |
| 	register struct commands *pcomm;
 | |
| 	register int temp;
 | |
| 	register int flags;
 | |
| 
 | |
| 	pcomm = &commands[comm];
 | |
| 	flags = pcomm->c_flags;
 | |
| 
 | |
| 	/*
 | |
| 	 * Check the command.
 | |
| 	 * If the last line of the file is displayed and the command goes
 | |
| 	 * forwards and does'nt have the ability to go to the next file, it
 | |
| 	 * is an error.
 | |
| 	 * If the first line of the file is displayed and the command goes
 | |
| 	 * backwards and does'nt have the ability to go to the previous file,
 | |
| 	 * it is an error.
 | |
| 	 * Also check wether we need the next or previous file. If so, get it.
 | |
| 	 */
 | |
| 	if ((status & EOFILE) && (flags & AHEAD)) {
 | |
| 		if (qflag || !(flags & TONEXTFILE)) return;
 | |
| 		if (nextfile(1)) quit();
 | |
| 	}
 | |
| 	if ((status & START) && (flags & BACK)) {
 | |
| 		if (qflag || !(flags & TOPREVFILE)) return;
 | |
| 		if (nextfile(-1)) quit();
 | |
| 	}
 | |
| 	/*
 | |
| 	 * Does the command stick around for LASTCOMM?
 | |
| 	 */
 | |
| 	if (flags & STICKY) {
 | |
| 		lastcomm = comm;
 | |
| 		lastcount = count;
 | |
| 	}
 | |
| 	if (!count) {
 | |
| 		if (flags & NEEDS_COUNT) count = 1;
 | |
| 	}
 | |
| 	else {
 | |
| 		/*
 | |
| 		 * Does the command adapt the screensize?
 | |
| 		 */
 | |
| 		if (flags & SCREENSIZE_ADAPT) {
 | |
| 			temp = maxpagesize;
 | |
| 			if ((unsigned) count < temp) {
 | |
| 				temp = count;
 | |
| 			}
 | |
| 			if (temp < MINPAGESIZE) {
 | |
| 				temp = MINPAGESIZE;
 | |
| 			}
 | |
| 			count = 0;
 | |
| 			pagesize = temp;
 | |
| 		}
 | |
| 		/*
 | |
| 		 * Does the command adapt the scrollsize?
 | |
| 		 */
 | |
| 		if (flags & SCROLLSIZE_ADAPT) {
 | |
| 			temp = maxpagesize - 1;
 | |
| 			if ((unsigned) count < temp) {
 | |
| 				temp = (int) count;
 | |
| 			}
 | |
| 			scrollsize = temp;
 | |
| 			count = 0;
 | |
| 		}
 | |
| 	}
 | |
| 	/*
 | |
| 	 * Now execute the command.
 | |
| 	 */
 | |
| 	(*(pcomm->c_func))(count);
 | |
| }
 | 
