AUSAM/source/S/pg.c

Compare this file to the similar file:
Show the results in this format:

#
/*		PG, page through a file
 *
 *		13-jun-78
 *		Copyright Sape Mullender
 *		Informatics staff Vrije Universiteit Amsterdam
 *
 *	This program allows the user to page through a file.
 */ 

#define MAXBLOCKS 8192
#define BLOCKSIZ 2048
#define COREBLOCK 512
#define DOUBLE 2
#define TRUE 1
#define FALSE 0
#define out	1

/* Pg divides a file in blocks of size BLOCKSIZ characters. For each
 * block read pg remembers the line number of the first character of
 * that block. Thus pg can find a line of the file without much trouble.
 */ 

int fildes;
int printfile;	/* file descriptor of print file */ 
int printing;	/* non zero when printing is on */ 
int filpos;	/* current position on the file */ 
char *arg "standard input";	/* pointer to filename */ 
char instr[128];
char searchstr[128];

int screensize 22;	/* number of lines per screen */ 
int scrshft;	/* distance of curline from top of screen */ 
int anchored;	/* true for anchored searches */ 
long *lines;		/* lines[x] is line# of first char of blck x */ 
long curline -100;	/* line currently on display */
char block[2][BLOCKSIZ];	/* Two blocks can be kept in core */ 
int charcnt[2];	/* number of chars in each block */ 
int blockno[2];	/* block no of in core blocks */ 
long lastline;	/* number of last known line of the file */ 
int lastblock;	/* number of the highest block read in */ 
int lastknown;	/* true if last line of file is known */ 
int oldestblock;	/* number of oldest block in core */ 

main(argc, argv)
char **argv;
{
	register i, c;
	register char *ptr;
	long l, l1;
	int adr1[DOUBLE], adr2[DOUBLE];
	int reset();


	signal(1, 1);
	signal(2, 1);	/* signal(3,1);*/ 
	while(--argc && **++argv == '-')
	{
		flags(*argv);
	}
	if(argc > 1)
	{
		prints(2, "Usage: pg [-num] [file]\n");
		exit(1);
	}
	if(argc)
	{
		if((fildes = open(*argv, 0)) < 0)
		{
			prints(2, *argv);
			prints(2, ": cannot open\n");
			exit(1);
		}
		arg = *argv;
	}
	lines = sbrk(4);
	screensize = 22;
	lines[0] = 1;
	setexit();
	signal(2, &reset);
	while(getline())
	{
		ptr = instr;
		l = curline;
		if((c = *ptr++) >= '0' && c <= '9')
			ptr = readnum(instr, &l);
		else
			switch(c)
			{
			case '!':
				shell(ptr);
				continue;
			case '+':
			case '-':
				if(*ptr == '\n')
					if(c == '+')
						l =+ screensize;
					else
						l =- screensize;
				else
				{
					ptr = readnum(ptr, &l);
					if(c == '+')
					{
						l =+ curline;
					}
					else
					{
						l = curline - l;
					}
				}
				break;
			case '/':
				if(*ptr != '/')
					if(setsearch(ptr) == FALSE)
					{
						prints(2, "bad search string\n");
						continue;
					}
				if(search(&l) == FALSE)
				{
					prints(2, "can't find string\n");
					continue;
				}
				*ptr = '\n';
				break;
			case '\n':
				l =+ screensize;
				--ptr;
				break;
			case '$':
				l = 017777777777l;	/* somewhat large */
				break;
			case '.':
				break;
			case 'p':
				if((c = *ptr++) == ' ')
				{
					if(printfile)
						close(printfile);
					i = ptr;
					while(*ptr++ != '\n');
					*--ptr = 0;
					if((printfile = creat(i, 0644)) < 0)
					{
						prints(2, i);
						prints(2, ": cannot create\n");
						printfile = 0;
						continue;
					}
					printing++;
				}
				else
				{
					if(c == '+')
						if(printfile)
							printing++;
						else
						{
							prints(2, "no printfile\n");
							continue;
						}
					else if(c == '-')
						printing = 0;
					else
					{
						prints(2, "bad print cmd\n");
						continue;
					}
				}
			case 'r':
				if((i = atoi(ptr)) >= 0 && i < screensize)
					scrshft = i;
				continue;
			case 's':
				if((i = atoi(ptr)) > 0)
					screensize = i;
				continue;
			case 'q':
				if(*ptr == '\n')
					return 0;
			default:
				prints(2, "unknown command\n");
				continue;
			}
		if(*ptr != '\n')
		{
			prints(2, "bad format\n");
			continue;
		}
		getaddress(&l, adr1);
		curline = l;
		l =- scrshft;
		getaddress(&l, adr1);
		l1 = l;
		l =+ screensize;
		if(getaddress(&l, adr2) == FALSE)
		{
			/* line not on file */ 
			l1 = l - screensize;
			getaddress(&l1, adr1);
		}
		display(adr1, adr2);
		prints(2, "\t\t\t\t\tlines ");
		prints(2, locv(l1));
		prints(2, " to ");
		prints(2, locv(l));
		prints(2, ": ");
		prints(2, arg);
		prints(2, "\r");
	}
	prints(2, "\n");
	return 0;
}

