DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦c7ed0fe68⟧ TextFile

    Length: 8536 (0x2158)
    Types: TextFile
    Notes: UNIX file
    Names: »pr.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »cmd/pr.c« 

TextFile



/*
 * pr -- print files
 *
 * All references to page length exclude possible margin lines.
 */
#include	<sys/types.h>
#include	<stdio.h>
#include	<errno.h>


#define	LSIZE	256			/* line size */
#define	LENGTH	(66-MARGIN)		/* default page length */
#define	WIDTH	80			/* default page width */
#define	TMAR	5			/* five lines of top margin */
#define	BMAR	5			/* five lines of bottom margin */
#define	HEADER	2			/* line # where header appears */

#define	MARGIN	(TMAR+BMAR)


/*
 * info on input file streams
 * Unless -m is in effect, only f[0] is used.
 */
struct f {
	int	f_ff;		/* '\f' received */
	FILE	*f_stream;	/* input stream */
};


int	ncol	= 1,			/* # of columns */
	nskip,				/* # pages to skip of each file */
	length	= LENGTH,		/* page length */
	width	= WIDTH,		/* page width */
	lno,				/* current input line # */
	fwidth;				/* field width */
char	schar,				/* separator char */
	tflag,				/* -t: no header or margins */
	mflag,				/* -m: multiple file output */
	nflag,				/* -n: line number output */
	*date,				/* date string */
	*header,			/* -h: header text */
	**lines;			/* buffer addr for multicolumn */

struct f	f[20];			/* input file info */

char	**init( ),
	*malloc( ),
	*ctime( );
int	page1( ), page2( ),
	putl( ), nop( );
FILE	*openf( );

int	(*page)( )	= page1;


/*
 * paginate files to standard output
 * If no files are given, use standard input.  The file name "-" also
 * means standard input.
 */
main( argc, argv)
register char	**argv;
{

	argv = init( argc, argv);

	if (*argv)
		while (*argv) {
			f[0].f_stream = openf( *argv);
			print( *argv++);
			fclose( f[0].f_stream);
		}
	else
		print( "");

	return (0);
}


/*
 * initialize & get options
 * Flags are recognized up to the first file name.  If multi-column (-N),
 * allocate line array.  If printing multiple files (-m), open all files.
 * There are two paging algorithms: one file per column (page1), and
 * many columns per file (page2).  The latter requires page buffering.
 * init( ) makes this selection.
 */
char	**
init( ac, av)
register char	**av;
{
	register	mar	= MARGIN;
	static char	obuf[BUFSIZ];
	time_t		tvec;

	setbuf( stdout, obuf);

	while (++av, --ac) {
		if (av[0][0] == '+')
			if ((nskip=atoi( &av[0][1])) <= 0)
				fatal( "bad skip");
			else
				continue;
		if (av[0][0] != '-')
			break;
		switch (av[0][1]) {
		case '\0':
			break;
		case 'l':
			length = atoi( &av[0][2]) - mar;
			continue;
		case 'w':
			width = atoi( &av[0][2]);
			continue;
		case 'h':
			if (av[0][2])
				header = &av[0][2];
			else {
				if (--ac <= 0)
					fatal( "missing header arg");
				header = (++av)[0];
			}
			continue;
		case 's':
			if ((schar=av[0][2]) == '\0')
				schar = '\t';
			continue;
		case 'm':
			++mflag;
			continue;
		case 't':
			++tflag;
			length += mar;
			mar = 0;
			continue;
		case 'n':
			++nflag;
			continue;
		default:
			if ('0'<=av[0][1] && av[0][1]<='9')
				ncol = atoi( &av[0][1]);
			else
				fatal( "no such switch %s", av[0]);
			continue;
		}
		break;
	}

	f[0].f_stream = stdin;
	if (mflag && av[0]) {
		ncol = 0;
		do {
			f[ncol++].f_stream = openf( av++[0]);
		} while (av[0]);
	}

	/*
	 * check that all options jive
	 */
	if (length <= 0)
		if (length == -mar) {	/* gunja artifice */
			length = 1;
			++tflag;
		}
		else
			fatal( "length too small");
	fwidth = width / ncol;
	if (schar)
		--fwidth;
	if (fwidth <= 0 || (nflag && fwidth < 10))
		fatal( "width too small");
	if (fwidth >= LSIZE-1)
		fatal( "too wide");
	if (ncol>1 && mflag==0) {
		if ((lines=malloc( (ncol-1)*length*sizeof( char *))) == NULL)
			fatal( "insufficient core");
		page = page2;
	}

	time( &tvec);
	date = ctime( &tvec);

	return (av);
}


/*
 * open input file
 * Failure to open is fatal.  openf( "-") returns stdin.
 */
FILE	*
openf( file)
register char	*file;
{
	register FILE	*stream;
	extern		errno;

	lno = 0;
	if (file[0]=='-' && file[1]=='\0')
		return (stdin);
	if ((stream=fopen( file, "r")) == NULL)
		if (errno == EMFILE)
			fatal( "too many files for -m");
		else
			fatal( "can't open %s", file);
	return (stream);
}


/*
 * print from open input streams
 * Control output of pages, perhaps provide header/footer margins and title.
 * The paging routine is expected to give an eof warning on the last page.
 */
