19b50d902SRodney W. Grimes /*- 29b50d902SRodney W. Grimes * Copyright (c) 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 349b50d902SRodney W. Grimes #ifndef lint 35df899658SPhilippe Charnier static const char copyright[] = 369b50d902SRodney W. Grimes "@(#) Copyright (c) 1993\n\ 379b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 389b50d902SRodney W. Grimes #endif /* not lint */ 399b50d902SRodney W. Grimes 409b50d902SRodney W. Grimes #ifndef lint 41df899658SPhilippe Charnier #if 0 429b50d902SRodney W. Grimes static char sccsid[] = "@(#)lam.c 8.1 (Berkeley) 6/6/93"; 43df899658SPhilippe Charnier #endif 449b50d902SRodney W. Grimes #endif /* not lint */ 45e026a48cSDavid E. O'Brien #include <sys/cdefs.h> 46e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 479b50d902SRodney W. Grimes 489b50d902SRodney W. Grimes /* 499b50d902SRodney W. Grimes * lam - laminate files 509b50d902SRodney W. Grimes * Author: John Kunze, UCB 519b50d902SRodney W. Grimes */ 529b50d902SRodney W. Grimes 53aeacf525SMike Heffner #include <ctype.h> 54df899658SPhilippe Charnier #include <err.h> 559b50d902SRodney W. Grimes #include <stdio.h> 569b50d902SRodney W. Grimes #include <stdlib.h> 579b50d902SRodney W. Grimes #include <string.h> 589b50d902SRodney W. Grimes 599b50d902SRodney W. Grimes #define MAXOFILES 20 609b50d902SRodney W. Grimes #define BIGBUFSIZ 5 * BUFSIZ 619b50d902SRodney W. Grimes 629b50d902SRodney W. Grimes struct openfile { /* open file structure */ 639b50d902SRodney W. Grimes FILE *fp; /* file pointer */ 649b50d902SRodney W. Grimes short eof; /* eof flag */ 659b50d902SRodney W. Grimes short pad; /* pad flag for missing columns */ 669b50d902SRodney W. Grimes char eol; /* end of line character */ 67b5b9b430SMike Barcroft const char *sepstring; /* string to print before each line */ 68b5b9b430SMike Barcroft const char *format; /* printf(3) style string spec. */ 699b50d902SRodney W. Grimes } input[MAXOFILES]; 709b50d902SRodney W. Grimes 719b50d902SRodney W. Grimes int morefiles; /* set by getargs(), changed by gatherline() */ 729b50d902SRodney W. Grimes int nofinalnl; /* normally append \n to each output line */ 739b50d902SRodney W. Grimes char line[BIGBUFSIZ]; 749b50d902SRodney W. Grimes char *linep; 759b50d902SRodney W. Grimes 76b5b9b430SMike Barcroft static char *gatherline(struct openfile *); 77b5b9b430SMike Barcroft static void getargs(char *[]); 78b5b9b430SMike Barcroft static char *pad(struct openfile *); 797a536c3bSMike Heffner static void usage(void); 809b50d902SRodney W. Grimes 819b50d902SRodney W. Grimes int 82f63eec78SJuli Mallett main(int argc, char *argv[]) 839b50d902SRodney W. Grimes { 84aeacf525SMike Heffner struct openfile *ip; 859b50d902SRodney W. Grimes 86f201bc9cSJuli Mallett if (argc == 1) 87df899658SPhilippe Charnier usage(); 88f63eec78SJuli Mallett getargs(argv); 89f201bc9cSJuli Mallett if (!morefiles) 90f201bc9cSJuli Mallett usage(); 919b50d902SRodney W. Grimes for (;;) { 929b50d902SRodney W. Grimes linep = line; 939b50d902SRodney W. Grimes for (ip = input; ip->fp != NULL; ip++) 949b50d902SRodney W. Grimes linep = gatherline(ip); 959b50d902SRodney W. Grimes if (!morefiles) 969b50d902SRodney W. Grimes exit(0); 979b50d902SRodney W. Grimes fputs(line, stdout); 989b50d902SRodney W. Grimes fputs(ip->sepstring, stdout); 999b50d902SRodney W. Grimes if (!nofinalnl) 1009b50d902SRodney W. Grimes putchar('\n'); 1019b50d902SRodney W. Grimes } 1029b50d902SRodney W. Grimes } 1039b50d902SRodney W. Grimes 104b5b9b430SMike Barcroft static void 1058ecfa014SMike Heffner getargs(char *av[]) 1069b50d902SRodney W. Grimes { 107aeacf525SMike Heffner struct openfile *ip = input; 108aeacf525SMike Heffner char *p, *c; 1099b50d902SRodney W. Grimes static char fmtbuf[BUFSIZ]; 1109b50d902SRodney W. Grimes char *fmtp = fmtbuf; 1119b50d902SRodney W. Grimes int P, S, F, T; 1129b50d902SRodney W. Grimes 1139b50d902SRodney W. Grimes P = S = F = T = 0; /* capitalized options */ 1149b50d902SRodney W. Grimes while ((p = *++av) != NULL) { 1159b50d902SRodney W. Grimes if (*p != '-' || !p[1]) { 116f201bc9cSJuli Mallett if (++morefiles >= MAXOFILES) 117f201bc9cSJuli Mallett errx(1, "too many input files"); 118f201bc9cSJuli Mallett if (*p == '-') 1199b50d902SRodney W. Grimes ip->fp = stdin; 120f201bc9cSJuli Mallett else if ((ip->fp = fopen(p, "r")) == NULL) { 1210c4d24a7SKris Kennaway err(1, "%s", p); 1229b50d902SRodney W. Grimes } 1239b50d902SRodney W. Grimes ip->pad = P; 1249b50d902SRodney W. Grimes if (!ip->sepstring) 1259b50d902SRodney W. Grimes ip->sepstring = (S ? (ip-1)->sepstring : ""); 1269b50d902SRodney W. Grimes if (!ip->format) 1279b50d902SRodney W. Grimes ip->format = ((P || F) ? (ip-1)->format : "%s"); 1289b50d902SRodney W. Grimes if (!ip->eol) 1299b50d902SRodney W. Grimes ip->eol = (T ? (ip-1)->eol : '\n'); 1309b50d902SRodney W. Grimes ip++; 1319b50d902SRodney W. Grimes continue; 1329b50d902SRodney W. Grimes } 133aeacf525SMike Heffner c = ++p; 134be1e385eSTim J. Robbins switch (tolower((unsigned char)*c)) { 1359b50d902SRodney W. Grimes case 's': 1369b50d902SRodney W. Grimes if (*++p || (p = *++av)) 1379b50d902SRodney W. Grimes ip->sepstring = p; 1389b50d902SRodney W. Grimes else 139dfaacec6SJuli Mallett usage(); 1409b50d902SRodney W. Grimes S = (*c == 'S' ? 1 : 0); 1419b50d902SRodney W. Grimes break; 1429b50d902SRodney W. Grimes case 't': 1439b50d902SRodney W. Grimes if (*++p || (p = *++av)) 1449b50d902SRodney W. Grimes ip->eol = *p; 1459b50d902SRodney W. Grimes else 146dfaacec6SJuli Mallett usage(); 1479b50d902SRodney W. Grimes T = (*c == 'T' ? 1 : 0); 1489b50d902SRodney W. Grimes nofinalnl = 1; 1499b50d902SRodney W. Grimes break; 1509b50d902SRodney W. Grimes case 'p': 1519b50d902SRodney W. Grimes ip->pad = 1; 1529b50d902SRodney W. Grimes P = (*c == 'P' ? 1 : 0); 153aeacf525SMike Heffner /* FALLTHROUGH */ 1549b50d902SRodney W. Grimes case 'f': 1559b50d902SRodney W. Grimes F = (*c == 'F' ? 1 : 0); 1569b50d902SRodney W. Grimes if (*++p || (p = *++av)) { 1579b50d902SRodney W. Grimes fmtp += strlen(fmtp) + 1; 158aeacf525SMike Heffner if (fmtp >= fmtbuf + sizeof(fmtbuf)) 159df899658SPhilippe Charnier errx(1, "no more format space"); 160aeacf525SMike Heffner /* restrict format string to only valid width formatters */ 161aeacf525SMike Heffner if (strspn(p, "-.0123456789") != strlen(p)) 162aeacf525SMike Heffner errx(1, "invalid format string `%s'", p); 163aeacf525SMike Heffner if (snprintf(fmtp, fmtbuf + sizeof(fmtbuf) - fmtp, "%%%ss", p) 164aeacf525SMike Heffner >= fmtbuf + sizeof(fmtbuf) - fmtp) 165aeacf525SMike Heffner errx(1, "no more format space"); 1669b50d902SRodney W. Grimes ip->format = fmtp; 1679b50d902SRodney W. Grimes } 1689b50d902SRodney W. Grimes else 169dfaacec6SJuli Mallett usage(); 1709b50d902SRodney W. Grimes break; 1719b50d902SRodney W. Grimes default: 172dfaacec6SJuli Mallett usage(); 1739b50d902SRodney W. Grimes } 1749b50d902SRodney W. Grimes } 1759b50d902SRodney W. Grimes ip->fp = NULL; 1769b50d902SRodney W. Grimes if (!ip->sepstring) 1779b50d902SRodney W. Grimes ip->sepstring = ""; 1789b50d902SRodney W. Grimes } 1799b50d902SRodney W. Grimes 180b5b9b430SMike Barcroft static char * 1817a536c3bSMike Heffner pad(struct openfile *ip) 1829b50d902SRodney W. Grimes { 183aeacf525SMike Heffner char *lp = linep; 1849b50d902SRodney W. Grimes 185aeacf525SMike Heffner strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); 186aeacf525SMike Heffner lp += strlen(lp); 1879b50d902SRodney W. Grimes if (ip->pad) { 188aeacf525SMike Heffner snprintf(lp, line + sizeof(line) - lp, ip->format, ""); 1899b50d902SRodney W. Grimes lp += strlen(lp); 1909b50d902SRodney W. Grimes } 1919b50d902SRodney W. Grimes return (lp); 1929b50d902SRodney W. Grimes } 1939b50d902SRodney W. Grimes 194b5b9b430SMike Barcroft static char * 1957a536c3bSMike Heffner gatherline(struct openfile *ip) 1969b50d902SRodney W. Grimes { 1979b50d902SRodney W. Grimes char s[BUFSIZ]; 198aeacf525SMike Heffner int c; 199aeacf525SMike Heffner char *p; 200aeacf525SMike Heffner char *lp = linep; 201aeacf525SMike Heffner char *end = s + sizeof(s) - 1; 2029b50d902SRodney W. Grimes 2039b50d902SRodney W. Grimes if (ip->eof) 2049b50d902SRodney W. Grimes return (pad(ip)); 2059b50d902SRodney W. Grimes for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++) 2069b50d902SRodney W. Grimes if ((*p = c) == ip->eol) 2079b50d902SRodney W. Grimes break; 2089b50d902SRodney W. Grimes *p = '\0'; 2099b50d902SRodney W. Grimes if (c == EOF) { 2109b50d902SRodney W. Grimes ip->eof = 1; 2119b50d902SRodney W. Grimes if (ip->fp == stdin) 2129b50d902SRodney W. Grimes fclose(stdin); 2139b50d902SRodney W. Grimes morefiles--; 2149b50d902SRodney W. Grimes return (pad(ip)); 2159b50d902SRodney W. Grimes } 216aeacf525SMike Heffner strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); 217aeacf525SMike Heffner lp += strlen(lp); 218aeacf525SMike Heffner snprintf(lp, line + sizeof(line) - lp, ip->format, s); 2199b50d902SRodney W. Grimes lp += strlen(lp); 2209b50d902SRodney W. Grimes return (lp); 2219b50d902SRodney W. Grimes } 2229b50d902SRodney W. Grimes 223df899658SPhilippe Charnier static void 224df899658SPhilippe Charnier usage() 2259b50d902SRodney W. Grimes { 226df899658SPhilippe Charnier fprintf(stderr, "%s\n%s\n", 227df899658SPhilippe Charnier "usage: lam [ -f min.max ] [ -s sepstring ] [ -t c ] file ...", 228df899658SPhilippe Charnier " lam [ -p min.max ] [ -s sepstring ] [ -t c ] file ..."); 2299b50d902SRodney W. Grimes exit(1); 2309b50d902SRodney W. Grimes } 231