Annotation of src/usr.bin/lam/lam.c, Revision 1.23
1.23 ! jmc 1: /* $OpenBSD: lam.c,v 1.22 2018/07/29 11:27:14 schwarze Exp $ */
1.1 deraadt 2: /* $NetBSD: lam.c,v 1.2 1994/11/14 20:27:42 jtc Exp $ */
3:
4: /*-
5: * Copyright (c) 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.8 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * lam - laminate files
35: * Author: John Kunze, UCB
36: */
37:
1.17 deraadt 38: #include <sys/param.h> /* NOFILE_MAX */
1.13 ray 39:
1.11 millert 40: #include <ctype.h>
41: #include <err.h>
1.22 schwarze 42: #include <locale.h>
1.1 deraadt 43: #include <stdio.h>
44: #include <stdlib.h>
45: #include <string.h>
1.15 millert 46: #include <unistd.h>
1.1 deraadt 47:
48: #define BIGBUFSIZ 5 * BUFSIZ
49:
50: struct openfile { /* open file structure */
51: FILE *fp; /* file pointer */
1.22 schwarze 52: int minwidth; /* pad this column to this width */
53: int maxwidth; /* truncate this column */
1.1 deraadt 54: short eof; /* eof flag */
55: short pad; /* pad flag for missing columns */
56: char eol; /* end of line character */
1.22 schwarze 57: char align; /* '0' for zero fill, '-' for left align */
1.1 deraadt 58: char *sepstring; /* string to print before each line */
1.13 ray 59: } input[NOFILE_MAX + 1]; /* last one is for the last -s arg. */
60: #define INPUTSIZE sizeof(input) / sizeof(*input)
1.1 deraadt 61:
1.13 ray 62: int numfiles; /* number of open files */
1.1 deraadt 63: int nofinalnl; /* normally append \n to each output line */
64: char line[BIGBUFSIZ];
65: char *linep;
66:
1.22 schwarze 67: int mbswidth_truncate(char *, int); /* utf8.c */
68:
1.11 millert 69: void usage(void);
1.4 millert 70: char *gatherline(struct openfile *);
1.11 millert 71: void getargs(int, char *[]);
1.4 millert 72: char *pad(struct openfile *);
1.1 deraadt 73:
74: int
1.9 deraadt 75: main(int argc, char *argv[])
1.1 deraadt 76: {
1.13 ray 77: int i;
1.18 deraadt 78:
1.22 schwarze 79: setlocale(LC_CTYPE, "");
80:
1.19 deraadt 81: if (pledge("stdio rpath", NULL) == -1)
82: err(1, "pledge");
1.1 deraadt 83:
1.13 ray 84: /* Process arguments, set numfiles to file argument count. */
1.11 millert 85: getargs(argc, argv);
1.13 ray 86: if (numfiles == 0)
1.11 millert 87: usage();
1.21 schwarze 88:
89: if (pledge("stdio", NULL) == -1)
90: err(1, "pledge");
91:
1.13 ray 92: /* Concatenate lines from each file, then print. */
1.1 deraadt 93: for (;;) {
94: linep = line;
1.13 ray 95: /*
96: * For each file that has a line to print, numfile is
97: * incremented. Thus if numfiles is 0, we are done.
98: */
99: numfiles = 0;
100: for (i = 0; i < INPUTSIZE - 1 && input[i].fp != NULL; i++)
101: linep = gatherline(&input[i]);
102: if (numfiles == 0)
1.1 deraadt 103: exit(0);
104: fputs(line, stdout);
1.13 ray 105: /* Print terminating -s argument. */
106: fputs(input[i].sepstring, stdout);
1.1 deraadt 107: if (!nofinalnl)
108: putchar('\n');
109: }
110: }
111:
112: void
1.11 millert 113: getargs(int argc, char *argv[])
1.1 deraadt 114: {
1.11 millert 115: struct openfile *ip = input;
1.22 schwarze 116: const char *errstr;
117: char *p, *q;
1.11 millert 118: int ch, P, S, F, T;
1.1 deraadt 119:
120: P = S = F = T = 0; /* capitalized options */
1.11 millert 121: while (optind < argc) {
122: switch (ch = getopt(argc, argv, "F:f:P:p:S:s:T:t:")) {
1.20 schwarze 123: case 'P': case 'p':
124: P = (ch == 'P');
125: ip->pad = 1;
126: /* FALLTHROUGH */
1.11 millert 127: case 'F': case 'f':
128: F = (ch == 'F');
129: /* Validate format string argument. */
1.22 schwarze 130: p = optarg;
131: if (*p == '0' || *p == '-')
132: ip->align = *p++;
133: else
134: ip->align = ' ';
135: if ((q = strchr(p, '.')) != NULL)
136: *q++ = '\0';
137: if (*p != '\0') {
138: ip->minwidth = strtonum(p, 1, INT_MAX,
139: &errstr);
140: if (errstr != NULL)
141: errx(1, "minimum width is %s: %s",
142: errstr, p);
143: }
144: if (q != NULL) {
145: ip->maxwidth = strtonum(q, 1, INT_MAX,
146: &errstr);
147: if (errstr != NULL)
148: errx(1, "maximum width is %s: %s",
149: errstr, q);
150: } else
151: ip->maxwidth = INT_MAX;
1.11 millert 152: break;
153: case 'S': case 's':
154: S = (ch == 'S');
155: ip->sepstring = optarg;
156: break;
157: case 'T': case 't':
158: T = (ch == 'T');
159: if (strlen(optarg) != 1)
160: usage();
161: ip->eol = optarg[0];
162: nofinalnl = 1;
163: break;
164: case -1:
165: if (optind >= argc)
166: break; /* to support "--" */
1.13 ray 167: /* This is a file, not a flag. */
168: ++numfiles;
169: if (numfiles >= INPUTSIZE)
170: errx(1, "too many files");
1.11 millert 171: if (strcmp(argv[optind], "-") == 0)
1.1 deraadt 172: ip->fp = stdin;
1.11 millert 173: else if ((ip->fp = fopen(argv[optind], "r")) == NULL)
174: err(1, "%s", argv[optind]);
1.1 deraadt 175: ip->pad = P;
1.11 millert 176: if (ip->sepstring == NULL)
177: ip->sepstring = S ? (ip-1)->sepstring : "";
178: if (ip->eol == '\0')
179: ip->eol = T ? (ip-1)->eol : '\n';
1.22 schwarze 180: if (ip->align == '\0') {
181: if (F || P) {
182: ip->align = (ip-1)->align;
183: ip->minwidth = (ip-1)->minwidth;
184: ip->maxwidth = (ip-1)->maxwidth;
185: } else
186: ip->maxwidth = INT_MAX;
187: }
1.1 deraadt 188: ip++;
1.11 millert 189: optind++;
1.1 deraadt 190: break;
191: default:
1.11 millert 192: usage();
193: /* NOTREACHED */
1.1 deraadt 194: }
195: }
196: ip->fp = NULL;
1.11 millert 197: if (ip->sepstring == NULL)
1.1 deraadt 198: ip->sepstring = "";
199: }
200:
201: char *
1.9 deraadt 202: pad(struct openfile *ip)
1.1 deraadt 203: {
1.7 millert 204: size_t n;
1.3 mpech 205: char *lp = linep;
1.22 schwarze 206: int i = 0;
1.1 deraadt 207:
1.7 millert 208: n = strlcpy(lp, ip->sepstring, line + sizeof(line) - lp);
209: lp += (n < line + sizeof(line) - lp) ? n : strlen(lp);
1.22 schwarze 210: if (ip->pad)
211: while (i++ < ip->minwidth && lp + 1 < line + sizeof(line))
212: *lp++ = ' ';
213: *lp = '\0';
1.1 deraadt 214: return (lp);
215: }
216:
1.13 ray 217: /*
218: * Grab line from file, appending to linep. Increments numfiles if file
219: * is still open.
220: */
1.1 deraadt 221: char *
1.9 deraadt 222: gatherline(struct openfile *ip)
1.1 deraadt 223: {
1.7 millert 224: size_t n;
1.1 deraadt 225: char s[BUFSIZ];
1.3 mpech 226: char *p;
227: char *lp = linep;
1.11 millert 228: char *end = s + BUFSIZ - 1;
1.22 schwarze 229: int c, width;
1.1 deraadt 230:
231: if (ip->eof)
232: return (pad(ip));
233: for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++)
234: if ((*p = c) == ip->eol)
235: break;
236: *p = '\0';
237: if (c == EOF) {
238: ip->eof = 1;
239: if (ip->fp == stdin)
240: fclose(stdin);
241: return (pad(ip));
242: }
1.13 ray 243: /* Something will be printed. */
244: numfiles++;
1.7 millert 245: n = strlcpy(lp, ip->sepstring, line + sizeof(line) - lp);
246: lp += (n < line + sizeof(line) - lp) ? n : strlen(lp);
1.22 schwarze 247: width = mbswidth_truncate(s, ip->maxwidth);
248: if (ip->align != '-')
249: while (width++ < ip->minwidth && lp + 1 < line + sizeof(line))
250: *lp++ = ip->align;
251: n = strlcpy(lp, s, line + sizeof(line) - lp);
252: lp += (n < line + sizeof(line) - lp) ? n : strlen(lp);
253: if (ip->align == '-')
254: while (width++ < ip->minwidth && lp + 1 < line + sizeof(line))
255: *lp++ = ' ';
256: *lp = '\0';
1.1 deraadt 257: return (lp);
258: }
259:
260: void
1.11 millert 261: usage(void)
1.1 deraadt 262: {
1.10 mickey 263: extern char *__progname;
1.11 millert 264:
1.1 deraadt 265: fprintf(stderr,
1.23 ! jmc 266: "usage: %s [-F|f min.max] [-P|p min.max] [-S|s sepstring] [-T|t c] file ...\n",
1.10 mickey 267: __progname);
1.1 deraadt 268: exit(1);
269: }