/* * Changes by Gunnar Ritter, Freiburg i. Br., Germany, May 2003. */ /* from Unix 32V /usr/src/cmd/pr.c */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * Redistributions of source code and documentation must retain the * above copyright notice, this list of conditions and the following * disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of * other contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * print file with headings * 2+head+2+page[56]+5 */ #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 #define USED __attribute__ ((used)) #elif defined __GNUC__ #define USED __attribute__ ((unused)) #else #define USED #endif #if defined (SUS) static const char sccsid[] USED = "@(#)pr_sus.sl 1.29 (gritter) 5/29/05"; #else /* !SUS */ static const char sccsid[] USED = "@(#)pr.sl 1.29 (gritter) 5/29/05"; #endif /* !SUS */ #include #include #include "sigset.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef __GLIBC__ #ifdef _IO_getc_unlocked #undef getc #define getc(f) _IO_getc_unlocked(f) #endif #ifdef _IO_putc_unlocked #undef putc #define putc(c, f) _IO_putc_unlocked(c, f) #undef putchar #define putchar(c) _IO_putc_unlocked(c, stdout) #endif #endif /* __GLIBC__ */ #include #include #include #define next(wc, s, n) (mb_cur_max > 1 && *(s) & 0200 ? \ ((n) = mbtowi(&(wc), (s), mb_cur_max), \ (n) = ((n) > 0 ? (n) : (n) < 0 ? (wc=WEOF, 1) : 1)) :\ ((wc) = *(s) & 0377, (n) = 1)) static struct chargap { wint_t c_c; int c_g; int c_u; } eflg = { '\t', 8, 0 }, iflg = { '\t', 8, 0 }, nflg = { '\t', 5, 0 }; static int status; static const char *progname; static int ncol = 1; static const char *header; static int col; static long NCOL; static int *icol; static int *scol; static struct iblok *file; static long BUFS; static wint_t *buffer; /* for multi-column output */ #define FF 014 static int line; static wint_t **colp; static int nofile; static char isclosed[10]; static struct iblok *ifile[10]; static const char **lastarg; static wint_t *peekc, *peek2c; static long long fpage; static long long page; static int colw; static int nspace; static int width = 72; static int length = 66; static int plength = 61; static int margin = 10; static int ntflg; static int mflg; static wint_t tabc; static char *tty; static int mode; static int oneof; static int mb_cur_max; static const char *curfile; static int aflg; static int dflg; static int fflg; static int oflg; static int wflg; static int Fflg; static int rflg; static int pflg = -1; static int numwidth; static void usage(int); static void eitmcol(void); static wint_t argchar(int, const char *); static struct chargap getcg(int, const char *, struct chargap); static void done(void); static void onintr(int); static void fixtty(void); static void print(const char *, const char **); static void mopen(const char **); static wint_t putpage(void); static wint_t readc(void); static wint_t tpgetc(int); static wint_t pgetc(int); static void put(wint_t); static void putcp(wint_t); static void putcs(const char *); static int putnum(long long); static int cnumwidth(void); static void delaym(const char *, const char *); static void printm(void); int main(int argc, char **argv) { int nfdone, hadtd; int ac; const char **av, *ap; progname = basename(argv[0]); setlocale(LC_CTYPE, ""); mb_cur_max = MB_CUR_MAX; setlocale(LC_TIME, ""); if (sigset(SIGINT, SIG_IGN) != SIG_IGN) sigset(SIGINT, onintr); lastarg = (const char **)&argv[argc-1]; fixtty(); ac = argc, av = (const char **)argv; for (nfdone=0; ac>1; ac--) { av++; if (**av == '-' && av[0][1]) { if (av[0][1] == '-' && av[0][2] == '\0') break; ap = *av; nc: switch (*++ap) { case 'a': aflg++; goto nc; case 'd': dflg++; goto nc; case 'F': #ifndef SUS Fflg++; goto nc; #endif /* SUS */ case 'f': fflg++; goto nc; case 'r': rflg++; goto nc; case 'p': pflg = open("/dev/tty", O_RDONLY); goto nc; case 'e': eflg = getcg('e', &ap[1], eflg); continue; case 'i': iflg = getcg('i', &ap[1], iflg); continue; case 'n': nflg = getcg('n', &ap[1], nflg); continue; case 'o': if (ap[1]) oflg = atoi(++ap); else if (ac>2) { oflg = atoi(*++av); *av = NULL; ac--; } continue; case 'h': if (ap[1]) header = &ap[1]; else if (ac>2) { header = *++av; *av = NULL; ac--; } continue; case 't': ntflg++; goto nc; case 'l': if (ap[1]) length = atoi(++ap); else if (ac>2) { length = atoi(*++av); *av = NULL; ac--; } continue; case 'w': wflg++; if (ap[1]) width = atoi(++ap); else if (ac>2) { width = atoi(*++av); *av = NULL; ac--; } #ifdef SUS else usage(0); #endif /* SUS */ continue; case 's': if (*++ap) tabc = argchar('s', ap); else tabc = '\t'; if (wflg == 0) width = 512; continue; case 'm': if (ncol > 1) eitmcol(); mflg++; goto nc; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (mflg) eitmcol(); ncol = atoi(ap); continue; case '\0': continue; default: usage(*ap); } } else if (**av == '+') { fpage = atoll(&(*av)[1]); } else { nfdone++; if (mflg) break; } } if (aflg && ncol <= 1) { fprintf(stderr, "%s: -a valid only with -column\n", progname); usage(0); } numwidth = cnumwidth(); if ((nflg.c_u&(1|2)) == 1 && ncol > 1) nflg.c_c = ' '; ac = argc, av = (const char **)argv; if (nfdone==0) mflg = 0; if ((aflg||mflg) == 0) { BUFS = ncol > 1 ? length*3*(width+1) : 2; if ((buffer = calloc(BUFS+1, sizeof *buffer)) == 0) { write(2, "out of space\n", 13); exit(1); } } NCOL = mflg ? 10 : ncol; if ((icol = calloc(NCOL, sizeof *icol)) == NULL || (scol = calloc(NCOL, sizeof *scol)) == NULL || (colp = calloc(NCOL, sizeof *colp)) == NULL || (peekc = calloc(NCOL, sizeof *peekc)) == NULL || (peek2c = calloc(NCOL, sizeof *peek2c)) == NULL) { free(buffer); fprintf(stderr, "%s: No room for columns.\n", progname); exit(1); } for (nfdone=0, hadtd=0; ac>1; ac--) { av++; if (*av) { if (**av != '-' && **av != '+' || hadtd || **av == '-' && av[0][1] == '\0') { print(*av, av); nfdone++; if (mflg) break; } else if (av[0][0] == '-' && av[0][1] == '-' && av[0][2] == '\0') hadtd++; } } if (nfdone==0) print(NULL, NULL); done(); /*NOTREACHED*/ return 0; } static void usage(int c) { if (c) fprintf(stderr, "%s: unknown option, %c\n", progname, c); fprintf(stderr, "\ usage: %s [-column [-wwidth] [-a]] [-ect] [-ict] [-drtfp] [+page] [-nsk] \\\n\ [-ooffset] [-llength] [-sseparator] [-h header] [-F] [file ...]\n\ \n\ %s [-m [-wwidth]] [-ect] [-ict] [-drtfp] [+page] [-nsk] \\\n\ [-ooffset] [-llength] [-sseparator] [-h header] [-F] file1 file2 ...\ \n", progname, progname); exit(1); } static void eitmcol(void) { fprintf(stderr, "%s: only one of either -m or -column allowed\n", progname); usage(0); } static wint_t argchar(int optc, const char *ap) { wint_t wc; int n; next(wc, ap, n); if (wc == WEOF) { fprintf(stderr, "%s: illegal byte sequence in argument to -%c\n", progname, optc); exit(1); } return wc; } static struct chargap getcg(int optc, const char *ap, struct chargap dg) { struct chargap cg; int n; cg.c_u = 0; if (*ap && !isdigit(*ap)) { next(cg.c_c, ap, n); if (cg.c_c == WEOF) { fprintf(stderr, "%s: illegal byte sequence in argument to -%c\n", progname, optc); exit(1); } ap += n; cg.c_u |= 2; } else cg.c_c = dg.c_c; if (*ap == '\0' || (cg.c_g = atoi(ap)) <= 0) cg.c_g = dg.c_g; cg.c_u |= 1; return cg; } static void done(void) { printm(); if (tty) chmod(tty, mode); exit(status); } /*ARGSUSED*/ static void onintr(int signo) { printm(); if (tty) chmod(tty, mode); _exit(1); } static void fixtty(void) { struct stat sbuf; tty = ttyname(1); if (tty == 0) { close(pflg); pflg = -1; return; } stat(tty, &sbuf); mode = sbuf.st_mode&0777; chmod(tty, 0600); } static void print(const char *fp, const char **argp) { struct stat sbuf; register int sncol, i; register const char *sheader; char cbuf[100], linebuf[100]; wint_t c; curfile = fp ? fp : ""; if (ntflg) margin = 0; else margin = 10; if (length <= margin) { margin = 0; ntflg = 1; } if (width <= 0) width = 72; if (width <= numwidth || ncol*2>width) { fprintf(stderr, "%s: width too small\n", progname); status |= 1; done(); } if (mflg) { mopen(argp); ncol = nofile; } colw = (width-numwidth)/(ncol==0? 1 : ncol); sncol = ncol; sheader = header; plength = length-5; if (--ncol<0) ncol = 0; if (ntflg) plength = length; if (ncol) iflg.c_u |= 1, eflg.c_u |= 1; if (mflg || fp && fp[0] == '-' && fp[1] == '\0') fp = 0; oneof = 2; if (fp) { if((file=ib_open(fp, 0))==NULL) { delaym("%s: can't open %s\n", fp); ncol = sncol; header = sheader; return; } fstat(file->ib_fd, &sbuf); if (aflg) { ifile[0] = file; nofile = 1; } } else { if ((file=ib_alloc(dup(0), 0))==NULL) { delaym("%s: cannot open stdin\n", NULL); return; } time(&sbuf.st_mtime); } if (header == 0) header = fp?fp:""; strftime(cbuf, sizeof cbuf, "%b %e %H:%M %Y", localtime(&sbuf.st_mtime)); page = 1; for (i = 0; i= 0) { putc('\a', stderr); while (read(pflg, linebuf, 1) == 1 && *linebuf != '\n'); } if (mflg==0&&aflg==0) { colp[ncol]--; if (colp[ncol] < buffer) colp[ncol] = &buffer[BUFS]; } line = 0; if (ntflg==0) { putcs("\n\n"); putcs(cbuf); putcs(" "); putcs(header); snprintf(linebuf, sizeof linebuf, " Page %lld\n\n\n", page); putcs(linebuf); } c = putpage(); if (ntflg==0 || c==FF) { if (fflg) put(FF); else while(line=10) { fprintf(stderr, "%s: Too many args\n", progname); status |= 2; done(); } } } static wint_t putpage(void) { static long long cnt; long long ocnt; register int lastcol, i; register wint_t c = 0; register wint_t *cp; int j, k, l, xplength, content; if (ncol==0) { while (line 1 ? ib_getw(file, &c, &m) == NULL : (c = ib_get(file)) == (wint_t)EOF) { ib_close(file); if (oneof) delaym("%s: %s -- empty file\n", curfile); oneof = 1; return WEOF; } oneof = 0; } while (c == WEOF || c == 0); return c; } static wint_t tpgetc(int ai) { struct iblok *ip; register wint_t **p; wint_t c; register int i; int m; i = ai; if (mflg||aflg) { do { ip = aflg ? file : ifile[i]; if(isclosed[i] || ( mb_cur_max > 1 ? ib_getw(ip, &c, &m) == NULL : (c=ib_get(ip))==(wint_t)EOF)) { if (mflg&&isclosed[i]==0) { isclosed[i] = 1; if (--nofile <= 0) return(0); } else if (aflg) { nofile = 0; return(0); } if (nofile <= 0) return(0); return('\n'); } } while (c == WEOF || c == 0); if (c==FF && ncol>0) c = '\n'; return(c); } c = **(p = &colp[i]); if (c == WEOF || c == 0) { if (oneof == 1 || (c = readc()) == WEOF) return(c); /* For multi-column output, store at least three times the column width so that cc sequences remain complete. */ if (ncol==0 || scol[i]<=colw*3 || c=='\n') { **p = c; (*p)++; if (*p >= &buffer[BUFS]) { *p = buffer; if (ncol==0) *(*p)++ = c; } **p = WEOF; } } else { (*p)++; if (*p >= &buffer[BUFS]) *p = buffer; } if (c==FF && ncol>0) c = '\n'; return(c); } static wint_t pgetc(int ai) { register wint_t c; int i; i = aflg?0:ai; if (peek2c[ai]) { c = peek2c[ai]; peek2c[ai] = 0; return c; } else if (peekc[i]) { c = peekc[i]; peekc[i] = 0; } else { c = tpgetc(i); scol[i]++; } if (Fflg && icol[i] >= colw - (ncol != 0) && c != 0 && c != '\n' && c != WEOF) { peekc[i] = c; c = '\n'; } if (tabc) { if (c == '\n') scol[i] = 0; return(c); } if (eflg.c_u && c == eflg.c_c) { icol[i]++; if (icol[i] % eflg.c_g != 0) peekc[i] = eflg.c_c; return(' '); } else switch (c) { case '\n': scol[i] = 0; /*FALLTHRU*/ case '\r': icol[i] = 0; break; case 010: case 033: if (icol[i] > 0) icol[i]--; break; case '\t': icol[i]++; while (icol[i] & 07) icol[i]++; default: if (mb_cur_max > 1 && c & ~(wchar_t)0177) icol[i] += wcwidth(c); else if (isprint(c)) icol[i]++; } return(c); } static void put(wint_t ac) { register int ns; register wint_t c; c = ac; if (tabc) { putcp(c); if (c=='\n') line++; return; } switch (c) { case ' ': nspace++; col++; return; case '\n': line++; /*FALLTHRU*/ case '\r': col = 0; nspace = 0; break; case 010: case 033: if (--col<0) col = 0; if (--nspace<0) nspace = 0; } while(nspace) { if (iflg.c_u && nspace >= (ns=iflg.c_g-(col-nspace)%iflg.c_g) #ifdef SUS && (ns > 1 || nspace > 1) #endif /* SUS */ ) { nspace -= ns; putcp(iflg.c_c); } else { nspace--; putcp(' '); } } if (c == '\t') { col++; while (col & 07) col++; } else if (mb_cur_max > 1 && c & ~(wchar_t)0177) col += wcwidth(c); else if (isprint(c)) col++; putcp(c); } static void putcp(wint_t c) { if (page >= fpage) { if (mb_cur_max > 1 && c & ~(wchar_t)0177) { char mb[MB_LEN_MAX]; int i, n; n = wctomb(mb, c); for (i = 0; i < n; i++) putchar(mb[i]); } else putchar(c); } } static void putcs(const char *s) { wint_t c; int n; while (*s) { next(c, s, n); if (c != WEOF) put(c); s += n; } } static int putnum(long long n) { char buf[40], *bp; int i; i = col; snprintf(buf, sizeof buf, "%*lld", nflg.c_g, n); for (bp = buf; *bp; bp++) put(*bp); put(nflg.c_c); return col - i; } static int cnumwidth(void) { int i; if (nflg.c_u == 0 || ncol > 1 && mflg == 0) return 0; i = nflg.c_g; if (nflg.c_c == '\t') { i++; while (i & 07) i++; } else if (mb_cur_max > 1 && nflg.c_c & ~(wchar_t)0177) i += wcwidth(nflg.c_c); else if (i >= 040) i++; return i; } static struct message { struct message *m_nxt; const char *m_fmt; const char *m_arg; } *messages; static void delaym(const char *fmt, const char *arg) { struct message *mp, *mq; status |= 1; if (tty == NULL) { if (rflg == 0) fprintf(stderr, fmt, progname, arg); return; } if ((mp = calloc(1, sizeof *mp)) == NULL) { write(2, "pr: malloc failed\n", 18); exit(1); } mp->m_fmt = fmt; mp->m_arg = arg; if (messages) { for (mq = messages; mq->m_nxt; mq = mq->m_nxt); mq->m_nxt = mp; } else messages = mp; } static void printm(void) { struct message *mp; if (rflg == 0 && tty) for (mp = messages; mp; mp = mp->m_nxt) fprintf(stderr, mp->m_fmt, progname, mp->m_arg); }