getaddress(line, address)
int address[];
long *line;
{
	/* Find out the file address of line,
	 * Return 1 if successfull, 0 if not
	 * If line not on file, change line to closest line
	 * that is on the file and set address accordingly.
	 */ 

	register i, b;
	register char *j;
	long l;


	if(*line <= 0)
	{
		address[0] = address[1] = 0;
		*line = 1;
		/* get the appropriate block in core */ 
		getblock(0);
		return(FALSE);
	}
	if(*line > lastline)
	{
		if(lastknown)
		{
			/* The line is not on the file */ 
		not_found:
			*line = lastline;
			getaddress(line, address);
			return(FALSE);
		}
		while(newblock() && *line > lastline);
		if(*line > lastline)
		{
			/* The line is not on the file */ 
			goto not_found;
		}
	}
	/* The line is in the file, search to the right block */ 
	if(*line == 1)
	{
		/* line 1 is a special case,
		 * Prevent pg from reading block -1
		 */ 
		address[0] = address[1] = 0;
		getblock(0);
		return(TRUE);
	}
	for(i = 0; *line > lines[i+1]; i++);
	/* Now i contains the block number of the line-feed before
	 * the desired line, (the line itself might be in the next
	 * block) read the block in
	 */ 
	b = getblock(i);
	l = lines[i];
	j = block[b];
	do
	{
		while(*j++ != '\n');
		l++;
	}
	while(l < *line);
	address[0] = i;
	address[1] = j-block[b];
	return(TRUE);
}

newblock()
{
	long l;
	register int i, b;
	register char *p;

	/* Read a new block, update the lines table */ 


	l = lines[lastblock];
	/*
	 * We're going to read block "lastblock"
	 * If neccessairy seek to the right position first
	 */ 
	if(lastblock != filpos)
	{
		if(seek(fildes, lastblock*(BLOCKSIZ/512), 3) < 0)
		{
			/* seek failed */ 
			prints(2, "can't seek");
			reset();
		}
	}
	b = oldestblock++&1;
	charcnt[b] = 0;
	while((i = read(fildes, block[b]+charcnt[b], BLOCKSIZ-charcnt[b])) > 0 && (charcnt[b] =+ i) < BLOCKSIZ);
	if(charcnt[b])
	{
		/* at least something was read, it may not have
		 * been a whole block though
		 */ 
		p = block[b];
		for(i = 0; i < charcnt[b]; i++)
		{
			if(*p++ == '\n')
				l++;
		}
		blockno[b] = lastblock;
		if((lastblock%(COREBLOCK/4)) == 0)
		{
			/* ask for more memory */ 
			sbrk(COREBLOCK);
		}
		lastblock++;
		filpos++;
		lastline = lines[lastblock] = l;
		return(TRUE);
	}
	else
	{
		lastknown = TRUE;
		return(FALSE);
	}
}

