summaryrefslogtreecommitdiff
path: root/usr/src/cmd/pr
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/pr
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/pr')
-rw-r--r--usr/src/cmd/pr/Makefile56
-rw-r--r--usr/src/cmd/pr/pr.c1540
-rw-r--r--usr/src/cmd/pr/pr.xcl30
3 files changed, 1626 insertions, 0 deletions
diff --git a/usr/src/cmd/pr/Makefile b/usr/src/cmd/pr/Makefile
new file mode 100644
index 0000000000..8c6b8c8747
--- /dev/null
+++ b/usr/src/cmd/pr/Makefile
@@ -0,0 +1,56 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1989 by Sun Microsystems, Inc.
+#
+
+PROG= pr
+XPG4PROG= pr
+
+include ../Makefile.cmd
+
+SED = sed
+DCFILE = $(PROG).dc
+
+$(XPG4):= CPPFLAGS += -DXPG4
+$(POFILE) := XGETFLAGS += -a -x pr.xcl
+
+.KEEP_STATE:
+
+all: $(PROG) $(XPG4)
+
+install: all $(ROOTPROG) $(ROOTXPG4PROG)
+
+clean:
+
+lint: lint_PROG
+
+$(DCFILE):
+ $(RM) messages.po
+ $(COMPILE.cpp) $(PROG).c | \
+ $(XGETTEXT) $(XGETFLAGS) -t -
+ $(SED) -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/pr/pr.c b/usr/src/cmd/pr/pr.c
new file mode 100644
index 0000000000..6cf12e460b
--- /dev/null
+++ b/usr/src/cmd/pr/pr.c
@@ -0,0 +1,1540 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 <sys/types.h>
+#include <sys/stat.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 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, n) \
+ { \
+ int i; \
+ for (i = ind; argp[i]; i++) \
+ argp[i] = argp[i + n]; \
+ }
+
+/*
+ * ---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;
+typedef struct { FILE *f_f; char *f_name; wchar_t f_nextc; } FILS;
+typedef struct {int fold; int skip; int eof; } foldinf;
+typedef struct { wchar_t *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 wchar_t 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 wchar_t Etabc = '\t';
+static int Itabn = 0;
+static wchar_t Itabc = '\t';
+static int fold = 0;
+static int foldcol = 0;
+static int alleof = 0;
+static char *Head = NULL;
+static wchar_t *Buffer = NULL, *Bufend, *Bufptr;
+static UNS Buflen;
+static COLP Colpts;
+static foldinf *Fcol;
+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 ERR *Err = NULL;
+static ERR *Lasterr = (ERR *)&Err;
+static int mbcurmax = 1;
+
+/*
+ * 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(wchar_t **, int, COLP);
+static wint_t get(int);
+static int put(wchar_t);
+static void putspace();
+static void unget(int);
+static FILE *mustopen(char *, FILS *);
+static void die(char *);
+static void errprint();
+static void usage(int);
+static wint_t _fgetwc_pr(FILE *, int *);
+static size_t freadw(wchar_t *, size_t, FILE *);
+
+
+main(int argc, char **argv)
+{
+ FILS fstr[NFILES];
+ int nfdone = 0;
+
+
+ /* Get locale variables for environment */
+ (void) setlocale(LC_ALL, "");
+
+#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);
+
+ mbcurmax = MB_CUR_MAX;
+ 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:
+ end_opt++;
+ 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, 1);
+ if ((c = argv[optnum][argv_ind]) != '\0' &&
+ !isdigit(c)) {
+ int r;
+ wchar_t wc;
+ r = mbtowc(&wc, &argv[optnum][argv_ind],
+ mbcurmax);
+ if (r == -1) {
+ (void) fprintf(stderr, gettext(
+"pr: Illegal character in -e option\n"));
+ exit(1);
+ }
+ Etabc = wc;
+ SQUEEZE_ARG(argv[optnum], argv_ind, r);
+ }
+ 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, 1);
+ }
+ if (Etabn <= 0)
+ Etabn = DEFTAB;
+ argv_ind--;
+ break;
+
+ case 'i':
+ SQUEEZE_ARG(argv[optnum], argv_ind, 1);
+ if ((c = argv[optnum][argv_ind]) != '\0' &&
+ !isdigit(c)) {
+ int r;
+ wchar_t wc;
+ r = mbtowc(&wc, &argv[optnum][argv_ind],
+ mbcurmax);
+ if (r == -1) {
+ (void) fprintf(stderr, gettext(
+"pr: Illegal character in -i option\n"));
+ exit(1);
+ }
+ Itabc = wc;
+ SQUEEZE_ARG(argv[optnum], argv_ind, r);
+ }
+ 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, 1);
+ }
+ if (Itabn <= 0)
+ Itabn = DEFTAB;
+ argv_ind--;
+ break;
+
+
+ case 'n':
+ ++Lnumb;
+ SQUEEZE_ARG(argv[optnum], argv_ind, 1);
+ if ((c = argv[optnum][argv_ind]) != '\0' &&
+ !isdigit(c)) {
+ int r;
+ wchar_t wc;
+ r = mbtowc(&wc, &argv[optnum][argv_ind],
+ mbcurmax);
+ if (r == -1) {
+ (void) fprintf(stderr, gettext(
+"pr: Illegal character in -n option\n"));
+ exit(1);
+ }
+ Nsepc = wc;
+ SQUEEZE_ARG(argv[optnum], argv_ind, r);
+ }
+ 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, 1);
+ }
+ argv_ind--;
+ if (!Numw)
+ Numw = NUMW;
+ break;
+
+ case 's':
+ SQUEEZE_ARG(argv[optnum], argv_ind, 1);
+ if ((Sepc = argv[optnum][argv_ind]) == '\0')
+ Sepc = '\t';
+ else {
+ int r;
+ wchar_t wc;
+ r = mbtowc(&wc, &argv[optnum][argv_ind],
+ mbcurmax);
+ if (r == -1) {
+ (void) fprintf(stderr, gettext(
+"pr: Illegal character in -s option\n"));
+ exit(1);
+ }
+ Sepc = wc;
+ SQUEEZE_ARG(argv[optnum], argv_ind, r);
+ }
+ 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 + ((iswprint(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 should take the number of wide characters */
+ /* Not the size for Buffer */
+ Buflen = ((UNS) (Plength / Dblspace + 1)) *
+ 2 * (Linew + 1);
+ /* Should allocate Buflen * sizeof (wchar_t) */
+ Buffer = (wchar_t *)getspace(Buflen * sizeof (wchar_t));
+ 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) ungetwc(Files->f_nextc, Files->f_f);
+ if (Lnumb)
+ Lnumb = 1;
+ for (Page = 0; ; putpage()) {
+ if (C == WEOF && !(fold && Buffer))
+ break;
+ if (Buffer)
+ nexbuf();
+ Inpos = 0;
+ if (get(0) == WEOF)
+ 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()
+{
+ 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 != WEOF) &&
+ (((colno == 0) && (Multi == 'm')) ||
+ (Multi != 'm'))) {
+ if (Page >= Fpage) {
+ putspace();
+ (void) printf("%*ld%wc", 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 != WEOF;
+ (void) get(colno))
+ (void) put(C);
+
+ if ((C == WEOF) || (++colno == Ncols) ||
+ ((C == '\n') && (get(colno) == WEOF)))
+ break;
+
+ if (Sepc)
+ (void) put(Sepc);
+ else if ((Nspace += Colw - Lcolpos + 1) < 1)
+ Nspace = 1;
+ }
+
+ if (C == WEOF) {
+ 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()
+{
+ int colno;
+ int keep;
+ int i;
+ int pLcolpos;
+ 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("%wc", 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 != WEOF) &&
+ ((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("%wc", Nsepc);
+ if (Buffer) {
+ Colpts[colno].c_lno++;
+ Colpts[colno].c_skip =
+ 0;
+ }
+ }
+ else
+ (void) printf("%*ld%wc", Numw, Buffer ?
+ Colpts[colno].c_lno++ :
+ Lnumb, Nsepc);
+ }
+ sl = Lnumb++;
+ }
+ pLcolpos = 0;
+ for (Lcolpos = 0, Pcolpos = 0;
+ C != '\n' && C != '\f' && C != WEOF;
+ (void) get(colno)) {
+ if (put(C)) {
+ unget(colno);
+ Fcol[(Multi == 'a') ? 0 : colno].fold
+ = 1;
+ break;
+ } else if (Multi == 'a') {
+ Fcol[0].fold = 0;
+ }
+ pLcolpos = Lcolpos;
+ }
+ 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 == WEOF)
+ break;
+ if (Sepc)
+ (void) put(Sepc);
+ else if ((Nspace += Colw - pLcolpos + 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 == WEOF) {
+ 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()
+{
+ wchar_t *s = Buffer;
+ COLP p = Colpts;
+ int j;
+ int c;
+ int bline = 0;
+ wchar_t wc;
+
+ 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; ; ) {
+ errno = 0;
+ wc = _fgetwc_pr(Files->f_f, &c);
+ if (wc == WEOF) {
+ /* If there is an illegal character, */
+ /* handle it as a byte sequence. */
+ if (errno == EILSEQ) {
+ if (Inpos < Colw - 1) {
+ *s = c;
+ if (++s >= Bufend)
+die("page-buffer overflow");
+ }
+ Inpos++;
+ Error++;
+ return;
+ } else {
+ /* Real EOF */
+for (*s = WEOF; p <= &Colpts[Ncols]; ++p)
+ p->c_ptr0 = p->c_ptr = s;
+ balance(bline);
+ return;
+ }
+ }
+
+ if (isascii(wc)) {
+ if (isprint(wc))
+ Inpos++;
+ } else if (iswprint(wc)) {
+ Inpos += wcwidth(wc);
+ }
+
+ if (Inpos <= Colw || wc == '\n') {
+ *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;
+ int size = Buflen;
+ wchar_t *s;
+ wchar_t *d;
+ 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 = freadw(d, size, Files->f_f)) != size) {
+ for (*(d+num) = WEOF; (++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 */
+{
+ wchar_t *s = Buffer;
+ 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(wchar_t **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 != WEOF) {
+ 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 (isascii(**s)) {
+ if (isprint(**s))
+ chars++;
+ } else if (iswprint(**s)) {
+ chars += wcwidth(**s);
+ }
+ }
+ 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 = (wchar_t *)*s;
+ return (0);
+ }
+ if (decr)
+ decr = 0;
+ else
+ (*s)++;
+ }
+ return (lines);
+}
+
+
+static wint_t
+get(int colno)
+{
+ static int peekc = 0;
+ COLP p;
+ FILS *q;
+ int c;
+ wchar_t wc, w;
+
+ if (peekc) {
+ peekc = 0;
+ wc = Etabc;
+ } else if (Buffer) {
+ p = &Colpts[colno];
+ if (p->c_ptr >= (p+1)->c_ptr0)
+ wc = WEOF;
+ else if ((wc = *p->c_ptr) != WEOF)
+ ++p->c_ptr;
+ if (fold && wc == WEOF)
+ Fcol[colno].eof = 1;
+ } else if ((wc =
+ (q = &Files[Multi == 'a' ? 0 : colno])->f_nextc) == WEOF) {
+ for (q = &Files[Nfiles]; --q >= Files && q->f_nextc == WEOF; )
+ ;
+ if (q >= Files)
+ wc = '\n';
+ } else {
+ errno = 0;
+ w = _fgetwc_pr(q->f_f, &c);
+ if (w == WEOF && errno == EILSEQ) {
+ q->f_nextc = (wchar_t)c;
+ } else {
+ q->f_nextc = w;
+ }
+ }
+
+ if (Etabn != 0 && wc == Etabc) {
+ ++Inpos;
+ peekc = ETABS;
+ wc = ' ';
+ return (C = wc);
+ }
+
+ if (wc == WEOF)
+ return (C = wc);
+
+ if (isascii(wc)) {
+ if (isprint(wc)) {
+ Inpos++;
+ return (C = wc);
+ }
+ } else if (iswprint(wc)) {
+ Inpos += wcwidth(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
+put(wchar_t wc)
+{
+ int move = 0;
+ int width = Colw;
+ int sp = Lcolpos;
+
+ if (fold && Ncols == 1)
+ width = Linew;
+
+ switch (wc) {
+ case ' ':
+ /* If column not full or this is separator char */
+ if ((!fold && Ncols < 2) || (Lcolpos < width) ||
+ ((Sepc == wc) && (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 == wc) && (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;
+ /* FALLTHROUGH */
+ default:
+ if (isascii(wc)) {
+ if (isprint(wc))
+ move = 1;
+ else
+ move = 0;
+ } else if (iswprint(wc)) {
+ move = wcwidth(wc);
+ } else {
+ move = 0;
+ }
+ break;
+ }
+ 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 == wc) && (Lcolpos > width))) {
+ (void) fputwc(wc, stdout);
+ Outpos += move;
+ Pcolpos = Lcolpos;
+ }
+
+ if (fold && Lcolpos > width)
+ return (1);
+
+ return (0);
+}
+
+
+static void
+putspace(void)
+{
+ 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) fputwc(Itabc, stdout);
+ } 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) ungetwc(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, FILS *f)
+{
+ char *empty_file_msg = gettext("%s -- empty file");
+ int c;
+
+ 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) {
+ errno = 0;
+ f->f_nextc = _fgetwc_pr(f->f_f, &c);
+ if (f->f_nextc != WEOF) {
+ return (f->f_f);
+ } else { /* WEOF */
+ if (errno == EILSEQ) {
+ f->f_nextc = (wchar_t)c;
+ return (f->f_f);
+ }
+ if (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,
+ dcgettext(NULL, FORMAT, LC_TIME),
+ &nbuf.st_mtime);
+ now = time_buf;
+ }
+ return (now);
+ } else {
+ (void) stat(Files->f_name, &sbuf);
+ (void) cftime(time_buf, dcgettext(NULL, FORMAT, LC_TIME),
+ &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);
+}
+
+static wint_t
+_fgetwc_pr(FILE *f, int *ic)
+{
+ int i;
+ int len;
+ char mbuf[MB_LEN_MAX];
+ int c;
+ wchar_t wc;
+
+ c = getc(f);
+
+ if (c == EOF)
+ return (WEOF);
+ if (mbcurmax == 1 || isascii(c)) {
+ 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;
+
+ len = mbtowc(&wc, mbuf, i);
+ if (len == -1) {
+ /* Illegal character */
+ /* Set the first byte to *ic */
+ *ic = mbuf[0];
+ /* Push back remaining characters */
+ for (i--; i > 0; i--) {
+ (void) ungetc(mbuf[i], f);
+ }
+ errno = EILSEQ;
+ return (WEOF);
+ } else {
+ /* Push back over-read characters */
+ for (i--; i >= len; i--) {
+ (void) ungetc(mbuf[i], f);
+ }
+ return ((wint_t)wc);
+ }
+}
+
+static size_t
+freadw(wchar_t *ptr, size_t nitems, FILE *f)
+{
+ size_t i;
+ size_t ret;
+ int c;
+ wchar_t *p;
+ wint_t wc;
+
+ if (feof(f)) {
+ return (0);
+ }
+
+ p = ptr;
+ ret = 0;
+ for (i = 0; i < nitems; i++) {
+ errno = 0;
+ wc = _fgetwc_pr(f, &c);
+ if (wc == WEOF) {
+ if (errno == EILSEQ) {
+ *p++ = (wchar_t)c;
+ ret++;
+ } else {
+ return (ret);
+ }
+ } else {
+ *p++ = (wchar_t)wc;
+ ret++;
+ }
+ }
+ return (ret);
+}
diff --git a/usr/src/cmd/pr/pr.xcl b/usr/src/cmd/pr/pr.xcl
new file mode 100644
index 0000000000..b4615cdab5
--- /dev/null
+++ b/usr/src/cmd/pr/pr.xcl
@@ -0,0 +1,30 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+msgid ""
+msgid " "
+msgid "%*ld%c"
+msgid "%b %e %H:%M %Y"
+msgid "%c"
+msgid "/dev/tty"
+msgid "\n\n"
+msgid "pr: %s"
+msgid "r"