459 lines
9.3 KiB
C
459 lines
9.3 KiB
C
/*
|
|
* print file with headings
|
|
* 2+head+2+page[56]+5
|
|
*/
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
/* Making putcp a macro sped things up by 14%. */
|
|
#define putcp(c) \
|
|
if (page >= fpage) \
|
|
putchar(c)
|
|
|
|
int ncol = 1;
|
|
char *header;
|
|
int col;
|
|
int icol;
|
|
FILE *file;
|
|
char *bufp;
|
|
#define BUFS 9000 /* at least 66 * 132 */
|
|
char buffer[BUFS]; /* for multi-column output */
|
|
char obuf[BUFSIZ];
|
|
#define FF 014
|
|
int line;
|
|
char *colp[72];
|
|
int nofile;
|
|
char isclosed[10];
|
|
FILE *ifile[10];
|
|
char **lastarg;
|
|
int peekc;
|
|
int fpage;
|
|
int page;
|
|
int colw;
|
|
int nspace;
|
|
int width = 72;
|
|
int length = 66;
|
|
int plength = 61;
|
|
int margin = 10;
|
|
int ntflg;
|
|
int fflg;
|
|
int mflg;
|
|
int tabc;
|
|
char *tty;
|
|
int mode;
|
|
|
|
static void fixtty(void);
|
|
static int numeric(char *str);
|
|
static void print(char *fp, char **argp);
|
|
static void done(void);
|
|
static void mopen(char **ap);
|
|
static void nexbuf(void);
|
|
static int tpgetc(int ai);
|
|
static void put(int ac);
|
|
static void putpage(void);
|
|
static int pgetc(int i);
|
|
|
|
void onintr(int sig)
|
|
{
|
|
if (tty)
|
|
chmod(tty, mode);
|
|
_exit(1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int nfdone;
|
|
|
|
setbuf(stdout, obuf);
|
|
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
|
|
signal(SIGINT, onintr);
|
|
lastarg = &argv[argc - 1];
|
|
fixtty();
|
|
for (nfdone = 0; argc > 1; argc--) {
|
|
argv++;
|
|
if (**argv == '-') {
|
|
switch (*++*argv) {
|
|
case 'h': /* define page header */
|
|
if (argc >= 2) {
|
|
header = *++argv;
|
|
argc--;
|
|
}
|
|
continue;
|
|
|
|
case 't': /* don't print page headers */
|
|
ntflg++;
|
|
continue;
|
|
|
|
case 'f': /* use form feeds */
|
|
fflg++;
|
|
plength = 60;
|
|
continue;
|
|
|
|
case 'l': /* length of page */
|
|
length = atoi(++*argv);
|
|
continue;
|
|
|
|
case 'w': /* width of page */
|
|
width = atoi(++*argv);
|
|
continue;
|
|
|
|
case 's': /* col separator */
|
|
if (*++*argv)
|
|
tabc = **argv;
|
|
else
|
|
tabc = '\t';
|
|
continue;
|
|
|
|
case 'm': /* all files at once */
|
|
mflg++;
|
|
continue;
|
|
|
|
default:
|
|
if (numeric(*argv)) { /* # of cols */
|
|
if ((ncol = atoi(*argv)) == 0) {
|
|
fprintf(stderr, "can't print 0 cols, using 1 instead.\n");
|
|
ncol = 1;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "pr: bad key %s\n", *argv);
|
|
exit(1);
|
|
}
|
|
continue;
|
|
}
|
|
} else if (**argv == '+') { /* start at page ++*argv */
|
|
fpage = atoi(++*argv);
|
|
} else {
|
|
print(*argv, argv);
|
|
nfdone++;
|
|
if (mflg)
|
|
break;
|
|
}
|
|
}
|
|
if (nfdone == 0)
|
|
print((char *)0, (char **)0);
|
|
done();
|
|
}
|
|
|
|
void done()
|
|
{
|
|
if (tty)
|
|
chmod(tty, mode);
|
|
exit(0);
|
|
}
|
|
|
|
/* numeric -- returns 1 if str is numeric, elsewise 0 */
|
|
int numeric(char *str)
|
|
{
|
|
for (; *str; str++) {
|
|
if (*str > '9' || *str < '0') {
|
|
return (0);
|
|
}
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
void fixtty()
|
|
{
|
|
struct stat sbuf;
|
|
|
|
tty = ttyname(1);
|
|
if (tty == 0)
|
|
return;
|
|
stat(tty, &sbuf);
|
|
mode = sbuf.st_mode & 0777;
|
|
chmod(tty, 0600);
|
|
}
|
|
|
|
/* print -- print file */
|
|
void print(char *fp, char **argp)
|
|
{
|
|
struct stat sbuf;
|
|
int sncol;
|
|
char *sheader;
|
|
char *cbuf;
|
|
char linebuf[150], *cp;
|
|
|
|
if (ntflg)
|
|
margin = 0;
|
|
else
|
|
margin = 10;
|
|
if (length <= margin)
|
|
length = 66;
|
|
if (width <= 0)
|
|
width = 72;
|
|
if (ncol > 72 || ncol > width) {
|
|
fprintf(stderr, "pr: No room for columns.\n");
|
|
done();
|
|
}
|
|
if (mflg) {
|
|
mopen(argp);
|
|
ncol = nofile;
|
|
}
|
|
colw = width / (ncol == 0 ? 1 : ncol);
|
|
sncol = ncol;
|
|
sheader = header;
|
|
plength = length - 5;
|
|
if (ntflg)
|
|
plength = length;
|
|
if (--ncol < 0)
|
|
ncol = 0;
|
|
if (mflg)
|
|
fp = 0;
|
|
if (fp) {
|
|
if ((file = fopen(fp, "r")) == NULL) {
|
|
if (tty == NULL)
|
|
perror(fp);
|
|
ncol = sncol;
|
|
header = sheader;
|
|
return;
|
|
}
|
|
stat(fp, &sbuf);
|
|
} else {
|
|
file = stdin;
|
|
time(&sbuf.st_mtime);
|
|
}
|
|
if (header == 0)
|
|
header = fp ? fp : "";
|
|
cbuf = ctime(&sbuf.st_mtime);
|
|
cbuf[16] = '\0';
|
|
cbuf[24] = '\0';
|
|
page = 1;
|
|
icol = 0;
|
|
colp[ncol] = bufp = buffer;
|
|
if (mflg == 0)
|
|
nexbuf();
|
|
while (mflg && nofile || (!mflg) && tpgetc(ncol) > 0) {
|
|
if (mflg == 0) {
|
|
colp[ncol]--;
|
|
if (colp[ncol] < buffer)
|
|
colp[ncol] = &buffer[BUFS];
|
|
}
|
|
line = 0;
|
|
if (ntflg == 0) {
|
|
if (fflg) {
|
|
/* Assume a ff takes two blank lines at the
|
|
top of the page. */
|
|
line = 2;
|
|
sprintf(linebuf, "%s %s %s Page %d\n\n\n", cbuf + 4, cbuf + 20, header, page);
|
|
} else
|
|
sprintf(linebuf, "\n\n%s %s %s Page %d\n\n\n", cbuf + 4, cbuf + 20, header, page);
|
|
for (cp = linebuf; *cp;)
|
|
put(*cp++);
|
|
}
|
|
putpage();
|
|
if (ntflg == 0) {
|
|
if (fflg)
|
|
put('\f');
|
|
else
|
|
while (line < length)
|
|
put('\n');
|
|
}
|
|
page++;
|
|
}
|
|
fclose(file);
|
|
ncol = sncol;
|
|
header = sheader;
|
|
}
|
|
|
|
void mopen(char **ap)
|
|
{
|
|
char **p, *p1;
|
|
|
|
p = ap;
|
|
while ((p1 = *p) && p++ <= lastarg) {
|
|
if ((ifile[nofile] = fopen(p1, "r")) == NULL) {
|
|
isclosed[nofile] = 1;
|
|
nofile--;
|
|
} else
|
|
isclosed[nofile] = 0;
|
|
if (++nofile >= 10) {
|
|
fprintf(stderr, "pr: Too many args\n");
|
|
done();
|
|
}
|
|
}
|
|
}
|
|
|
|
void putpage()
|
|
{
|
|
int lastcol, i, c;
|
|
int j;
|
|
|
|
if (ncol == 0) {
|
|
while (line < plength) {
|
|
while ((c = tpgetc(0)) && c != '\n' && c != FF)
|
|
putcp(c);
|
|
if (c == 0)
|
|
break;
|
|
putcp('\n');
|
|
line++;
|
|
if (c == FF)
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
colp[0] = colp[ncol];
|
|
if (mflg == 0)
|
|
for (i = 1; i <= ncol; i++) {
|
|
colp[i] = colp[i - 1];
|
|
for (j = margin; j < length; j++)
|
|
while ((c = tpgetc(i)) != '\n')
|
|
if (c == 0)
|
|
break;
|
|
}
|
|
while (line < plength) {
|
|
lastcol = colw;
|
|
for (i = 0; i < ncol; i++) {
|
|
while ((c = pgetc(i)) && c != '\n')
|
|
if (col < lastcol || tabc != 0)
|
|
put(c);
|
|
if (c == 0)
|
|
continue;
|
|
if (tabc)
|
|
put(tabc);
|
|
else
|
|
while (col < lastcol)
|
|
put(' ');
|
|
lastcol += colw;
|
|
}
|
|
while ((c = pgetc(ncol)) && c != '\n')
|
|
put(c);
|
|
put('\n');
|
|
}
|
|
}
|
|
|
|
void nexbuf()
|
|
{
|
|
int n;
|
|
char *rbufp;
|
|
|
|
rbufp = bufp;
|
|
n = &buffer[BUFS] - rbufp;
|
|
if (n > 512)
|
|
n = 512;
|
|
if ((n = fread(rbufp, 1, n, file)) <= 0) {
|
|
fclose(file);
|
|
*rbufp = 0376;
|
|
} else {
|
|
rbufp += n;
|
|
if (rbufp >= &buffer[BUFS])
|
|
rbufp = buffer;
|
|
*rbufp = 0375;
|
|
}
|
|
bufp = rbufp;
|
|
}
|
|
|
|
int tpgetc(int ai)
|
|
{
|
|
char **p;
|
|
int c, i;
|
|
|
|
i = ai;
|
|
if (mflg) {
|
|
if ((c = getc(ifile[i])) == EOF) {
|
|
if (isclosed[i] == 0) {
|
|
isclosed[i] = 1;
|
|
if (--nofile <= 0)
|
|
return (0);
|
|
}
|
|
return ('\n');
|
|
}
|
|
if (c == FF && ncol > 0)
|
|
c = '\n';
|
|
return (c);
|
|
}
|
|
loop:
|
|
c = **(p = &colp[i]) & 0377;
|
|
if (c == 0375) {
|
|
nexbuf();
|
|
c = **p & 0377;
|
|
}
|
|
if (c == 0376)
|
|
return (0);
|
|
(*p)++;
|
|
if (*p >= &buffer[BUFS])
|
|
*p = buffer;
|
|
if (c == 0)
|
|
goto loop;
|
|
return (c);
|
|
}
|
|
|
|
int pgetc(int i)
|
|
{
|
|
int c;
|
|
|
|
if (peekc) {
|
|
c = peekc;
|
|
peekc = 0;
|
|
} else
|
|
c = tpgetc(i);
|
|
if (tabc)
|
|
return (c);
|
|
switch (c) {
|
|
case '\t':
|
|
icol++;
|
|
if ((icol & 07) != 0)
|
|
peekc = '\t';
|
|
return (' ');
|
|
|
|
case '\n':
|
|
icol = 0;
|
|
break;
|
|
|
|
case 010:
|
|
case 033:
|
|
icol--;
|
|
break;
|
|
}
|
|
if (c >= ' ')
|
|
icol++;
|
|
return (c);
|
|
}
|
|
|
|
void put(int ac)
|
|
{
|
|
int ns, c;
|
|
|
|
c = ac;
|
|
if (tabc) {
|
|
putcp(c);
|
|
if (c == '\n')
|
|
line++;
|
|
return;
|
|
}
|
|
switch (c) {
|
|
case ' ':
|
|
nspace++;
|
|
col++;
|
|
return;
|
|
|
|
case '\n':
|
|
col = 0;
|
|
nspace = 0;
|
|
line++;
|
|
break;
|
|
|
|
case 010:
|
|
case 033:
|
|
if (--col < 0)
|
|
col = 0;
|
|
if (--nspace < 0)
|
|
nspace = 0;
|
|
}
|
|
while (nspace) {
|
|
if (nspace > 2 && col > (ns = ((col - nspace) | 07))) {
|
|
nspace = col - ns - 1;
|
|
putcp('\t');
|
|
} else {
|
|
nspace--;
|
|
putcp(' ');
|
|
}
|
|
}
|
|
if (c >= ' ')
|
|
col++;
|
|
putcp(c);
|
|
}
|