print( file)
char	*file;
{
	register	i,
			pg,
			eof;

	for (pg=1; pg<=nskip; ++pg)
		if ((*page)( nop))
			return;

	do {
		if (tflag == 0)
			for (i=0; i<TMAR; ++i) {
				if (i != HEADER) {
					putchar( '\n');
					continue;
				}
				printf( "%.12s%.5s  %s  Page %d, line %D\n",
					date+4, date+19,
					header? header: file,
					pg,
					(long)(pg-1)*(mflag?1:ncol)*length+1);
			}
		eof = (*page)( putl);
		if (tflag == 0)
			for (i=0; i<BMAR; ++i)
				putchar( '\n');
	} while (++pg, eof==0);
}


/*
 * page one stream per column
 * This handles all cases of one column per page.
 * Formfeed advances output of that stream to the next page.
 * Eof is only indicated when all streams give this condition.
 */
page1( putline)
int	(*putline)( );
{
	register	i,
			j;
	char	lbuf[LSIZE];

	for (i=0; i<length; ++i) {
		for (j=0; j<ncol; ++j) {
			getline( &f[j], lbuf);
			(*putline)( lbuf, j<ncol-1? schar: 0);
		}
		(*putline)( (char *)0);
	}

	i = 0;
	for (j=0; j<ncol; ++j) {
		f[j].f_ff = 0;
		if (feof( f[j].f_stream))
			++i;
		else if (ungetc( getc( f[j].f_stream), f[j].f_stream) == EOF)
			++i;
	}
	return (i == j);
}


/*
 * page one stream across multiple columns
 * The first `ncol'-1 columns of text are buffered; the last is simply
 * read as needed.  Formfeeds advance output to the next column.
 */
page2( putline)
int	(*putline)( );
{
	register	i,
			j,
			k;
	char	lbuf[LSIZE];

	for (i=0; i<(ncol-1)*length; ++i) {
		if ((i%length) == 0)
			f[0].f_ff = 0;
		if (k = getline( &f[0], lbuf)) {
			if ((lines[i]=malloc( k+1)) == NULL)
				fatal( "out of core");
			strcpy( lines[i], lbuf);
		}
		else
			lines[i] = NULL;
	}
	f[0].f_ff = 0;

	for (i=0; i<length; ++i) {
		for (j=0; j<ncol-1; ++j) {
			k = j*length + i;
			if (lines[k]) {
				(*putline)( lines[k], schar);
				free( lines[k]);
			}
			else
				(*putline)( "", schar);
		}
		getline( &f[0], lbuf);
		(*putline)( lbuf, 0);
		(*putline)( (char *)0);
	}

	if (feof( f[0].f_stream))
		return (1);
	if (ungetc( getc( f[0].f_stream), f[0].f_stream) == EOF)
		return (1);
	return (0);
}


/*
 * read a line
 * Simple char processing is done, including tab expansion.  getline( )
 * will return an empty line if f_ff is set.  Lines are truncated to
 * fit the field width.
 */
getline( fp, lbuf)
register struct f	*fp;
char	*lbuf;
{
	register	col;
	register char	*p;
	char		c;

	col = 0;
	p = lbuf;
	if (feof( fp->f_stream)==0 && fp->f_ff==0) {
		if (nflag) {
			sprintf(p, "%4d: ", ++lno);
			p += 6;
		}
		for (; ; ) {
			switch (c = getc(fp->f_stream)) {
			case '\f':
				++fp->f_ff;
			case EOF:
				if (nflag && (p == &lbuf[6]))
					p = lbuf;
				break;
			case '\n':
				break;
			case '\r':
				continue;
			case '\t':
				do {
					if (p<&lbuf[LSIZE-1] && col<fwidth)
						*p++ = ' ';
				} while (++col & 7);
				continue;
			case '\b':
				if (col) {
					--col;
					if (p<&lbuf[LSIZE-1] && col<fwidth)
						*p++ = c;
				}
				continue;
			default:
				if (p<&lbuf[LSIZE-1] && col<fwidth)
					*p++ = c;
				++col;
				continue;
			}
			break;
		}

	}
	*p = '\0';
	return (p - lbuf);
}


/*
 * write a line, incrementally
 * A line of output can be built by successive calls to putl( ).  A line
 * address of 0 puts the newline.  Simple char processing is done,
 * including tab optimization.  Each line segment is padded to the
 * field width, unless a there is a field separator char.
 */
putl( lbuf, schr)
char	*lbuf;
{
	register char	*p;
	register	c,
			nextxcol;
	static		col,
			xcol;

	if ((p=lbuf) == NULL) {
		col = 0;
		xcol = 0;
		putchar( '\n');
		return;
	}
	nextxcol = xcol + fwidth;

	for (; ; ) {
		if ((c= *p++) == '\0') {
			if ((c=schr) == '\0')
				break;
			schr = 0;
			--p;
			nextxcol = xcol + 1;
		}
		if (c == ' ') {
			++xcol;
			continue;
		}
		if (c == '\b') {
			--xcol;
			continue;
		}
		while ((col|7)+1 <= xcol) {
			col = (col|7) + 1;
			putchar( '\t');
		}
		while (col < xcol) {
			++col;
			putchar( ' ');
		}
		while (col > xcol) {
			--col;
			putchar( '\b');
		}
		putchar( c);
		xcol = ++col;
	}

	xcol = nextxcol;
}


/*
 * throw away output line
 * Used when skipping the first pages of input.
 */
nop( )
{

}


/*
 * print error message, exit
 */
fatal( arg0)
{

	fflush( stdout);
	fprintf( stderr, "pr: %r\n", &arg0);
	exit (1);
}