add netbsd nl(1)
[rofl0r-hardcore-utils.git] / pr.c
blob3a937e3f0bdd351b88598a6de8769d8c27218629
1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (c) 1991 Keith Muller.
5 * Copyright (c) 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Keith Muller of the University of California, San Diego.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
41 #include <sys/types.h>
42 #include <sys/time.h>
43 #include <sys/stat.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <langinfo.h>
48 #include <locale.h>
49 #include <signal.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <time.h>
57 * parameter defaults
59 #define CLCNT 1
60 #define INCHAR '\t'
61 #define INGAP 8
62 #define OCHAR '\t'
63 #define OGAP 8
64 #define LINES 66
65 #define NMWD 5
66 #define NMCHAR '\t'
67 #define SCHAR '\t'
68 #define PGWD 72
69 #define SPGWD 512
72 * misc default values
74 #define HDFMT "%s %s Page %d\n\n\n"
75 #define HEADLEN 5
76 #define TAILLEN 5
77 #define TIMEFMTD "%e %b %H:%M %Y"
78 #define TIMEFMTM "%b %e %H:%M %Y"
79 #define FNAME ""
80 #define LBUF 8192
81 #define HDBUF 512
84 * structure for vertical columns. Used to balance cols on last page
86 struct vcol {
87 char *pt; /* ptr to col */
88 int cnt; /* char count */
93 * pr: a printing and pagination filter. If multiple input files
94 * are specified, each is read, formatted, and written to standard
95 * output. By default, input is separated into 66-line pages, each
96 * with a header that includes the page number, date, time and the
97 * files pathname.
99 * Complies with posix P1003.2/D11
103 * parameter variables
105 static int pgnm; /* starting page number */
106 static int clcnt; /* number of columns */
107 static int colwd; /* column data width - multiple columns */
108 static int across; /* mult col flag; write across page */
109 static int dspace; /* double space flag */
110 static char inchar; /* expand input char */
111 static int ingap; /* expand input gap */
112 static int pausefst; /* Pause before first page */
113 static int pauseall; /* Pause before each page */
114 static int formfeed; /* use formfeed as trailer */
115 static char *header; /* header name instead of file name */
116 static char ochar; /* contract output char */
117 static int ogap; /* contract output gap */
118 static int lines; /* number of lines per page */
119 static int merge; /* merge multiple files in output */
120 static char nmchar; /* line numbering append char */
121 static int nmwd; /* width of line number field */
122 static int offst; /* number of page offset spaces */
123 static int nodiag; /* do not report file open errors */
124 static char schar; /* text column separation character */
125 static int sflag; /* -s option for multiple columns */
126 static int nohead; /* do not write head and trailer */
127 static int pgwd; /* page width with multiple col output */
128 static char *timefrmt; /* time conversion string */
131 * misc globals
133 static FILE *err; /* error message file pointer */
134 static int addone; /* page length is odd with double space */
135 static int errcnt; /* error count on file processing */
136 static char digs[] = "0123456789"; /* page number translation map */
138 static char fnamedefault[] = FNAME;
140 /* forward decls for internal helper funcs */
141 static void mfail(void);
142 static void pfail(void);
143 static void usage(void);
144 static void flsh_errs(void);
145 static void terminate(int which_sig);
146 static int prtail(int cnt, int incomp);
147 static int setup(int argc, char *argv[]);
148 static int onecol(int argc, char *argv[]);
149 static int vertcol(int argc, char *argv[]);
150 static int horzcol(int argc, char *argv[]);
151 static int mulfile(int argc, char *argv[]);
152 static void addnum(char *buf, int wdth, int line);
153 static int inskip(FILE *inf, int pgcnt, int lncnt);
154 static int prhead(char *buf, const char *fname, int pagcnt);
155 static int inln(FILE *inf, char *buf, int lim, int *cps, int trnc, int *mor);
156 static int otln(char *buf, int cnt, int *svips, int *svops, int mor);
157 static FILE *nxtfile(int argc, char **argv, const char **fname, char *buf, int dt);
159 /* forward decls for egetopt */
160 extern int eopterr;
161 extern int eoptind;
162 extern int eoptopt;
163 extern char *eoptarg;
164 static int egetopt(int nargc, char * const *nargv, const char *ostr);
167 main(int argc, char *argv[])
169 int ret_val;
171 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
172 (void)signal(SIGINT, terminate);
173 ret_val = setup(argc, argv);
174 if (!ret_val) {
176 * select the output format based on options
178 if (merge)
179 ret_val = mulfile(argc, argv);
180 else if (clcnt == 1)
181 ret_val = onecol(argc, argv);
182 else if (across)
183 ret_val = horzcol(argc, argv);
184 else
185 ret_val = vertcol(argc, argv);
186 free(timefrmt);
187 } else
188 usage();
189 flsh_errs();
190 if (errcnt || ret_val)
191 exit(1);
192 return(0);
196 * Check if we should pause and write an alert character and wait for a
197 * carriage return on /dev/tty.
199 static void
200 ttypause(int pagecnt)
202 int pch;
203 FILE *ttyfp;
205 if ((pauseall || (pausefst && pagecnt == 1)) &&
206 isatty(STDOUT_FILENO)) {
207 if ((ttyfp = fopen("/dev/tty", "r")) != NULL) {
208 (void)putc('\a', stderr);
209 while ((pch = getc(ttyfp)) != '\n' && pch != EOF)
211 (void)fclose(ttyfp);
217 * onecol: print files with only one column of output.
218 * Line length is unlimited.
220 static int onecol(int argc, char *argv[])
222 int cnt = -1;
223 int off;
224 int lrgln;
225 int linecnt;
226 int num;
227 int lncnt;
228 int pagecnt;
229 int ips;
230 int ops;
231 int cps;
232 char *obuf;
233 char *lbuf;
234 char *nbuf;
235 char *hbuf;
236 char *ohbuf;
237 FILE *inf;
238 const char *fname;
239 int mor;
241 if (nmwd)
242 num = nmwd + 1;
243 else
244 num = 0;
245 off = num + offst;
248 * allocate line buffer
250 if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) {
251 mfail();
252 return(1);
255 * allocate header buffer
257 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
258 free(obuf);
259 mfail();
260 return(1);
263 ohbuf = hbuf + offst;
264 nbuf = obuf + offst;
265 lbuf = nbuf + num;
266 if (num)
267 nbuf[--num] = nmchar;
268 if (offst) {
269 (void)memset(obuf, (int)' ', offst);
270 (void)memset(hbuf, (int)' ', offst);
274 * loop by file
276 while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
277 if (pgnm) {
279 * skip to specified page
281 if (inskip(inf, pgnm, lines))
282 continue;
283 pagecnt = pgnm;
284 } else
285 pagecnt = 1;
286 lncnt = 0;
289 * loop by page
291 for(;;) {
292 linecnt = 0;
293 lrgln = 0;
294 ops = 0;
295 ips = 0;
296 cps = 0;
298 ttypause(pagecnt);
301 * loop by line
303 while (linecnt < lines) {
305 * input next line
307 if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0)
308 break;
309 if (!linecnt && !nohead &&
310 prhead(hbuf, fname, pagecnt))
311 goto err;
314 * start of new line.
316 if (!lrgln) {
317 if (num)
318 addnum(nbuf, num, ++lncnt);
319 if (otln(obuf,cnt+off, &ips, &ops, mor))
320 goto err;
321 } else if (otln(lbuf, cnt, &ips, &ops, mor))
322 goto err;
325 * if line bigger than buffer, get more
327 if (mor) {
328 lrgln = 1;
329 continue;
333 * whole line rcvd. reset tab proc. state
335 ++linecnt;
336 lrgln = 0;
337 ops = 0;
338 ips = 0;
342 * fill to end of page
344 if (linecnt && prtail(lines-linecnt-lrgln, lrgln))
345 goto err;
348 * On EOF go to next file
350 if (cnt < 0)
351 break;
352 ++pagecnt;
354 if (inf != stdin)
355 (void)fclose(inf);
357 if (eoptind < argc)
358 goto err;
359 free(hbuf);
360 free(obuf);
361 return(0);
362 err:
363 free(hbuf);
364 free(obuf);
365 return(1);
369 * vertcol: print files with more than one column of output down a page
371 static int vertcol(int argc, char *argv[])
373 char *ptbf;
374 char **lstdat = NULL;
375 int i;
376 int j;
377 int cnt = -1;
378 int pln;
379 int *indy = NULL;
380 int cvc;
381 int *lindy = NULL;
382 int lncnt;
383 int stp;
384 int pagecnt;
385 int col = colwd + 1;
386 int mxlen = pgwd + offst + 1;
387 int mclcnt = clcnt - 1;
388 struct vcol *vc = NULL;
389 int mvc;
390 int tvc;
391 int cw = nmwd + 1;
392 int fullcol;
393 char *buf = NULL;
394 char *hbuf = NULL;
395 char *ohbuf;
396 const char *fname;
397 FILE *inf;
398 int ips = 0;
399 int cps = 0;
400 int ops = 0;
401 int mor = 0;
402 int retval = 1;
405 * allocate page buffer
407 if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) {
408 mfail();
409 return(1);
413 * allocate page header
415 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
416 mfail();
417 goto out;
419 ohbuf = hbuf + offst;
420 if (offst)
421 (void)memset(hbuf, (int)' ', offst);
424 * col pointers when no headers
426 mvc = lines * clcnt;
427 if ((vc =
428 (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) {
429 mfail();
430 goto out;
434 * pointer into page where last data per line is located
436 if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){
437 mfail();
438 goto out;
442 * fast index lookups to locate start of lines
444 if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
445 mfail();
446 goto out;
448 if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
449 mfail();
450 goto out;
453 if (nmwd)
454 fullcol = col + cw;
455 else
456 fullcol = col;
459 * initialize buffer lookup indexes and offset area
461 for (j = 0; j < lines; ++j) {
462 lindy[j] = j * mxlen;
463 indy[j] = lindy[j] + offst;
464 if (offst) {
465 ptbf = buf + lindy[j];
466 (void)memset(ptbf, (int)' ', offst);
467 ptbf += offst;
468 } else
469 ptbf = buf + indy[j];
470 lstdat[j] = ptbf;
474 * loop by file
476 while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
477 if (pgnm) {
479 * skip to requested page
481 if (inskip(inf, pgnm, lines))
482 continue;
483 pagecnt = pgnm;
484 } else
485 pagecnt = 1;
486 lncnt = 0;
489 * loop by page
491 for(;;) {
492 ttypause(pagecnt);
495 * loop by column
497 cvc = 0;
498 for (i = 0; i < clcnt; ++i) {
499 j = 0;
501 * if last column, do not pad
503 if (i == mclcnt)
504 stp = 1;
505 else
506 stp = 0;
508 * loop by line
510 for(;;) {
512 * is this first column
514 if (!i) {
515 ptbf = buf + indy[j];
516 lstdat[j] = ptbf;
517 } else
518 ptbf = lstdat[j];
519 vc[cvc].pt = ptbf;
522 * add number
524 if (nmwd) {
525 addnum(ptbf, nmwd, ++lncnt);
526 ptbf += nmwd;
527 *ptbf++ = nmchar;
531 * input next line
533 cnt = inln(inf,ptbf,colwd,&cps,1,&mor);
534 vc[cvc++].cnt = cnt;
535 if (cnt < 0)
536 break;
537 ptbf += cnt;
540 * pad all but last column on page
542 if (!stp) {
544 * pad to end of column
546 if (sflag)
547 *ptbf++ = schar;
548 else if ((pln = col-cnt) > 0) {
549 (void)memset(ptbf,
550 (int)' ',pln);
551 ptbf += pln;
555 * remember last char in line
557 lstdat[j] = ptbf;
558 if (++j >= lines)
559 break;
561 if (cnt < 0)
562 break;
566 * when -t (no header) is specified the spec requires
567 * the min number of lines. The last page may not have
568 * balanced length columns. To fix this we must reorder
569 * the columns. This is a very slow technique so it is
570 * only used under limited conditions. Without -t, the
571 * balancing of text columns is unspecified. To NOT
572 * balance the last page, add the global variable
573 * nohead to the if statement below e.g.
575 * if ((cnt < 0) && nohead && cvc ......
577 --cvc;
580 * check to see if last page needs to be reordered
582 if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){
583 pln = cvc/clcnt;
584 if (cvc % clcnt)
585 ++pln;
588 * print header
590 if (!nohead && prhead(hbuf, fname, pagecnt))
591 goto out;
592 for (i = 0; i < pln; ++i) {
593 ips = 0;
594 ops = 0;
595 if (offst &&
596 otln(buf,offst,&ips,&ops,1))
597 goto out;
598 tvc = i;
600 for (j = 0; j < clcnt; ++j) {
602 * determine column length
604 if (j == mclcnt) {
606 * last column
608 cnt = vc[tvc].cnt;
609 if (nmwd)
610 cnt += cw;
611 } else if (sflag) {
613 * single ch between
615 cnt = vc[tvc].cnt + 1;
616 if (nmwd)
617 cnt += cw;
618 } else
619 cnt = fullcol;
620 if (otln(vc[tvc].pt, cnt, &ips,
621 &ops, 1))
622 goto out;
623 tvc += pln;
624 if (tvc >= cvc)
625 break;
628 * terminate line
630 if (otln(buf, 0, &ips, &ops, 0))
631 goto out;
634 * pad to end of page
636 if (prtail((lines - pln), 0))
637 goto out;
639 * done with output, go to next file
641 break;
645 * determine how many lines to output
647 if (i > 0)
648 pln = lines;
649 else
650 pln = j;
653 * print header
655 if (pln && !nohead && prhead(hbuf, fname, pagecnt))
656 goto out;
659 * output each line
661 for (i = 0; i < pln; ++i) {
662 ptbf = buf + lindy[i];
663 if ((j = lstdat[i] - ptbf) <= offst)
664 break;
665 if (otln(ptbf, j, &ips, &ops, 0))
666 goto out;
670 * pad to end of page
672 if (pln && prtail((lines - pln), 0))
673 goto out;
676 * if EOF go to next file
678 if (cnt < 0)
679 break;
680 ++pagecnt;
682 if (inf != stdin)
683 (void)fclose(inf);
685 if (eoptind < argc)
686 goto out;
687 retval = 0;
688 out:
689 free(lindy);
690 free(indy);
691 free(lstdat);
692 free(vc);
693 free(hbuf);
694 free(buf);
695 return(retval);
699 * horzcol: print files with more than one column of output across a page
701 static int horzcol(int argc, char *argv[])
703 char *ptbf;
704 int pln;
705 int cnt = -1;
706 char *lstdat;
707 int col = colwd + 1;
708 int j;
709 int i;
710 int lncnt;
711 int pagecnt;
712 char *buf;
713 char *hbuf;
714 char *ohbuf;
715 const char *fname;
716 FILE *inf;
717 int ips = 0;
718 int cps = 0;
719 int ops = 0;
720 int mor = 0;
722 if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
723 mfail();
724 return(1);
728 * page header
730 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
731 free(buf);
732 mfail();
733 return(1);
735 ohbuf = hbuf + offst;
736 if (offst) {
737 (void)memset(buf, (int)' ', offst);
738 (void)memset(hbuf, (int)' ', offst);
742 * loop by file
744 while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
745 if (pgnm) {
746 if (inskip(inf, pgnm, lines))
747 continue;
748 pagecnt = pgnm;
749 } else
750 pagecnt = 1;
751 lncnt = 0;
754 * loop by page
756 for(;;) {
757 ttypause(pagecnt);
760 * loop by line
762 for (i = 0; i < lines; ++i) {
763 ptbf = buf + offst;
764 lstdat = ptbf;
765 j = 0;
767 * loop by col
769 for(;;) {
770 if (nmwd) {
772 * add number to column
774 addnum(ptbf, nmwd, ++lncnt);
775 ptbf += nmwd;
776 *ptbf++ = nmchar;
779 * input line
781 if ((cnt = inln(inf,ptbf,colwd,&cps,1,
782 &mor)) < 0)
783 break;
784 ptbf += cnt;
785 lstdat = ptbf;
788 * if last line skip padding
790 if (++j >= clcnt)
791 break;
794 * pad to end of column
796 if (sflag)
797 *ptbf++ = schar;
798 else if ((pln = col - cnt) > 0) {
799 (void)memset(ptbf,(int)' ',pln);
800 ptbf += pln;
805 * determine line length
807 if ((j = lstdat - buf) <= offst)
808 break;
809 if (!i && !nohead &&
810 prhead(hbuf, fname, pagecnt))
811 goto err;
813 * output line
815 if (otln(buf, j, &ips, &ops, 0))
816 goto err;
820 * pad to end of page
822 if (i && prtail(lines-i, 0))
823 goto err;
826 * if EOF go to next file
828 if (cnt < 0)
829 break;
830 ++pagecnt;
832 if (inf != stdin)
833 (void)fclose(inf);
835 if (eoptind < argc)
836 goto err;
837 free(hbuf);
838 free(buf);
839 return(0);
840 err:
841 free(hbuf);
842 free(buf);
843 return(1);
847 * mulfile: print files with more than one column of output and
848 * more than one file concurrently
850 static int mulfile(int argc, char *argv[])
852 char *ptbf;
853 int j;
854 int pln;
855 int cnt;
856 char *lstdat;
857 int i;
858 FILE **fbuf = NULL;
859 int actf;
860 int lncnt;
861 int col;
862 int pagecnt;
863 int fproc;
864 char *buf = NULL;
865 char *hbuf = NULL;
866 char *ohbuf;
867 const char *fname;
868 int ips = 0;
869 int cps = 0;
870 int ops = 0;
871 int mor = 0;
872 int retval = 1;
875 * array of FILE *, one for each operand
877 if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) {
878 mfail();
879 goto out;
883 * page header
885 if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
886 mfail();
887 goto out;
889 ohbuf = hbuf + offst;
892 * do not know how many columns yet. The number of operands provide an
893 * upper bound on the number of columns. We use the number of files
894 * we can open successfully to set the number of columns. The operation
895 * of the merge operation (-m) in relation to unsuccessful file opens
896 * is unspecified by posix.
898 j = 0;
899 while (j < clcnt) {
900 if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL)
901 break;
902 if (pgnm && (inskip(fbuf[j], pgnm, lines)))
903 fbuf[j] = NULL;
904 ++j;
908 * if no files, exit
910 if (!j)
911 goto out;
914 * calculate page boundaries based on open file count
916 clcnt = j;
917 if (nmwd) {
918 colwd = (pgwd - clcnt - nmwd)/clcnt;
919 pgwd = ((colwd + 1) * clcnt) - nmwd - 2;
920 } else {
921 colwd = (pgwd + 1 - clcnt)/clcnt;
922 pgwd = ((colwd + 1) * clcnt) - 1;
924 if (colwd < 1) {
925 (void)fprintf(err,
926 "pr: page width too small for %d columns\n", clcnt);
927 goto out;
929 actf = clcnt;
930 col = colwd + 1;
933 * line buffer
935 if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
936 mfail();
937 goto out;
939 if (offst) {
940 (void)memset(buf, (int)' ', offst);
941 (void)memset(hbuf, (int)' ', offst);
943 if (pgnm)
944 pagecnt = pgnm;
945 else
946 pagecnt = 1;
947 lncnt = 0;
950 * continue to loop while any file still has data
952 while (actf > 0) {
953 ttypause(pagecnt);
956 * loop by line
958 for (i = 0; i < lines; ++i) {
959 ptbf = buf + offst;
960 lstdat = ptbf;
961 if (nmwd) {
963 * add line number to line
965 addnum(ptbf, nmwd, ++lncnt);
966 ptbf += nmwd;
967 *ptbf++ = nmchar;
969 j = 0;
970 fproc = 0;
973 * loop by column
975 for (j = 0; j < clcnt; ++j) {
976 if (fbuf[j] == NULL) {
978 * empty column; EOF
980 cnt = 0;
981 } else if ((cnt = inln(fbuf[j], ptbf, colwd,
982 &cps, 1, &mor)) < 0) {
984 * EOF hit; no data
986 if (fbuf[j] != stdin)
987 (void)fclose(fbuf[j]);
988 fbuf[j] = NULL;
989 --actf;
990 cnt = 0;
991 } else {
993 * process file data
995 ptbf += cnt;
996 lstdat = ptbf;
997 fproc++;
1001 * if last ACTIVE column, done with line
1003 if (fproc >= actf)
1004 break;
1007 * pad to end of column
1009 if (sflag) {
1010 *ptbf++ = schar;
1011 } else if ((pln = col - cnt) > 0) {
1012 (void)memset(ptbf, (int)' ', pln);
1013 ptbf += pln;
1018 * calculate data in line
1020 if ((j = lstdat - buf) <= offst)
1021 break;
1023 if (!i && !nohead && prhead(hbuf, fname, pagecnt))
1024 goto out;
1027 * output line
1029 if (otln(buf, j, &ips, &ops, 0))
1030 goto out;
1033 * if no more active files, done
1035 if (actf <= 0) {
1036 ++i;
1037 break;
1042 * pad to end of page
1044 if (i && prtail(lines-i, 0))
1045 goto out;
1046 ++pagecnt;
1048 if (eoptind < argc)
1049 goto out;
1050 retval = 0;
1051 out:
1052 free(buf);
1053 free(hbuf);
1054 free(fbuf);
1055 return(retval);
1059 * inln(): input a line of data (unlimited length lines supported)
1060 * Input is optionally expanded to spaces
1062 * inf: file
1063 * buf: buffer
1064 * lim: buffer length
1065 * cps: column position 1st char in buffer (large line support)
1066 * trnc: throw away data more than lim up to \n
1067 * mor: set if more data in line (not truncated)
1069 static int inln(FILE *inf, char *buf, int lim, int *cps, int trnc, int *mor)
1071 int col;
1072 int gap = ingap;
1073 int ch = EOF;
1074 char *ptbuf;
1075 int chk = (int)inchar;
1077 ptbuf = buf;
1079 if (gap) {
1081 * expanding input option
1083 while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
1085 * is this the input "tab" char
1087 if (ch == chk) {
1089 * expand to number of spaces
1091 col = (ptbuf - buf) + *cps;
1092 col = gap - (col % gap);
1095 * if more than this line, push back
1097 if ((col > lim) && (ungetc(ch, inf) == EOF))
1098 return(1);
1101 * expand to spaces
1103 while ((--col >= 0) && (--lim >= 0))
1104 *ptbuf++ = ' ';
1105 continue;
1107 if (ch == '\n')
1108 break;
1109 *ptbuf++ = ch;
1111 } else {
1113 * no expansion
1115 while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
1116 if (ch == '\n')
1117 break;
1118 *ptbuf++ = ch;
1121 col = ptbuf - buf;
1122 if (ch == EOF) {
1123 *mor = 0;
1124 *cps = 0;
1125 if (!col)
1126 return(-1);
1127 return(col);
1129 if (ch == '\n') {
1131 * entire line processed
1133 *mor = 0;
1134 *cps = 0;
1135 return(col);
1139 * line was larger than limit
1141 if (trnc) {
1143 * throw away rest of line
1145 while ((ch = getc(inf)) != EOF) {
1146 if (ch == '\n')
1147 break;
1149 *cps = 0;
1150 *mor = 0;
1151 } else {
1153 * save column offset if not truncated
1155 *cps += col;
1156 *mor = 1;
1159 return(col);
1163 * otln(): output a line of data. (Supports unlimited length lines)
1164 * output is optionally contracted to tabs
1166 * buf: output buffer with data
1167 * cnt: number of chars of valid data in buf
1168 * svips: buffer input column position (for large lines)
1169 * svops: buffer output column position (for large lines)
1170 * mor: output line not complete in this buf; more data to come.
1171 * 1 is more, 0 is complete, -1 is no \n's
1173 static int otln(char *buf, int cnt, int *svips, int *svops, int mor)
1175 int ops; /* last col output */
1176 int ips; /* last col in buf examined */
1177 int gap = ogap;
1178 int tbps;
1179 char *endbuf;
1181 if (ogap) {
1183 * contracting on output
1185 endbuf = buf + cnt;
1186 ops = *svops;
1187 ips = *svips;
1188 while (buf < endbuf) {
1190 * count number of spaces and ochar in buffer
1192 if (*buf == ' ') {
1193 ++ips;
1194 ++buf;
1195 continue;
1199 * simulate ochar processing
1201 if (*buf == ochar) {
1202 ips += gap - (ips % gap);
1203 ++buf;
1204 continue;
1208 * got a non space char; contract out spaces
1210 while (ips - ops > 1) {
1212 * use as many ochar as will fit
1214 if ((tbps = ops + gap - (ops % gap)) > ips)
1215 break;
1216 if (putchar(ochar) == EOF) {
1217 pfail();
1218 return(1);
1220 ops = tbps;
1223 while (ops < ips) {
1225 * finish off with spaces
1227 if (putchar(' ') == EOF) {
1228 pfail();
1229 return(1);
1231 ++ops;
1235 * output non space char
1237 if (putchar(*buf++) == EOF) {
1238 pfail();
1239 return(1);
1241 ++ips;
1242 ++ops;
1245 if (mor > 0) {
1247 * if incomplete line, save position counts
1249 *svops = ops;
1250 *svips = ips;
1251 return(0);
1254 if (mor < 0) {
1255 while (ips - ops > 1) {
1257 * use as many ochar as will fit
1259 if ((tbps = ops + gap - (ops % gap)) > ips)
1260 break;
1261 if (putchar(ochar) == EOF) {
1262 pfail();
1263 return(1);
1265 ops = tbps;
1267 while (ops < ips) {
1269 * finish off with spaces
1271 if (putchar(' ') == EOF) {
1272 pfail();
1273 return(1);
1275 ++ops;
1277 return(0);
1279 } else {
1281 * output is not contracted
1283 if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) {
1284 pfail();
1285 return(1);
1287 if (mor != 0)
1288 return(0);
1292 * process line end and double space as required
1294 if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) {
1295 pfail();
1296 return(1);
1298 return(0);
1302 * inskip(): skip over pgcnt pages with lncnt lines per page
1303 * file is closed at EOF (if not stdin).
1305 * inf FILE * to read from
1306 * pgcnt number of pages to skip
1307 * lncnt number of lines per page
1309 static int inskip(FILE *inf, int pgcnt, int lncnt)
1311 int c;
1312 int cnt;
1314 while(--pgcnt > 0) {
1315 cnt = lncnt;
1316 while ((c = getc(inf)) != EOF) {
1317 if ((c == '\n') && (--cnt == 0))
1318 break;
1320 if (c == EOF) {
1321 if (inf != stdin)
1322 (void)fclose(inf);
1323 return(1);
1326 return(0);
1330 * nxtfile: returns a FILE * to next file in arg list and sets the
1331 * time field for this file (or current date).
1333 * buf array to store proper date for the header.
1334 * dt if set skips the date processing (used with -m)
1336 static FILE *nxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
1338 FILE *inf = NULL;
1339 time_t tv_sec;
1340 struct tm *timeptr = NULL;
1341 struct stat statbuf;
1342 static int twice = -1;
1344 ++twice;
1345 if (eoptind >= argc) {
1347 * no file listed; default, use standard input
1349 if (twice)
1350 return(NULL);
1351 clearerr(stdin);
1352 inf = stdin;
1353 if (header != NULL)
1354 *fname = header;
1355 else
1356 *fname = fnamedefault;
1357 if (nohead)
1358 return(inf);
1359 if ((tv_sec = time(NULL)) == -1) {
1360 ++errcnt;
1361 (void)fprintf(err, "pr: cannot get time of day, %s\n",
1362 strerror(errno));
1363 eoptind = argc - 1;
1364 return(NULL);
1366 timeptr = localtime(&tv_sec);
1368 for (; eoptind < argc; ++eoptind) {
1369 if (strcmp(argv[eoptind], "-") == 0) {
1371 * process a "-" for filename
1373 clearerr(stdin);
1374 inf = stdin;
1375 if (header != NULL)
1376 *fname = header;
1377 else
1378 *fname = fnamedefault;
1379 ++eoptind;
1380 if (nohead || (dt && twice))
1381 return(inf);
1382 if ((tv_sec = time(NULL)) == -1) {
1383 ++errcnt;
1384 (void)fprintf(err,
1385 "pr: cannot get time of day, %s\n",
1386 strerror(errno));
1387 return(NULL);
1389 timeptr = localtime(&tv_sec);
1390 } else {
1392 * normal file processing
1394 if ((inf = fopen(argv[eoptind], "r")) == NULL) {
1395 ++errcnt;
1396 if (nodiag)
1397 continue;
1398 (void)fprintf(err, "pr: cannot open %s, %s\n",
1399 argv[eoptind], strerror(errno));
1400 continue;
1402 if (header != NULL)
1403 *fname = header;
1404 else if (dt)
1405 *fname = fnamedefault;
1406 else
1407 *fname = argv[eoptind];
1408 ++eoptind;
1409 if (nohead || (dt && twice))
1410 return(inf);
1412 if (dt) {
1413 if ((tv_sec = time(NULL)) == -1) {
1414 ++errcnt;
1415 (void)fprintf(err,
1416 "pr: cannot get time of day, %s\n",
1417 strerror(errno));
1418 fclose(inf);
1419 return(NULL);
1421 timeptr = localtime(&tv_sec);
1422 } else {
1423 if (fstat(fileno(inf), &statbuf) < 0) {
1424 ++errcnt;
1425 (void)fclose(inf);
1426 (void)fprintf(err,
1427 "pr: cannot stat %s, %s\n",
1428 argv[eoptind], strerror(errno));
1429 return(NULL);
1431 timeptr = localtime(&(statbuf.st_mtime));
1434 break;
1436 if (inf == NULL)
1437 return(NULL);
1440 * set up time field used in header
1442 if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) {
1443 ++errcnt;
1444 if (inf != stdin)
1445 (void)fclose(inf);
1446 (void)fputs("pr: time conversion failed\n", err);
1447 return(NULL);
1449 return(inf);
1453 * addnum(): adds the line number to the column
1454 * Truncates from the front or pads with spaces as required.
1455 * Numbers are right justified.
1457 * buf buffer to store the number
1458 * wdth width of buffer to fill
1459 * line line number
1461 * NOTE: numbers occupy part of the column. The posix
1462 * spec does not specify if -i processing should or should not
1463 * occur on number padding. The spec does say it occupies
1464 * part of the column. The usage of addnum currently treats
1465 * numbers as part of the column so spaces may be replaced.
1467 static void addnum(char *buf, int wdth, int line)
1469 char *pt = buf + wdth;
1471 do {
1472 *--pt = digs[line % 10];
1473 line /= 10;
1474 } while (line && (pt > buf));
1477 * pad with space as required
1479 while (pt > buf)
1480 *--pt = ' ';
1484 * prhead(): prints the top of page header
1486 * buf buffer with time field (and offset)
1487 * cnt number of chars in buf
1488 * fname fname field for header
1489 * pagcnt page number
1491 static int prhead(char *buf, const char *fname, int pagcnt)
1493 int ips = 0;
1494 int ops = 0;
1496 if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) {
1497 pfail();
1498 return(1);
1501 * posix is not clear if the header is subject to line length
1502 * restrictions. The specification for header line format
1503 * in the spec clearly does not limit length. No pr currently
1504 * restricts header length. However if we need to truncate in
1505 * a reasonable way, adjust the length of the printf by
1506 * changing HDFMT to allow a length max as an argument to printf.
1507 * buf (which contains the offset spaces and time field could
1508 * also be trimmed
1510 * note only the offset (if any) is processed for tab expansion
1512 if (offst && otln(buf, offst, &ips, &ops, -1))
1513 return(1);
1514 (void)printf(HDFMT,buf+offst, fname, pagcnt);
1515 return(0);
1519 * prtail(): pad page with empty lines (if required) and print page trailer
1520 * if requested
1522 * cnt number of lines of padding needed
1523 * incomp was a '\n' missing from last line output
1525 static int prtail(int cnt, int incomp)
1527 if (nohead) {
1529 * only pad with no headers when incomplete last line
1531 if (incomp &&
1532 ((dspace && (putchar('\n') == EOF)) ||
1533 (putchar('\n') == EOF))) {
1534 pfail();
1535 return(1);
1538 * but honor the formfeed request
1540 if (formfeed) {
1541 if (putchar('\f') == EOF) {
1542 pfail();
1543 return(1);
1546 return(0);
1549 * if double space output two \n
1551 if (dspace)
1552 cnt *= 2;
1555 * if an odd number of lines per page, add an extra \n
1557 if (addone)
1558 ++cnt;
1561 * pad page
1563 if (formfeed) {
1564 if ((incomp && (putchar('\n') == EOF)) ||
1565 (putchar('\f') == EOF)) {
1566 pfail();
1567 return(1);
1569 return(0);
1571 cnt += TAILLEN;
1572 while (--cnt >= 0) {
1573 if (putchar('\n') == EOF) {
1574 pfail();
1575 return(1);
1578 return(0);
1582 * terminate(): when a SIGINT is recvd
1584 static void terminate(int which_sig)
1586 (void) which_sig;
1587 flsh_errs();
1588 exit(1);
1593 * flsh_errs(): output saved up diagnostic messages after all normal
1594 * processing has completed
1596 static void flsh_errs(void)
1598 char buf[BUFSIZ];
1600 (void)fflush(stdout);
1601 (void)fflush(err);
1602 if (err == stderr)
1603 return;
1604 rewind(err);
1605 while (fgets(buf, BUFSIZ, err) != NULL)
1606 (void)fputs(buf, stderr);
1609 static void mfail(void)
1611 (void)fputs("pr: memory allocation failed\n", err);
1614 static void pfail(void)
1616 (void)fprintf(err, "pr: write failure, %s\n", strerror(errno));
1619 static void usage(void)
1621 (void)fputs(
1622 "usage: pr [+page] [-col] [-adFfmprt] [-e[ch][gap]] [-h header]\n",
1623 err);
1624 (void)fputs(
1625 " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err);
1626 (void)fputs(
1627 " [-L locale] [-s[ch]] [-w width] [-] [file ...]\n", err);
1631 * setup: Validate command args, initialize and perform sanity
1632 * checks on options
1634 static int setup(int argc, char *argv[])
1636 int c;
1637 int d_first;
1638 int eflag = 0;
1639 int iflag = 0;
1640 int wflag = 0;
1641 int cflag = 0;
1642 char *Lflag = NULL;
1644 if (isatty(fileno(stdout))) {
1646 * defer diagnostics until processing is done
1648 if ((err = tmpfile()) == NULL) {
1649 err = stderr;
1650 (void)fputs("Cannot defer diagnostic messages\n",stderr);
1651 return(1);
1653 } else
1654 err = stderr;
1655 while ((c = egetopt(argc, argv, "#adFfmrte?h:i?L:l:n?o:ps?w:")) != -1) {
1656 switch (c) {
1657 case '+':
1658 if ((pgnm = atoi(eoptarg)) < 1) {
1659 (void)fputs("pr: +page number must be 1 or more\n",
1660 err);
1661 return(1);
1663 break;
1664 case '-':
1665 if ((clcnt = atoi(eoptarg)) < 1) {
1666 (void)fputs("pr: -columns must be 1 or more\n",err);
1667 return(1);
1669 if (clcnt > 1)
1670 ++cflag;
1671 break;
1672 case 'a':
1673 ++across;
1674 break;
1675 case 'd':
1676 ++dspace;
1677 break;
1678 case 'e':
1679 ++eflag;
1680 if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
1681 inchar = *eoptarg++;
1682 else
1683 inchar = INCHAR;
1684 if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
1685 if ((ingap = atoi(eoptarg)) < 0) {
1686 (void)fputs(
1687 "pr: -e gap must be 0 or more\n", err);
1688 return(1);
1690 if (ingap == 0)
1691 ingap = INGAP;
1692 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1693 (void)fprintf(err,
1694 "pr: invalid value for -e %s\n", eoptarg);
1695 return(1);
1696 } else
1697 ingap = INGAP;
1698 break;
1699 case 'f':
1700 ++pausefst;
1701 /*FALLTHROUGH*/
1702 case 'F':
1703 ++formfeed;
1704 break;
1705 case 'h':
1706 header = eoptarg;
1707 break;
1708 case 'i':
1709 ++iflag;
1710 if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
1711 ochar = *eoptarg++;
1712 else
1713 ochar = OCHAR;
1714 if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
1715 if ((ogap = atoi(eoptarg)) < 0) {
1716 (void)fputs(
1717 "pr: -i gap must be 0 or more\n", err);
1718 return(1);
1720 if (ogap == 0)
1721 ogap = OGAP;
1722 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1723 (void)fprintf(err,
1724 "pr: invalid value for -i %s\n", eoptarg);
1725 return(1);
1726 } else
1727 ogap = OGAP;
1728 break;
1729 case 'L':
1730 Lflag = eoptarg;
1731 break;
1732 case 'l':
1733 if (!isdigit((unsigned char)*eoptarg) || ((lines=atoi(eoptarg)) < 1)) {
1734 (void)fputs(
1735 "pr: number of lines must be 1 or more\n",err);
1736 return(1);
1738 break;
1739 case 'm':
1740 ++merge;
1741 break;
1742 case 'n':
1743 if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
1744 nmchar = *eoptarg++;
1745 else
1746 nmchar = NMCHAR;
1747 if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
1748 if ((nmwd = atoi(eoptarg)) < 1) {
1749 (void)fputs(
1750 "pr: -n width must be 1 or more\n",err);
1751 return(1);
1753 } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
1754 (void)fprintf(err,
1755 "pr: invalid value for -n %s\n", eoptarg);
1756 return(1);
1757 } else
1758 nmwd = NMWD;
1759 break;
1760 case 'o':
1761 if (!isdigit((unsigned char)*eoptarg) || ((offst = atoi(eoptarg))< 1)){
1762 (void)fputs("pr: -o offset must be 1 or more\n",
1763 err);
1764 return(1);
1766 break;
1767 case 'p':
1768 ++pauseall;
1769 break;
1770 case 'r':
1771 ++nodiag;
1772 break;
1773 case 's':
1774 ++sflag;
1775 if (eoptarg == NULL)
1776 schar = SCHAR;
1777 else {
1778 schar = *eoptarg++;
1779 if (*eoptarg != '\0') {
1780 (void)fprintf(err,
1781 "pr: invalid value for -s %s\n",
1782 eoptarg);
1783 return(1);
1786 break;
1787 case 't':
1788 ++nohead;
1789 break;
1790 case 'w':
1791 ++wflag;
1792 if ((eoptarg == NULL ) ||
1793 !isdigit((unsigned char)*eoptarg) ||
1794 ((pgwd = atoi(eoptarg)) < 1)){
1795 (void)fputs(
1796 "pr: -w width must be 1 or more \n",err);
1797 return(1);
1799 break;
1800 case '?':
1801 default:
1802 return(1);
1807 * default and sanity checks
1809 if (!clcnt) {
1810 if (merge) {
1811 if ((clcnt = argc - eoptind) <= 1) {
1812 clcnt = CLCNT;
1813 merge = 0;
1815 } else
1816 clcnt = CLCNT;
1818 if (across) {
1819 if (clcnt == 1) {
1820 (void)fputs("pr: -a flag requires multiple columns\n",
1821 err);
1822 return(1);
1824 if (merge) {
1825 (void)fputs("pr: -m cannot be used with -a\n", err);
1826 return(1);
1829 if (!wflag) {
1830 if (sflag)
1831 pgwd = SPGWD;
1832 else
1833 pgwd = PGWD;
1835 if (cflag || merge) {
1836 if (!eflag) {
1837 inchar = INCHAR;
1838 ingap = INGAP;
1840 if (!iflag) {
1841 ochar = OCHAR;
1842 ogap = OGAP;
1845 if (cflag) {
1846 if (merge) {
1847 (void)fputs(
1848 "pr: -m cannot be used with multiple columns\n", err);
1849 return(1);
1851 if (nmwd) {
1852 colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt;
1853 pgwd = ((colwd + nmwd + 2) * clcnt) - 1;
1854 } else {
1855 colwd = (pgwd + 1 - clcnt)/clcnt;
1856 pgwd = ((colwd + 1) * clcnt) - 1;
1858 if (colwd < 1) {
1859 (void)fprintf(err,
1860 "pr: page width is too small for %d columns\n",clcnt);
1861 return(1);
1864 if (!lines)
1865 lines = LINES;
1868 * make sure long enough for headers. if not disable
1870 if (lines <= HEADLEN + TAILLEN)
1871 ++nohead;
1872 else if (!nohead)
1873 lines -= HEADLEN + TAILLEN;
1876 * adjust for double space on odd length pages
1878 if (dspace) {
1879 if (lines == 1)
1880 dspace = 0;
1881 else {
1882 if (lines & 1)
1883 ++addone;
1884 lines /= 2;
1888 (void) setlocale(LC_TIME, (Lflag != NULL) ? Lflag : "");
1890 #if 0 /* FIXME : figure out how to do this portably */
1891 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
1892 timefrmt = strdup(d_first ? TIMEFMTD : TIMEFMTM);
1893 #else
1894 timefrmt = strdup(TIMEFMTM);
1895 #endif
1896 return(0);
1899 /* embedded contents of egetopt.c START */
1901 int eopterr = 1; /* if error message should be printed */
1902 int eoptind = 1; /* index into parent argv vector */
1903 int eoptopt; /* character checked for validity */
1904 char *eoptarg; /* argument associated with option */
1906 #define BADCH (int)'?'
1908 static char emsg[] = "";
1910 static int egetopt(int nargc, char * const *nargv, const char *ostr)
1912 static char *place = emsg; /* option letter processing */
1913 char *oli; /* option letter list index */
1914 static int delim; /* which option delimiter */
1915 char *p;
1916 static char savec = '\0';
1918 if (savec != '\0') {
1919 *place = savec;
1920 savec = '\0';
1923 if (!*place) {
1925 * update scanning pointer
1927 if ((eoptind >= nargc) ||
1928 ((*(place = nargv[eoptind]) != '-') && (*place != '+'))) {
1929 place = emsg;
1930 return (-1);
1933 delim = (int)*place;
1934 if (place[1] && *++place == '-' && !place[1]) {
1936 * found "--"
1938 ++eoptind;
1939 place = emsg;
1940 return (-1);
1945 * check option letter
1947 if ((eoptopt = (int)*place++) == (int)':' || (eoptopt == (int)'?') ||
1948 !(oli = strchr(ostr, eoptopt))) {
1950 * if the user didn't specify '-' as an option,
1951 * assume it means -1 when by itself.
1953 if ((eoptopt == (int)'-') && !*place)
1954 return (-1);
1955 if (strchr(ostr, '#') && (isdigit(eoptopt) ||
1956 (((eoptopt == (int)'-') || (eoptopt == (int)'+')) &&
1957 isdigit(*place)))) {
1959 * # option: +/- with a number is ok
1961 for (p = place; *p != '\0'; ++p) {
1962 if (!isdigit(*p))
1963 break;
1965 eoptarg = place-1;
1967 if (*p == '\0') {
1968 place = emsg;
1969 ++eoptind;
1970 } else {
1971 place = p;
1972 savec = *p;
1973 *place = '\0';
1975 return (delim);
1978 if (!*place)
1979 ++eoptind;
1980 if (eopterr) {
1981 if (!(p = strrchr(*nargv, '/')))
1982 p = *nargv;
1983 else
1984 ++p;
1985 (void)fprintf(stderr, "%s: illegal option -- %c\n",
1986 p, eoptopt);
1988 return (BADCH);
1990 if (delim == (int)'+') {
1992 * '+' is only allowed with numbers
1994 if (!*place)
1995 ++eoptind;
1996 if (eopterr) {
1997 if (!(p = strrchr(*nargv, '/')))
1998 p = *nargv;
1999 else
2000 ++p;
2001 (void)fprintf(stderr,
2002 "%s: illegal '+' delimiter with option -- %c\n",
2003 p, eoptopt);
2005 return (BADCH);
2007 ++oli;
2008 if ((*oli != ':') && (*oli != '?')) {
2010 * don't need argument
2012 eoptarg = NULL;
2013 if (!*place)
2014 ++eoptind;
2015 return (eoptopt);
2018 if (*place) {
2020 * no white space
2022 eoptarg = place;
2023 } else if (*oli == '?') {
2025 * no arg, but NOT required
2027 eoptarg = NULL;
2028 } else if (nargc <= ++eoptind) {
2030 * no arg, but IS required
2032 place = emsg;
2033 if (eopterr) {
2034 if (!(p = strrchr(*nargv, '/')))
2035 p = *nargv;
2036 else
2037 ++p;
2038 (void)fprintf(stderr,
2039 "%s: option requires an argument -- %c\n", p,
2040 eoptopt);
2042 return (BADCH);
2043 } else {
2045 * arg has white space
2047 eoptarg = nargv[eoptind];
2049 place = emsg;
2050 ++eoptind;
2051 return (eoptopt);
2054 /* embedded contents of egetopt.c END */