Files
Arquivotheca.Solaris-2.5/cmd/pr/pr.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

1448 lines
28 KiB
C
Executable File

#ident "@(#)pr.c 1.19 95/05/10 SMI" /* SVr4.0 1.19 */
/*
* PR command (print files in pages and columns, with headings)
* 2+head+2+page[56]+5
*/
/*
* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
* All Rights Reserved
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
* The copyright notice above does not evidence any
* actual or intended publication of such source code.
*/
/*
* PROPRIETARY NOTICE (Combined)
*
* This source code is unpublished proprietary information
* constituting, or derived under license from AT&T's UNIX(r) System V.
* In addition, portions of such source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*/
/*
* Copyright Notice
*
* Notice of copyright on this source code product does not indicate
* publication.
*
* (c) 1986, 1987, 1988, 1989 Sun Microsystems, Inc
* (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T.
* All rights reserved.
*/
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#ifdef EUC
#include <euc.h>
#include <getwidth.h>
#endif EUC
#define ESC '\033'
#define LENGTH 66
#define LINEW 72
#define NUMW 5
#define MARGIN 10
#define DEFTAB 8
#define NFILES 10
#define STDINNAME() nulls
#define PROMPT() (void) putc('\7', stderr) /* BEL */
#define NOFILE nulls
#define ETABS (Inpos % Etabn)
#define NSEPC '\t'
#define HEAD gettext("%s %s Page %d\n\n\n"), date, head, Page
#define cerror(S) (void) fprintf(stderr, "pr: %s", gettext(S))
#define done() if (Ttyout) (void) chmod(Ttyout, Mode)
#define ALL_NUMS(s) (strspn(s, "0123456789") == strlen(s))
#define REMOVE_ARG(argc, argp) \
{ \
char **p = argp; \
while (*p != NULL) \
{ \
*p = *(p + 1); \
p++; \
} \
argc--; \
}
#define SQUEEZE_ARG(argp, ind) \
{ \
int i; \
for (i = ind; argp[i]; i++) \
argp[i] = argp[i+1]; \
}
/*
* ---date time format---
* b -- abbreviated month name
* e -- day of month
* H -- Hour (24 hour version)
* M -- Minute
* Y -- Year in the form ccyy
*/
#define FORMAT "%b %e %H:%M %Y"
#ifdef EUC
#define OFF 0
#define ON 1
#define ROUNDUP 0.9
#endif EUC
typedef char CHAR;
typedef int ANY;
typedef unsigned int UNS;
typedef struct { FILE *f_f; char *f_name; int f_nextc; } FILS;
typedef struct {int fold; int skip; int eof; } foldinf;
typedef struct { CHAR *c_ptr, *c_ptr0; long c_lno; int c_skip; } *COLP;
typedef struct err { struct err *e_nextp; char *e_mess; } ERR;
/*
* Global data.
*/
static FILS *Files;
static mode_t Mode;
static int Multi = 0;
static int Nfiles = 0;
static int Error = 0;
static char nulls[] = "";
static char *Ttyout;
static char obuf[BUFSIZ];
static char time_buf[50]; /* array to hold the time and date */
static long Lnumb = 0;
static FILE *Ttyin = stdin;
static int Dblspace = 1;
static int Fpage = 1;
static int Formfeed = 0;
static int Length = LENGTH;
static int Linew = 0;
static int Offset = 0;
static int Ncols = 0;
static int Pause = 0;
static int Sepc = 0;
static int Colw;
static int Plength;
static int Margin = MARGIN;
static int Numw;
static int Nsepc = NSEPC;
static int Report = 1;
static int Etabn = 0;
static int Etabc = '\t';
static int Itabn = 0;
static int Itabc = '\t';
static int fold = 0;
static int foldcol = 0;
static int alleof = 0;
static char *Head = NULL;
static CHAR *Buffer = NULL, *Bufend, *Bufptr;
static UNS Buflen;
static COLP Colpts;
static foldinf *Fcol;
static int Page;
static int C = '\0';
static int Nspace;
static int Inpos;
static int Outpos;
static int Lcolpos;
static int Pcolpos;
static int Line;
static ERR *Err = NULL;
static ERR *Lasterr = (ERR *)&Err;
#ifdef EUC
static double eucbuf = 1, eucbufw = 0;
static eucwidth_t wp;
static int setswitch = 0;
static int eucwcount = 0;
static int scrwcount = 0;
static int eucstart = OFF;
#endif EUC
/*
* Function prototypes.
*/
static void onintr();
static ANY *getspace();
static int findopt(int, char **);
static void fixtty();
static char *GETDATE();
static char *ffiler(char *);
static int print(char *);
static void putpage();
static void foldpage();
static void nexbuf();
static void foldbuf();
static void balance(int);
static int readbuf(char **, int, COLP);
static int get(int);
static int put(int);
static void putspace();
static void unget(int);
static FILE *mustopen(char *, FILS *);
static void die(char *);
static void errprint();
static void usage(int);
main(int argc, char **argv)
{
FILS fstr[NFILES];
int nfdone = 0;
/* Get locale variables for environment */
(void) setlocale(LC_ALL, "");
#ifdef EUC
getwidth(&wp);
wp._eucw2++;
wp._eucw3++;
#endif
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
#endif
(void) textdomain(TEXT_DOMAIN);
Files = fstr;
for (argc = findopt(argc, argv); argc > 0; --argc, ++argv) {
if (Multi == 'm') {
if (Nfiles >= NFILES - 1) die("too many files");
if (mustopen(*argv, &Files[Nfiles++]) == NULL)
++nfdone; /* suppress printing */
} else {
if (print(*argv))
(void) fclose(Files->f_f);
++nfdone;
}
}
if (!nfdone) /* no files named, use stdin */
(void) print(NOFILE); /* on GCOS, use current file, if any */
if (Report) {
errprint(); /* print accumulated error reports */
exit(Error);
}
return (Error);
}
/*
* findopt() returns argc modified to be the number of explicitly supplied
* filenames, including '-', the explicit request to use stdin.
* argc == 0 implies that no filenames were supplied and stdin should be used.
* Options are striped from argv and only file names are returned.
*/
static int
findopt(int argc, char **argv)
{
int eargc = 0;
int c;
int mflg = 0;
int aflg = 0;
int optnum;
int argv_ind;
int end_opt;
int i;
fixtty();
/* Handle page number option */
for (optnum = 1, end_opt = 0; optnum < argc && !end_opt; optnum++) {
switch (*argv[optnum]) {
case '+':
/* check for all digits */
if (strlen(&argv[optnum][1]) !=
strspn(&argv[optnum][1], "0123456789")) {
(void) fprintf(stderr, gettext(
"pr: Badly formed number\n"));
exit(1);
}
if ((Fpage = (int) strtol(&argv[optnum][1],
(char **)NULL, 10)) < 0) {
(void) fprintf(stderr, gettext(
"pr: Badly formed number\n"));
exit(1);
}
REMOVE_ARG(argc, &argv[optnum]);
optnum--;
break;
case '-':
/* Check for end of options */
if (argv[optnum][1] == '-') {
end_opt++;
break;
}
break;
default:
break;
}
}
/*
* Handle options with optional arguments.
* If optional arguments are present they may not be separated
* from the option letter.
*/
for (optnum = 1; optnum < argc; optnum++) {
if (argv[optnum][0] == '-' && argv[optnum][1] == '-')
/* End of options */
break;
if (argv[optnum][0] == '-' && argv[optnum][1] == '\0')
/* stdin file name */
continue;
if (argv[optnum][0] != '-')
/* not option */
continue;
for (argv_ind = 1; argv[optnum][argv_ind] != '\0'; argv_ind++) {
switch (argv[optnum][argv_ind]) {
case 'e':
SQUEEZE_ARG(argv[optnum], argv_ind);
if ((c = argv[optnum][argv_ind]) != '\0' &&
!isdigit(c)) {
Etabc = c;
SQUEEZE_ARG(argv[optnum], argv_ind);
}
if (isdigit(argv[optnum][argv_ind])) {
Etabn = (int) strtol(&argv[optnum]
[argv_ind], (char **)NULL, 10);
while (isdigit(argv[optnum][argv_ind]))
SQUEEZE_ARG(argv[optnum], argv_ind);
}
if (Etabn <= 0)
Etabn = DEFTAB;
argv_ind--;
break;
case 'i':
SQUEEZE_ARG(argv[optnum], argv_ind);
if ((c = argv[optnum][argv_ind]) != '\0' &&
!isdigit(c)) {
Itabc = c;
SQUEEZE_ARG(argv[optnum], argv_ind);
}
if (isdigit(argv[optnum][argv_ind])) {
Itabn = (int) strtol(&argv[optnum]
[argv_ind], (char **)NULL, 10);
while (isdigit(argv[optnum][argv_ind]))
SQUEEZE_ARG(argv[optnum], argv_ind);
}
if (Itabn <= 0)
Itabn = DEFTAB;
argv_ind--;
break;
case 'n':
++Lnumb;
SQUEEZE_ARG(argv[optnum], argv_ind);
if ((c = argv[optnum][argv_ind]) != '\0' &&
!isdigit(c)) {
Nsepc = c;
SQUEEZE_ARG(argv[optnum], argv_ind);
}
if (isdigit(argv[optnum][argv_ind])) {
Numw = (int) strtol(&argv[optnum]
[argv_ind], (char **)NULL, 10);
while (isdigit(argv[optnum][argv_ind]))
SQUEEZE_ARG(argv[optnum], argv_ind);
}
argv_ind--;
if (!Numw)
Numw = NUMW;
break;
case 's':
SQUEEZE_ARG(argv[optnum], argv_ind);
if ((Sepc = argv[optnum][argv_ind]) == '\0')
Sepc = '\t';
else {
Sepc = argv[optnum][argv_ind];
SQUEEZE_ARG(argv[optnum], argv_ind);
}
argv_ind--;
break;
default:
break;
}
}
if (argv[optnum][0] == '-' && argv[optnum][1] == '\0') {
REMOVE_ARG(argc, &argv[optnum]);
optnum--;
}
}
/* Now get the other options */
while ((c = getopt(argc, argv, "0123456789adfFh:l:mo:prtw:"))
!= EOF) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
Ncols *= 10;
Ncols += c - '0';
break;
case 'a':
aflg++;
if (!Multi)
Multi = c;
break;
case 'd':
Dblspace = 2;
break;
case 'f':
++Formfeed;
++Pause;
break;
case 'h':
Head = optarg;
break;
case 'l':
if (strlen(optarg) != strspn(optarg, "0123456789"))
usage(1);
Length = (int) strtol(optarg, (char **)NULL, 10);
break;
case 'm':
mflg++;
Multi = c;
break;
case 'o':
if (strlen(optarg) != strspn(optarg, "0123456789"))
usage(1);
Offset = (int) strtol(optarg, (char **)NULL, 10);
break;
case 'p':
++Pause;
break;
case 'r':
Report = 0;
break;
case 't':
Margin = 0;
break;
case 'w':
if (strlen(optarg) != strspn(optarg, "0123456789"))
usage(1);
Linew = (int) strtol(optarg, (char **)NULL, 10);
break;
case 'F':
#ifdef XPG4
++Formfeed;
#else
fold++;
#endif
break;
case '?':
usage(2);
break;
default :
usage(2);
}
}
/* Count the file names and strip options */
for (i = 1; i < argc; i++) {
/* Check for explicit stdin */
if ((argv[i][0] == '-') && (argv[i][1] == '\0')) {
argv[eargc++][0] = '\0';
REMOVE_ARG(argc, &argv[i]);
if (i < optind)
optind--;
}
}
for (i = eargc; optind < argc; i++, optind++) {
argv[i] = argv[optind];
eargc++;
}
/* Check options */
if (Ncols == 0)
Ncols = 1;
if (mflg && (Ncols > 1)) {
(void) fprintf(stderr,
gettext("pr: only one of either -m or -column allowed\n"));
usage(1);
}
if (Ncols == 1 && fold)
Multi = 'm';
if (Length <= 0)
Length = LENGTH;
if (Length <= Margin)
Margin = 0;
Plength = Length - Margin/2;
if (Multi == 'm')
Ncols = eargc;
switch (Ncols) {
case 0:
Ncols = 1;
break;
case 1:
break;
default:
if (Etabn == 0) /* respect explicit tab specification */
Etabn = DEFTAB;
if (Itabn == 0)
Itabn = DEFTAB;
}
if ((Fcol = (foldinf *) malloc(sizeof (foldinf) * Ncols)) == NULL) {
(void) fprintf(stderr, gettext("pr: malloc failed\n"));
exit(1);
}
for (i = 0; i < Ncols; i++)
Fcol[i].fold = Fcol[i].skip = 0;
if (Linew == 0)
Linew = Ncols != 1 && Sepc == 0 ? LINEW : 512;
if (Lnumb) {
int numw;
if (Nsepc == '\t') {
if (Itabn == 0)
numw = Numw + DEFTAB - (Numw % DEFTAB);
else
numw = Numw + Itabn - (Numw % Itabn);
} else {
numw = Numw + ((isprint(Nsepc)) ? 1 : 0);
}
Linew -= (Multi == 'm') ? numw : numw * Ncols;
}
if ((Colw = (Linew - Ncols + 1)/Ncols) < 1)
die("width too small");
if (Ncols != 1 && Multi == 0) {
Buflen = ((UNS) (Plength / Dblspace + 1)) *
(Linew + 1) * sizeof (CHAR);
#ifdef EUC
if (wp._multibyte) {
if (wp._scrw1 > 0)
if ((eucbufw = (double) wp._eucw1 /
(double) wp._scrw1) > 0)
if (eucbufw > 1)
eucbuf = eucbufw;
else
eucbuf = 1;
if (wp._scrw2 > 0)
if ((eucbufw = (double) wp._eucw2 /
(double) wp._scrw2) > 0)
if (eucbufw > eucbuf)
eucbuf = eucbufw;
if (wp._scrw3 > 0)
if ((eucbufw = (double) wp._eucw3 /
(double) wp._scrw3) > 0)
if (eucbufw > eucbuf)
eucbuf = eucbufw;
Buflen = (UNS) (Buflen * eucbuf + ROUNDUP);
}
#endif
Buffer = (CHAR *) getspace(Buflen);
Bufptr = Bufend = &Buffer[Buflen];
Colpts = (COLP) getspace((UNS) ((Ncols + 1) *
sizeof (*Colpts)));
Colpts[0].c_lno = 0;
}
/* is stdin not a tty? */
if (Ttyout && (Pause || Formfeed) && !ttyname(fileno(stdin)))
Ttyin = fopen("/dev/tty", "r");
return (eargc);
}
static int
print(char *name)
{
static int notfirst = 0;
char *date = NULL;
char *head = NULL;
int c;
if (Multi != 'm' && mustopen(name, &Files[0]) == NULL)
return (0);
if (Multi == 'm' && Nfiles == 0 && mustopen(name, &Files[0]) == NULL)
die("cannot open stdin");
if (Buffer)
(void) ungetc(Files->f_nextc, Files->f_f);
if (Lnumb)
Lnumb = 1;
for (Page = 0; ; putpage()) {
if (C == EOF && !(fold && Buffer))
break;
if (Buffer)
nexbuf();
Inpos = 0;
if (get(0) == EOF)
break;
(void) fflush(stdout);
if (++Page >= Fpage) {
/* Pause if -p and not first page */
if (Ttyout && Pause && !notfirst++) {
PROMPT(); /* prompt with bell and pause */
while ((c = getc(Ttyin)) != EOF && c != '\n')
;
}
if (Margin == 0)
continue;
if (date == NULL)
date = GETDATE();
if (head == NULL)
head = Head != NULL ? Head :
Nfiles < 2 ? Files->f_name : nulls;
(void) printf("\n\n");
Nspace = Offset;
putspace();
(void) printf(HEAD);
}
}
C = '\0';
return (1);
}
static void
putpage()
{
register int colno;
if (fold) {
foldpage();
return;
}
for (Line = Margin / 2; ; (void) get(0)) {
for (Nspace = Offset, colno = 0, Outpos = 0; C != '\f'; ) {
if (Lnumb && (C != EOF) &&
(((colno == 0) && (Multi == 'm')) ||
(Multi != 'm'))) {
if (Page >= Fpage) {
putspace();
(void) printf("%*ld%c", Numw, Buffer ?
Colpts[colno].c_lno++ :
Lnumb, Nsepc);
/* Move Outpos for number field */
Outpos += Numw;
if (Nsepc == '\t')
Outpos +=
DEFTAB - (Outpos % DEFTAB);
else
Outpos++;
}
++Lnumb;
}
for (Lcolpos = 0, Pcolpos = 0;
C != '\n' && C != '\f' && C != EOF;
(void) get(colno))
(void) put(C);
if ((C == EOF) || (++colno == Ncols) ||
((C == '\n') && (get(colno) == EOF)))
break;
if (Sepc)
(void) put(Sepc);
else if ((Nspace += Colw - Lcolpos + 1) < 1)
Nspace = 1;
}
if (C == EOF) {
if (Margin != 0)
break;
if (colno != 0)
(void) put('\n');
return;
}
if (C == '\f')
break;
(void) put('\n');
if (Dblspace == 2 && Line < Plength)
(void) put('\n');
if (Line >= Plength)
break;
}
if (Formfeed)
(void) put('\f');
else
while (Line < Length)
(void) put('\n');
}
static void
foldpage()
{
register int colno;
int keep;
int i;
static int sl;
for (Line = Margin / 2; ; (void) get(0)) {
for (Nspace = Offset, colno = 0, Outpos = 0; C != '\f'; ) {
if (Lnumb && Multi == 'm' && foldcol) {
if (!Fcol[colno].skip) {
unget(colno);
putspace();
if (!colno) {
for (i = 0; i <= Numw; i++)
(void) printf(" ");
(void) printf("%c", Nsepc);
}
for (i = 0; i <= Colw; i++)
(void) printf(" ");
(void) put(Sepc);
if (++colno == Ncols)
break;
(void) get(colno);
continue;
} else if (!colno)
Lnumb = sl;
}
if (Lnumb && (C != EOF) &&
((colno == 0 && Multi == 'm') || (Multi != 'm'))) {
if (Page >= Fpage) {
putspace();
if ((foldcol &&
Fcol[colno].skip && Multi != 'a') ||
(Fcol[0].fold && Multi == 'a') ||
(Buffer && Colpts[colno].c_skip)) {
for (i = 0; i < Numw; i++)
(void) printf(" ");
(void) printf("%c", Nsepc);
if (Buffer) {
Colpts[colno].c_lno++;
Colpts[colno].c_skip =
0;
}
}
else
(void) printf("%*ld%c", Numw, Buffer ?
Colpts[colno].c_lno++ :
Lnumb, Nsepc);
}
sl = Lnumb++;
}
for (Lcolpos = 0, Pcolpos = 0;
C != '\n' && C != '\f' && C != EOF;
(void) get(colno)) {
if (put(C)) {
unget(colno);
Fcol[(Multi == 'a') ? 0 : colno].fold
= 1;
break;
} else if (Multi == 'a') {
Fcol[0].fold = 0;
}
}
if (Buffer) {
alleof = 1;
for (i = 0; i < Ncols; i++)
if (!Fcol[i].eof)
alleof = 0;
if (alleof || ++colno == Ncols)
break;
} else if (C == EOF || ++colno == Ncols)
break;
keep = C;
(void) get(colno);
if (keep == '\n' && C == EOF)
break;
if (Sepc)
(void) put(Sepc);
else if ((Nspace += Colw - Lcolpos + 1) < 1)
Nspace = 1;
}
foldcol = 0;
if (Lnumb && Multi != 'a') {
for (i = 0; i < Ncols; i++) {
Fcol[i].skip = Fcol[i].fold;
foldcol += Fcol[i].fold;
Fcol[i].fold = 0;
}
}
if (C == EOF) {
if (Margin != 0)
break;
if (colno != 0)
(void) put('\n');
return;
}
if (C == '\f')
break;
(void) put('\n');
(void) fflush(stdout);
if (Dblspace == 2 && Line < Plength)
(void) put('\n');
if (Line >= Plength)
break;
}
if (Formfeed)
(void) put('\f');
else while (Line < Length)
(void) put('\n');
}
static void
nexbuf()
{
register CHAR *s = Buffer;
register COLP p = Colpts;
int j;
int c;
int bline = 0;
#ifdef EUC
int bufcolw;
if (wp._multibyte)
bufcolw = (int)(Colw * eucbuf + ROUNDUP);
else
bufcolw = Colw;
#endif EUC
if (fold) {
foldbuf();
return;
}
for (; ; ) {
p->c_ptr0 = p->c_ptr = s;
if (p == &Colpts[Ncols])
return;
(p++)->c_lno = Lnumb + bline;
for (j = (Length - Margin)/Dblspace; --j >= 0; ++bline) {
for (Inpos = 0; ; ) {
if ((c = getc(Files->f_f)) == EOF) {
for (*s = EOF; p <= &Colpts[Ncols]; ++p)
p->c_ptr0 = p->c_ptr = s;
balance(bline);
return;
}
#ifdef EUC
if (ISPRINT(c, wp))
++Inpos;
if (Inpos <= bufcolw || c == '\n') {
#else
if (isprint(c))
++Inpos;
if (Inpos <= Colw || c == '\n') {
#endif EUC
*s = c;
if (++s >= Bufend)
die("page-buffer overflow");
}
if (c == '\n')
break;
switch (c) {
case '\b':
if (Inpos == 0)
--s;
/*FALLTHROUGH*/
case ESC:
if (Inpos > 0)
--Inpos;
}
}
}
}
}
static void
foldbuf()
{
int num;
int i;
int colno = 0;
int size = Buflen;
char *s;
char *d;
register COLP p = Colpts;
for (i = 0; i < Ncols; i++)
Fcol[i].eof = 0;
d = Buffer;
if (Bufptr != Bufend) {
s = Bufptr;
while (s < Bufend)
*d++ = *s++;
size -= (Bufend - Bufptr);
}
Bufptr = Buffer;
p->c_ptr0 = p->c_ptr = Buffer;
if (p->c_lno == 0) {
p->c_lno = Lnumb;
p->c_skip = 0;
} else {
p->c_lno = Colpts[Ncols-1].c_lno;
p->c_skip = Colpts[Ncols].c_skip;
if (p->c_skip)
p->c_lno--;
}
if ((num = fread(d, 1, size, Files->f_f)) != size) {
for (*(d+num) = EOF; (++p) <= &Colpts[Ncols]; ) {
p->c_ptr0 = p->c_ptr = (d+num);
}
balance(0);
return;
}
i = (Length - Margin) / Dblspace;
do {
(void) readbuf(&Bufptr, i, p++);
} while (++colno < Ncols);
}
static void
balance(int bline) /* line balancing for last page */
{
CHAR *s = Buffer;
register COLP p = Colpts;
int colno = 0;
int j;
int c;
int l;
int lines;
if (!fold) {
c = bline % Ncols;
l = (bline + Ncols - 1)/Ncols;
bline = 0;
do {
for (j = 0; j < l; ++j)
while (*s++ != '\n')
;
(++p)->c_lno = Lnumb + (bline += l);
p->c_ptr0 = p->c_ptr = s;
if (++colno == c)
--l;
} while (colno < Ncols - 1);
} else {
lines = readbuf(&s, 0, 0);
l = (lines + Ncols - 1)/Ncols;
if (l > ((Length - Margin) / Dblspace)) {
l = (Length - Margin) / Dblspace;
c = Ncols;
} else {
c = lines % Ncols;
}
s = Buffer;
do {
(void) readbuf(&s, l, p++);
if (++colno == c)
--l;
} while (colno < Ncols);
Bufptr = s;
}
}
static int
readbuf(char **s, int lincol, COLP p)
{
int lines = 0;
int chars = 0;
int width;
int nls = 0;
int move;
int skip = 0;
int decr = 0;
width = (Ncols == 1) ? Linew : Colw;
while (**s != (char) EOF) {
switch (**s) {
case '\n':
lines++; nls++; chars = 0; skip = 0;
break;
case '\b':
case ESC:
if (chars) chars--;
break;
case '\t':
move = Itabn - ((chars + Itabn) % Itabn);
move = (move < width-chars) ? move :
width-chars;
chars += move;
default:
if (isprint(**s))
chars++;
}
if (chars > width) {
lines++;
skip++;
decr++;
chars = 0;
}
if (lincol && lines == lincol) {
(p+1)->c_lno = p->c_lno + nls;
(++p)->c_skip = skip;
if (**s == '\n') (*s)++;
p->c_ptr0 = p->c_ptr = (CHAR *) *s;
return (0);
}
if (decr)
decr = 0;
else
(*s)++;
}
return (lines);
}
static int
get(int colno)
{
static int peekc = 0;
register COLP p;
register FILS *q;
register int c;
if (peekc) {
peekc = 0;
c = Etabc;
} else if (Buffer) {
p = &Colpts[colno];
if (p->c_ptr >= (p+1)->c_ptr0)
c = EOF;
else if ((c = *p->c_ptr) != EOF)
++p->c_ptr;
if (fold && c == (char)EOF)
Fcol[colno].eof = 1;
} else if ((c =
(q = &Files[Multi == 'a' ? 0 : colno])->f_nextc) == (char)EOF) {
for (q = &Files[Nfiles]; --q >= Files && q->f_nextc == EOF; )
;
if (q >= Files)
c = '\n';
} else
q->f_nextc = getc(q->f_f);
if (Etabn != 0 && c == Etabc) {
++Inpos;
peekc = ETABS;
c = ' ';
#ifdef EUC
} else if (isprint(c) && ISASCII(c))
#else
} else if (isprint(c))
#endif EUC
++Inpos;
else
switch (c) {
case '\b':
case ESC:
if (Inpos > 0)
--Inpos;
break;
case '\f':
if (Ncols == 1)
break;
c = '\n';
/*FALLTHROUGH*/
case '\n':
case '\r':
Inpos = 0;
#ifdef EUC
break;
default :
if (NOTASCII(c)) {
if (ISSET2(c)) {
setswitch = 2;
eucwcount = wp._eucw2;
scrwcount = wp._scrw2;
eucstart = ON;
} else if (ISSET3(c)) {
setswitch = 3;
eucwcount = wp._eucw3;
scrwcount = wp._scrw3;
eucstart = ON;
} else if (!setswitch) {
setswitch = 1;
eucwcount = wp._eucw1;
scrwcount = wp._scrw1;
eucstart = ON;
}
if (eucstart == ON)
Inpos += scrwcount;
}
#endif EUC
}
return (C = c);
}
static int
put(int c)
{
int move = 0;
int width = Colw;
int sp = Lcolpos;
if (fold && Ncols == 1)
width = Linew;
switch (c) {
case ' ':
/* If column not full or this is separator char */
if ((!fold && Ncols < 2) || (Lcolpos < width) ||
((Sepc == c) && (Lcolpos == width))) {
++Nspace;
++Lcolpos;
}
if (fold && sp == Lcolpos)
if (Lcolpos >= width)
return (1);
return (0);
case '\t':
if (Itabn == 0)
break;
/* If column not full or this is separator char */
if ((Lcolpos < width) ||
((Sepc == c) && (Lcolpos == width))) {
move = Itabn - ((Lcolpos + Itabn) % Itabn);
move = (move < width-Lcolpos) ? move : width-Lcolpos;
Nspace += move;
Lcolpos += move;
}
if (fold && sp == Lcolpos)
if (Lcolpos >= width)
return (1);
return (0);
case '\b':
if (Lcolpos == 0)
return (0);
if (Nspace > 0) {
--Nspace;
--Lcolpos;
return (0);
}
if (Lcolpos > Pcolpos) {
--Lcolpos;
return (0);
}
/*FALLTHROUGH*/
case ESC:
move = -1;
break;
case '\n':
++Line;
/*FALLTHROUGH*/
case '\r':
case '\f':
Pcolpos = 0;
Lcolpos = 0;
Nspace = 0;
Outpos = 0;
#ifdef EUC
setswitch = 0;
eucstart = OFF;
#endif EUC
default:
move = (isprint(c) != 0);
#ifdef EUC
if (NOTASCII(c)) {
if (eucstart == ON)
move = scrwcount;
else
move = 0;
if (--eucwcount <= 0)
setswitch = 0;
}
#endif EUC
}
if (Page < Fpage)
return (0);
if (Lcolpos > 0 || move > 0)
Lcolpos += move;
putspace();
/* If column not full or this is separator char */
if ((!fold && Ncols < 2) || (Lcolpos <= width) ||
((Sepc == c) && (Lcolpos > width))) {
(void) putchar(c);
Outpos += move;
Pcolpos = Lcolpos;
#ifdef EUC
if (eucstart == ON)
eucstart = OFF;
#endif EUC
}
#ifdef EUC
else if (eucstart == ON) {
eucstart = OFF;
setswitch = 0;
if (Lcolpos - scrwcount < Colw) {
Nspace += (Colw + scrwcount - Lcolpos);
putspace();
}
}
#endif EUC
if (fold && Lcolpos > width)
return (1);
return (0);
}
static void
putspace()
{
int nc = 0;
for (; Nspace > 0; Outpos += nc, Nspace -= nc) {
#ifdef XPG4
/* XPG4: -i: replace multiple SPACE chars with tab chars */
if ((Nspace >= 2 && Itabn > 0 &&
Nspace >= (nc = Itabn - Outpos % Itabn)) && !fold) {
#else
/* Solaris: -i: replace white space with tab chars */
if ((Itabn > 0 && Nspace >= (nc = Itabn - Outpos % Itabn)) &&
!fold) {
#endif
(void) putchar(Itabc);
} else {
nc = 1;
(void) putchar(' ');
}
}
}
static void
unget(int colno)
{
if (Buffer) {
if (*(Colpts[colno].c_ptr-1) != '\t')
--(Colpts[colno].c_ptr);
if (Colpts[colno].c_lno)
Colpts[colno].c_lno--;
} else {
if ((Multi == 'm' && colno == 0) || Multi != 'm')
if (Lnumb && !foldcol)
Lnumb--;
colno = (Multi == 'a') ? 0 : colno;
(void) ungetc(Files[colno].f_nextc, Files[colno].f_f);
Files[colno].f_nextc = C;
}
}
/*
* Defer message about failure to open file to prevent messing up
* alignment of page with tear perforations or form markers.
* Treat empty file as special case and report as diagnostic.
*/
static FILE *
mustopen(char *s, register FILS *f)
{
char *empty_file_msg = gettext("%s -- empty file");
if (*s == '\0') {
f->f_name = STDINNAME();
f->f_f = stdin;
} else if ((f->f_f = fopen(f->f_name = s, "r")) == NULL) {
s = ffiler(f->f_name);
s = strcpy((char *) getspace((UNS) strlen(s) + 1), s);
}
if (f->f_f != NULL) {
if ((f->f_nextc = getc(f->f_f)) != EOF || Multi == 'm')
return (f->f_f);
(void) sprintf(s = (char *) getspace((UNS) strlen(f->f_name)
+ 1 + (UNS) strlen(empty_file_msg)),
empty_file_msg, f->f_name);
(void) fclose(f->f_f);
}
Error = 1;
if (Report)
if (Ttyout) { /* accumulate error reports */
Lasterr = Lasterr->e_nextp =
(ERR *) getspace((UNS) sizeof (ERR));
Lasterr->e_nextp = NULL;
Lasterr->e_mess = s;
} else { /* ok to print error report now */
cerror(s);
(void) putc('\n', stderr);
}
return ((FILE *) NULL);
}
static ANY *
getspace(UNS n)
{
ANY *t;
if ((t = (ANY *) malloc(n)) == NULL)
die("out of space");
return (t);
}
static void
die(char *s)
{
++Error;
errprint();
cerror(s);
(void) putc('\n', stderr);
exit(1);
/*NOTREACHED*/
}
static void
errprint() /* print accumulated error reports */
{
(void) fflush(stdout);
for (; Err != NULL; Err = Err->e_nextp) {
cerror(Err->e_mess);
(void) putc('\n', stderr);
}
done();
}
static void
fixtty()
{
struct stat sbuf;
setbuf(stdout, obuf);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
(void) signal(SIGINT, onintr);
if (Ttyout = ttyname(fileno(stdout))) { /* is stdout a tty? */
(void) stat(Ttyout, &sbuf);
Mode = sbuf.st_mode; /* save permissions */
(void) chmod(Ttyout, (S_IREAD|S_IWRITE));
}
}
static void
onintr()
{
++Error;
errprint();
_exit(1);
}
static char *
GETDATE() /* return date file was last modified */
{
static char *now = NULL;
static struct stat sbuf;
static struct stat nbuf;
if (Nfiles > 1 || Files->f_name == nulls) {
if (now == NULL) {
(void) time(&nbuf.st_mtime);
(void) cftime(time_buf, gettext(FORMAT),
&nbuf.st_mtime);
now = time_buf;
}
return (now);
} else {
(void) stat(Files->f_name, &sbuf);
(void) cftime(time_buf, gettext(FORMAT), &sbuf.st_mtime);
return (time_buf);
}
}
static char *
ffiler(char *s)
{
static char buf[100];
(void) sprintf(buf, gettext("can't open %s"), s);
return (buf);
}
static void
usage(int rc)
{
(void) fprintf(stderr, gettext(
"usage: pr [-# [-w #] [-a]] [-e[c][#]] [-i[c][#]] [-drtfp] [-n[c][#]] \\\n"
" [-o #] [-l #] [-s[char]] [-h header] [-F] [+#] [file ...]\n\n"
" pr [-m [-w #]] [-e[c][#]] [-i[c][#]] [-drtfp] [-n[c][#]] [-0 #] \\\n"
" [-l #] [-s[char]] [-h header] [-F] [+#] file1 file2 ...\n"
));
exit(rc);
}