diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/pr | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/pr')
| -rw-r--r-- | usr/src/cmd/pr/Makefile | 56 | ||||
| -rw-r--r-- | usr/src/cmd/pr/pr.c | 1540 | ||||
| -rw-r--r-- | usr/src/cmd/pr/pr.xcl | 30 |
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" |