getblock(num)
{
	/*
	 * get block nr num
	 * return the number of the block used
	 */ 
	register int i, b;


	if(num == blockno[0])
	{
		/* already in core */ 
		return(0);
	}
	if(num == blockno[1])
	{
		/* already in core */ 
		return(1);
	}
	if(filpos != num)
	{
		if(seek(fildes, num*(BLOCKSIZ/512), 3) < 0)
		{
			/* seek failed */ 
			prints(2, "bad seek\n");
			reset();
		}
	}
	b = oldestblock++&1;
	charcnt[b] = read(fildes, block[b], BLOCKSIZ);
	blockno[b] = num;
	filpos = num+1;
	return(b);
}

readnum(str, var)
char *str;
long *var;
{
	register char *p, c;
	register long *x;


	x = var;
	p = str;
	*x = 0;
	while((c = *p++) >= '0' && c <= '9')
	{
		*x =* 10;
		*x =+ c-'0';
	}
	return(p-1);
}

getline()
{
	register char *p;
	register c;


	prints(2, "* ");
	p = instr;
	c = read(2, p, sizeof instr - 1);
	p[c] = 0;
	return c;
}

display(adr1, adr2)
int *adr1, *adr2;
{
	register *a1, *a2, b;


	a1 = adr1;
	a2 = adr2;
	b = getblock(a1[0]);
	if(a1[0] == a2[0])
	{
		write2(&block[b][a1[1]], a2[1]-a1[1]);
	}
	else
	{
		write2(&block[b][a1[1]], BLOCKSIZ-a1[1]);
		do
		{
			b = getblock(blockno[b]+1);
			if(blockno[b] == a2[0])
			{
				write2(block[b], a2[1]);
			}
			else
			{
				write2(block[b], BLOCKSIZ);
			}
		}
		while(blockno[b] < a2[0]);
	}
}

flags(string)
{
}

search(line)
long *line;
{
	int addr[DOUBLE];
	int b, ii;
	char *ptr;
	register i;
	register char *s, *p;


	if(curline <= 0)
	{
		curline = 1;
	}
	*line = curline + 1;
	for(;;)
	{
		if(*line == curline)
		{
			/* not found */ 
			return(FALSE);
		}
		(*line)++;
		if(getaddress(line, addr) == FALSE)
		{
			/* eof, back to beginning */ 
			*line = 1;
			addr[0] = addr[1] = 0;
		}
		b = getblock(addr[0]);
		ptr = &block[b][addr[1]];
		ii = charcnt[b]-addr[1];
		do
		{
			s = searchstr;
			if((i = ii) == 0)
			{
				b = getblock(addr[0]++);
				i = ii = charcnt[b];
				ptr = block[b];
			}
			p = ptr;
			do
			{
				if(*s == 0)
					return(TRUE);
				if(i == 0)
				{
					/* get another block */ 
					b = getblock(addr[0]+1);
					p = block[b];
					i = charcnt[b];
				}
				i--;
			}
			while(*s++ == *p++);
			ii--;
		}
		while(anchored == FALSE && *ptr++ != '\n');
	}
}

shell(string)
char *string;
{
	register int pid;
	int status;
	int reset();


	signal(2, 1);
	if((pid = fork()) < 0)
	{
		prints(2, "Try again\n");
		return;
	}
	if(pid)
	{
		while(pid != wait(&status));
		signal(2, &reset);
		return;
	}
	execl("/bin/sh", "sh", "-c", string, 0);
	prints(2, "can't execute %s\n", string);
	exit(1);
}

setsearch(string)
char *string;
{
	register char c, *s, *ss;
	char *end;


	s = string;
	while(*s != '\n')
		s++;
	if(*--s != '/')
	{
		*searchstr = 0;
		return(FALSE);
	}
	if((end = s) <= string)
		return(FALSE);
	if(s[-1] == '$')
		s[-1] = '\n';
	if(*string == '^')
	{
		anchored = TRUE;
		string++;
	}
	else
		anchored = FALSE;
	ss = searchstr;
	for(s = string; s < end; *ss++ = *s++);
	*ss++ = 0;
	return(TRUE);
}

write2(buf, cnt)
{

	write(out, buf, cnt);
	if(printing)
		write(printfile, buf, cnt);
}