Annotation of src/usr.bin/lam/lam.c, Revision 1.21
1.20 schwarze 1: /* $OpenBSD: lam.c,v 1.19 2015/10/09 01:37:08 deraadt 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.1 deraadt 42: #include <stdio.h>
43: #include <stdlib.h>
44: #include <string.h>
1.15 millert 45: #include <unistd.h>
1.1 deraadt 46:
47: #define BIGBUFSIZ 5 * BUFSIZ
48:
49: struct openfile { /* open file structure */
50: FILE *fp; /* file pointer */
51: short eof; /* eof flag */
52: short pad; /* pad flag for missing columns */
53: char eol; /* end of line character */
54: char *sepstring; /* string to print before each line */
55: char *format; /* printf(3) style string spec. */
1.13 ray 56: } input[NOFILE_MAX + 1]; /* last one is for the last -s arg. */
57: #define INPUTSIZE sizeof(input) / sizeof(*input)
1.1 deraadt 58:
1.13 ray 59: int numfiles; /* number of open files */
1.1 deraadt 60: int nofinalnl; /* normally append \n to each output line */
61: char line[BIGBUFSIZ];
62: char *linep;
63:
1.11 millert 64: void usage(void);
1.4 millert 65: char *gatherline(struct openfile *);
1.11 millert 66: void getargs(int, char *[]);
1.4 millert 67: char *pad(struct openfile *);
1.1 deraadt 68:
69: int
1.9 deraadt 70: main(int argc, char *argv[])
1.1 deraadt 71: {
1.13 ray 72: int i;
1.18 deraadt 73:
1.19 deraadt 74: if (pledge("stdio rpath", NULL) == -1)
75: err(1, "pledge");
1.1 deraadt 76:
1.13 ray 77: /* Process arguments, set numfiles to file argument count. */
1.11 millert 78: getargs(argc, argv);
1.13 ray 79: if (numfiles == 0)
1.11 millert 80: usage();
1.21 ! schwarze 81:
! 82: if (pledge("stdio", NULL) == -1)
! 83: err(1, "pledge");
! 84:
1.13 ray 85: /* Concatenate lines from each file, then print. */
1.1 deraadt 86: for (;;) {
87: linep = line;
1.13 ray 88: /*
89: * For each file that has a line to print, numfile is
90: * incremented. Thus if numfiles is 0, we are done.
91: */
92: numfiles = 0;
93: for (i = 0; i < INPUTSIZE - 1 && input[i].fp != NULL; i++)
94: linep = gatherline(&input[i]);
95: if (numfiles == 0)
1.1 deraadt 96: exit(0);
97: fputs(line, stdout);
1.13 ray 98: /* Print terminating -s argument. */
99: fputs(input[i].sepstring, stdout);
1.1 deraadt 100: if (!nofinalnl)
101: putchar('\n');
102: }
103: }
104:
105: void
1.11 millert 106: getargs(int argc, char *argv[])
1.1 deraadt 107: {
1.11 millert 108: struct openfile *ip = input;
1.3 mpech 109: char *p;
1.11 millert 110: int ch, P, S, F, T;
111: size_t siz;
1.1 deraadt 112:
113: P = S = F = T = 0; /* capitalized options */
1.11 millert 114: while (optind < argc) {
115: switch (ch = getopt(argc, argv, "F:f:P:p:S:s:T:t:")) {
1.20 schwarze 116: case 'P': case 'p':
117: P = (ch == 'P');
118: ip->pad = 1;
119: /* FALLTHROUGH */
1.11 millert 120: case 'F': case 'f':
121: F = (ch == 'F');
122: /* Validate format string argument. */
123: for (p = optarg; *p != '\0'; p++)
1.16 deraadt 124: if (!isdigit((unsigned char)*p) &&
125: *p != '.' && *p != '-')
1.11 millert 126: errx(1, "%s: invalid width specified",
127: optarg);
128: /* '%' + width + 's' + '\0' */
129: siz = p - optarg + 3;
130: if ((p = realloc(ip->format, siz)) == NULL)
131: err(1, NULL);
132: snprintf(p, siz, "%%%ss", optarg);
133: ip->format = p;
134: break;
135: case 'S': case 's':
136: S = (ch == 'S');
137: ip->sepstring = optarg;
138: break;
139: case 'T': case 't':
140: T = (ch == 'T');
141: if (strlen(optarg) != 1)
142: usage();
143: ip->eol = optarg[0];
144: nofinalnl = 1;
145: break;
146: case -1:
147: if (optind >= argc)
148: break; /* to support "--" */
1.13 ray 149: /* This is a file, not a flag. */
150: ++numfiles;
151: if (numfiles >= INPUTSIZE)
152: errx(1, "too many files");
1.11 millert 153: if (strcmp(argv[optind], "-") == 0)
1.1 deraadt 154: ip->fp = stdin;
1.11 millert 155: else if ((ip->fp = fopen(argv[optind], "r")) == NULL)
156: err(1, "%s", argv[optind]);
1.1 deraadt 157: ip->pad = P;
1.11 millert 158: if (ip->sepstring == NULL)
159: ip->sepstring = S ? (ip-1)->sepstring : "";
160: if (ip->format == NULL)
161: ip->format = (P || F) ? (ip-1)->format : "%s";
162: if (ip->eol == '\0')
163: ip->eol = T ? (ip-1)->eol : '\n';
1.1 deraadt 164: ip++;
1.11 millert 165: optind++;
1.1 deraadt 166: break;
167: default:
1.11 millert 168: usage();
169: /* NOTREACHED */
1.1 deraadt 170: }
171: }
172: ip->fp = NULL;
1.11 millert 173: if (ip->sepstring == NULL)
1.1 deraadt 174: ip->sepstring = "";
175: }
176:
177: char *
1.9 deraadt 178: pad(struct openfile *ip)
1.1 deraadt 179: {
1.7 millert 180: size_t n;
1.3 mpech 181: char *lp = linep;
1.1 deraadt 182:
1.7 millert 183: n = strlcpy(lp, ip->sepstring, line + sizeof(line) - lp);
184: lp += (n < line + sizeof(line) - lp) ? n : strlen(lp);
1.1 deraadt 185: if (ip->pad) {
1.7 millert 186: n = snprintf(lp, line + sizeof(line) - lp, ip->format, "");
1.12 deraadt 187: if (n > 0)
188: lp += (n < line + sizeof(line) - lp) ? n : strlen(lp);
1.1 deraadt 189: }
190: return (lp);
191: }
192:
1.13 ray 193: /*
194: * Grab line from file, appending to linep. Increments numfiles if file
195: * is still open.
196: */
1.1 deraadt 197: char *
1.9 deraadt 198: gatherline(struct openfile *ip)
1.1 deraadt 199: {
1.7 millert 200: size_t n;
1.1 deraadt 201: char s[BUFSIZ];
1.3 mpech 202: char *p;
203: char *lp = linep;
1.11 millert 204: char *end = s + BUFSIZ - 1;
1.7 millert 205: int c;
1.1 deraadt 206:
207: if (ip->eof)
208: return (pad(ip));
209: for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++)
210: if ((*p = c) == ip->eol)
211: break;
212: *p = '\0';
213: if (c == EOF) {
214: ip->eof = 1;
215: if (ip->fp == stdin)
216: fclose(stdin);
217: return (pad(ip));
218: }
1.13 ray 219: /* Something will be printed. */
220: numfiles++;
1.7 millert 221: n = strlcpy(lp, ip->sepstring, line + sizeof(line) - lp);
222: lp += (n < line + sizeof(line) - lp) ? n : strlen(lp);
1.11 millert 223: n = snprintf(lp, line + sizeof(line) - lp, ip->format, s);
1.12 deraadt 224: if (n > 0)
225: lp += (n < line + sizeof(line) - lp) ? n : strlen(lp);
1.1 deraadt 226: return (lp);
227: }
228:
229: void
1.11 millert 230: usage(void)
1.1 deraadt 231: {
1.10 mickey 232: extern char *__progname;
1.11 millert 233:
1.1 deraadt 234: fprintf(stderr,
1.11 millert 235: "usage: %s [-f min.max] [-p min.max] [-s sepstring] [-t c] file ...\n",
1.10 mickey 236: __progname);
1.1 deraadt 237: exit(1);
238: }