pr.c revision a77d64af7813dad3dad148a9974e0ec7b80d1f43
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
* All Rights Reserved
*/
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* PR command (print files in pages and columns, with headings)
* 2+head+2+page[56]+5
*/
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
#include <wchar.h>
#include <errno.h>
#define ESC '\033'
#define LENGTH 66
#define LINEW 72
#define NUMW 5
#define MARGIN 10
#define DEFTAB 8
#define NFILES 10
#define NSEPC '\t'
{ \
char **p = argp; \
while (*p != NULL) \
{ \
*p = *(p + 1); \
p++; \
} \
argc--; \
}
{ \
int i; \
}
/*
* ---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"
typedef int ANY;
typedef unsigned int UNS;
/*
* Global data.
*/
static int Multi = 0;
static int Nfiles = 0;
static int Error = 0;
static char nulls[] = "";
static char *Ttyout;
static long Lnumb = 0;
static int Dblspace = 1;
static int Fpage = 1;
static int Formfeed = 0;
static int Linew = 0;
static int Offset = 0;
static int Ncols = 0;
static int Pause = 0;
static int Colw;
static int Plength;
static int Numw;
static int Report = 1;
static int Etabn = 0;
static int Itabn = 0;
static int fold = 0;
static int foldcol = 0;
static int alleof = 0;
static int Page;
static wchar_t C = '\0';
static int Nspace;
static int Inpos;
static int Outpos;
static int Lcolpos;
static int Pcolpos;
static int Line;
static int mbcurmax = 1;
/*
* Function prototypes.
*/
static void onintr();
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 void putspace();
static void unget(int);
static void die(char *);
static void errprint();
static void usage(int);
int
{
int nfdone = 0;
/* Get locale variables for environment */
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
if (Multi == 'm') {
++nfdone; /* suppress printing */
} else {
++nfdone;
}
}
if (!nfdone) /* no files named, use stdin */
if (Report) {
errprint(); /* print accumulated error reports */
}
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
{
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 */
case '+':
/* check for all digits */
"pr: Badly formed number\n"));
exit(1);
}
(char **)NULL, 10)) < 0) {
"pr: Badly formed number\n"));
exit(1);
}
optnum--;
break;
case '-':
/* Check for end of options */
end_opt++;
break;
}
break;
default:
end_opt++;
break;
}
}
/*
* Handle options with optional arguments.
* If optional arguments are present they may not be separated
* from the option letter.
*/
/* End of options */
break;
/* stdin file name */
continue;
/* not option */
continue;
case 'e':
!isdigit(c)) {
int r;
mbcurmax);
if (r == -1) {
"pr: Illegal character in -e option\n"));
exit(1);
}
}
argv_ind, 1);
}
if (Etabn <= 0)
argv_ind--;
break;
case 'i':
!isdigit(c)) {
int r;
mbcurmax);
if (r == -1) {
"pr: Illegal character in -i option\n"));
exit(1);
}
}
argv_ind, 1);
}
if (Itabn <= 0)
argv_ind--;
break;
case 'n':
++Lnumb;
!isdigit(c)) {
int r;
mbcurmax);
if (r == -1) {
"pr: Illegal character in -n option\n"));
exit(1);
}
}
argv_ind, 1);
}
argv_ind--;
if (!Numw)
break;
case 's':
Sepc = '\t';
else {
int r;
mbcurmax);
if (r == -1) {
"pr: Illegal character in -s option\n"));
exit(1);
}
}
argv_ind--;
break;
default:
break;
}
}
optnum--;
}
}
/* Now get the other options */
!= 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':
break;
case 'l':
usage(1);
break;
case 'm':
mflg++;
Multi = c;
break;
case 'o':
usage(1);
break;
case 'p':
++Pause;
break;
case 'r':
Report = 0;
break;
case 't':
Margin = 0;
break;
case 'w':
usage(1);
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 (i < optind)
optind--;
}
}
eargc++;
}
/* Check options */
if (Ncols == 0)
Ncols = 1;
gettext("pr: only one of either -m or -column allowed\n"));
usage(1);
}
Multi = 'm';
if (Length <= 0)
Margin = 0;
if (Multi == 'm')
switch (Ncols) {
case 0:
Ncols = 1;
break;
case 1:
break;
default:
if (Etabn == 0) /* respect explicit tab specification */
if (Itabn == 0)
}
exit(1);
}
for (i = 0; i < Ncols; i++)
if (Linew == 0)
if (Lnumb) {
int numw;
if (Nsepc == '\t') {
if (Itabn == 0)
else
} else {
}
}
die("width too small");
/* Buflen should take the number of wide characters */
/* Not the size for Buffer */
/* Should allocate Buflen * sizeof (wchar_t) */
sizeof (*Colpts)));
}
/* is stdin not a tty? */
return (eargc);
}
static int
{
static int notfirst = 0;
int c;
return (0);
die("cannot open stdin");
if (Buffer)
if (Lnumb)
Lnumb = 1;
break;
if (Buffer)
nexbuf();
Inpos = 0;
break;
/* Pause if -p and not first page */
PROMPT(); /* prompt with bell and pause */
;
}
if (Margin == 0)
continue;
(void) printf("\n\n");
putspace();
}
}
C = '\0';
return (1);
}
static void
putpage()
{
int colno;
if (fold) {
foldpage();
return;
}
(Multi != 'm'))) {
putspace();
/* Move Outpos for number field */
if (Nsepc == '\t')
Outpos +=
else
Outpos++;
}
++Lnumb;
}
(void) put(C);
break;
if (Sepc)
Nspace = 1;
}
if (C == WEOF) {
if (Margin != 0)
break;
if (colno != 0)
(void) put('\n');
return;
}
if (C == '\f')
break;
(void) put('\n');
(void) put('\n');
break;
}
if (Formfeed)
(void) put('\f');
else
(void) put('\n');
}
static void
foldpage()
{
int colno;
int keep;
int i;
int pLcolpos;
static int sl;
putspace();
if (!colno) {
for (i = 0; i <= Numw; i++)
(void) printf(" ");
}
for (i = 0; i <= Colw; i++)
(void) printf(" ");
break;
continue;
} else if (!colno)
}
putspace();
if ((foldcol &&
for (i = 0; i < Numw; i++)
(void) printf(" ");
if (Buffer) {
0;
}
}
else
}
}
pLcolpos = 0;
if (put(C)) {
= 1;
break;
} else if (Multi == 'a') {
}
}
if (Buffer) {
alleof = 1;
for (i = 0; i < Ncols; i++)
alleof = 0;
break;
break;
keep = C;
break;
if (Sepc)
Nspace = 1;
}
foldcol = 0;
for (i = 0; i < Ncols; i++) {
}
}
if (C == WEOF) {
if (Margin != 0)
break;
if (colno != 0)
(void) put('\n');
return;
}
if (C == '\f')
break;
(void) put('\n');
(void) put('\n');
break;
}
if (Formfeed)
(void) put('\f');
(void) put('\n');
}
static void
nexbuf()
{
int j;
int c;
int bline = 0;
if (fold) {
foldbuf();
return;
}
for (; ; ) {
return;
for (Inpos = 0; ; ) {
errno = 0;
/* If there is an illegal character, */
/* handle it as a byte sequence. */
*s = c;
if (++s >= Bufend)
die("page-buffer overflow");
}
Inpos++;
Error++;
return;
} else {
/* Real EOF */
return;
}
}
Inpos++;
}
*s = wc;
if (++s >= Bufend)
die("page-buffer overflow");
}
if (wc == '\n')
break;
switch (wc) {
case '\b':
if (Inpos == 0)
--s;
/*FALLTHROUGH*/
case ESC:
if (Inpos > 0)
--Inpos;
}
}
}
}
}
static void
foldbuf()
{
int num;
int i;
int colno = 0;
wchar_t *s;
wchar_t *d;
for (i = 0; i < Ncols; i++)
d = Buffer;
s = Bufptr;
while (s < Bufend)
*d++ = *s++;
}
if (p->c_lno == 0) {
p->c_skip = 0;
} else {
if (p->c_skip)
p->c_lno--;
}
}
balance(0);
return;
}
do {
}
static void
{
int colno = 0;
int j;
int c;
int l;
int lines;
if (!fold) {
bline = 0;
do {
for (j = 0; j < l; ++j)
while (*s++ != '\n')
;
if (++colno == c)
--l;
} else {
c = Ncols;
} else {
}
s = Buffer;
do {
(void) readbuf(&s, l, p++);
if (++colno == c)
--l;
Bufptr = s;
}
}
static int
{
int lines = 0;
int chars = 0;
int width;
int nls = 0;
int move;
int skip = 0;
int decr = 0;
while (**s != WEOF) {
switch (**s) {
case '\n':
break;
case '\b':
case ESC:
break;
case '\t':
default:
if (isascii(**s)) {
if (isprint(**s))
chars++;
} else if (iswprint(**s)) {
}
}
lines++;
skip++;
decr++;
chars = 0;
}
if (**s == '\n') (*s)++;
return (0);
}
if (decr)
decr = 0;
else
(*s)++;
}
return (lines);
}
static wint_t
{
static int peekc = 0;
COLP p;
FILS *q;
int c;
if (peekc) {
peekc = 0;
} else if (Buffer) {
++p->c_ptr;
} else if ((wc =
;
if (q >= Files)
wc = '\n';
} else {
errno = 0;
w = _fgetwc_pr(q->f_f, &c);
} else {
q->f_nextc = w;
}
}
++Inpos;
wc = ' ';
return (C = wc);
}
return (C = wc);
Inpos++;
return (C = wc);
}
return (C = wc);
}
switch (wc) {
case '\b':
case ESC:
if (Inpos > 0)
--Inpos;
break;
case '\f':
if (Ncols == 1)
break;
wc = '\n';
/* FALLTHROUGH */
case '\n':
case '\r':
Inpos = 0;
break;
}
return (C = wc);
}
static int
{
int move = 0;
switch (wc) {
case ' ':
/* If column not full or this is separator char */
++Nspace;
++Lcolpos;
}
return (1);
return (0);
case '\t':
if (Itabn == 0)
break;
/* If column not full or this is separator char */
}
return (1);
return (0);
case '\b':
if (Lcolpos == 0)
return (0);
if (Nspace > 0) {
--Nspace;
--Lcolpos;
return (0);
}
--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;
/* FALLTHROUGH */
default:
move = 1;
else
move = 0;
} else {
move = 0;
}
break;
}
return (0);
putspace();
/* If column not full or this is separator char */
}
return (1);
return (0);
}
static void
putspace(void)
{
int nc = 0;
#ifdef XPG4
/* XPG4: -i: replace multiple SPACE chars with tab chars */
#else
/* Solaris: -i: replace white space with tab chars */
!fold) {
#endif
} else {
nc = 1;
(void) putchar(' ');
}
}
}
static void
{
if (Buffer) {
} else {
Lnumb--;
}
}
/*
* 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 *
{
int c;
if (*s == '\0') {
}
errno = 0;
return (f->f_f);
} else { /* WEOF */
return (f->f_f);
}
if (Multi == 'm')
return (f->f_f);
}
empty_file_msg, f->f_name);
}
Error = 1;
if (Report)
if (Ttyout) { /* accumulate error reports */
} else { /* ok to print error report now */
cerror(s);
}
}
static ANY *
{
ANY *t;
die("out of space");
return (t);
}
static void
die(char *s)
{
++Error;
errprint();
cerror(s);
exit(1);
/*NOTREACHED*/
}
static void
errprint() /* print accumulated error reports */
{
}
done();
}
static void
fixtty()
{
}
}
static void
onintr()
{
++Error;
errprint();
_exit(1);
}
static char *
GETDATE() /* return date file was last modified */
{
}
return (now);
} else {
return (time_buf);
}
}
static char *
ffiler(char *s)
{
static char buf[100];
return (buf);
}
static void
{
"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"
));
}
static wint_t
{
int i;
int len;
char mbuf[MB_LEN_MAX];
int c;
c = getc(f);
if (c == EOF)
return (WEOF);
return ((wint_t)c);
}
mbuf[0] = (char)c;
for (i = 1; i < mbcurmax; i++) {
c = getc(f);
if (c == EOF) {
break;
} else {
mbuf[i] = (char)c;
}
}
mbuf[i] = 0;
if (len == -1) {
/* Illegal character */
/* Set the first byte to *ic */
/* Push back remaining characters */
for (i--; i > 0; i--) {
}
return (WEOF);
} else {
/* Push back over-read characters */
for (i--; i >= len; i--) {
}
}
}
static size_t
{
size_t i;
int c;
wchar_t *p;
if (feof(f)) {
return (0);
}
p = ptr;
ret = 0;
for (i = 0; i < nitems; i++) {
errno = 0;
wc = _fgetwc_pr(f, &c);
*p++ = (wchar_t)c;
ret++;
} else {
return (ret);
}
} else {
ret++;
}
}
return (ret);
}