11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3127497Scharnierstatic const char copyright[] = 321590Srgrimes"@(#) Copyright (c) 1993\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 341590Srgrimes#endif /* not lint */ 351590Srgrimes 361590Srgrimes#ifndef lint 3727497Scharnier#if 0 381590Srgrimesstatic char sccsid[] = "@(#)lam.c 8.1 (Berkeley) 6/6/93"; 3927497Scharnier#endif 401590Srgrimes#endif /* not lint */ 4199112Sobrien#include <sys/cdefs.h> 4299112Sobrien__FBSDID("$FreeBSD$"); 431590Srgrimes 441590Srgrimes/* 451590Srgrimes * lam - laminate files 461590Srgrimes * Author: John Kunze, UCB 471590Srgrimes */ 481590Srgrimes 4972152Smikeh#include <ctype.h> 5027497Scharnier#include <err.h> 511590Srgrimes#include <stdio.h> 521590Srgrimes#include <stdlib.h> 531590Srgrimes#include <string.h> 541590Srgrimes 551590Srgrimes#define MAXOFILES 20 561590Srgrimes#define BIGBUFSIZ 5 * BUFSIZ 571590Srgrimes 58227240Sedstatic struct openfile { /* open file structure */ 591590Srgrimes FILE *fp; /* file pointer */ 601590Srgrimes short eof; /* eof flag */ 611590Srgrimes short pad; /* pad flag for missing columns */ 621590Srgrimes char eol; /* end of line character */ 6381222Smike const char *sepstring; /* string to print before each line */ 6481222Smike const char *format; /* printf(3) style string spec. */ 651590Srgrimes} input[MAXOFILES]; 661590Srgrimes 67227240Sedstatic int morefiles; /* set by getargs(), changed by gatherline() */ 68227240Sedstatic int nofinalnl; /* normally append \n to each output line */ 69227240Sedstatic char line[BIGBUFSIZ]; 70227240Sedstatic char *linep; 711590Srgrimes 7281222Smikestatic char *gatherline(struct openfile *); 7381222Smikestatic void getargs(char *[]); 7481222Smikestatic char *pad(struct openfile *); 7572178Smikehstatic void usage(void); 761590Srgrimes 771590Srgrimesint 7898933Sjmallettmain(int argc, char *argv[]) 791590Srgrimes{ 8072152Smikeh struct openfile *ip; 811590Srgrimes 8299221Sjmallett if (argc == 1) 8398933Sjmallett usage(); 841590Srgrimes getargs(argv); 8599221Sjmallett if (!morefiles) 8699221Sjmallett usage(); 871590Srgrimes for (;;) { 881590Srgrimes linep = line; 891590Srgrimes for (ip = input; ip->fp != NULL; ip++) 901590Srgrimes linep = gatherline(ip); 911590Srgrimes if (!morefiles) 921590Srgrimes exit(0); 931590Srgrimes fputs(line, stdout); 941590Srgrimes fputs(ip->sepstring, stdout); 951590Srgrimes if (!nofinalnl) 961590Srgrimes putchar('\n'); 971590Srgrimes } 981590Srgrimes} 991590Srgrimes 10081222Smikestatic void 10172178Smikehgetargs(char *av[]) 1021590Srgrimes{ 10372152Smikeh struct openfile *ip = input; 10472152Smikeh char *p, *c; 1051590Srgrimes static char fmtbuf[BUFSIZ]; 1061590Srgrimes char *fmtp = fmtbuf; 1071590Srgrimes int P, S, F, T; 1081590Srgrimes 1091590Srgrimes P = S = F = T = 0; /* capitalized options */ 1101590Srgrimes while ((p = *++av) != NULL) { 1111590Srgrimes if (*p != '-' || !p[1]) { 11299221Sjmallett if (++morefiles >= MAXOFILES) 11399221Sjmallett errx(1, "too many input files"); 11499221Sjmallett if (*p == '-') 1151590Srgrimes ip->fp = stdin; 11699221Sjmallett else if ((ip->fp = fopen(p, "r")) == NULL) { 11762894Skris err(1, "%s", p); 1181590Srgrimes } 1191590Srgrimes ip->pad = P; 1201590Srgrimes if (!ip->sepstring) 1211590Srgrimes ip->sepstring = (S ? (ip-1)->sepstring : ""); 1221590Srgrimes if (!ip->format) 1231590Srgrimes ip->format = ((P || F) ? (ip-1)->format : "%s"); 1241590Srgrimes if (!ip->eol) 1251590Srgrimes ip->eol = (T ? (ip-1)->eol : '\n'); 1261590Srgrimes ip++; 1271590Srgrimes continue; 1281590Srgrimes } 12972152Smikeh c = ++p; 130132404Stjr switch (tolower((unsigned char)*c)) { 1311590Srgrimes case 's': 1321590Srgrimes if (*++p || (p = *++av)) 1331590Srgrimes ip->sepstring = p; 1341590Srgrimes else 135148713Sjmallett usage(); 1361590Srgrimes S = (*c == 'S' ? 1 : 0); 1371590Srgrimes break; 1381590Srgrimes case 't': 1391590Srgrimes if (*++p || (p = *++av)) 1401590Srgrimes ip->eol = *p; 1411590Srgrimes else 142148713Sjmallett usage(); 1431590Srgrimes T = (*c == 'T' ? 1 : 0); 1441590Srgrimes nofinalnl = 1; 1451590Srgrimes break; 1461590Srgrimes case 'p': 1471590Srgrimes ip->pad = 1; 1481590Srgrimes P = (*c == 'P' ? 1 : 0); 14972152Smikeh /* FALLTHROUGH */ 1501590Srgrimes case 'f': 1511590Srgrimes F = (*c == 'F' ? 1 : 0); 1521590Srgrimes if (*++p || (p = *++av)) { 1531590Srgrimes fmtp += strlen(fmtp) + 1; 15472152Smikeh if (fmtp >= fmtbuf + sizeof(fmtbuf)) 15527497Scharnier errx(1, "no more format space"); 15672152Smikeh /* restrict format string to only valid width formatters */ 15772152Smikeh if (strspn(p, "-.0123456789") != strlen(p)) 15872152Smikeh errx(1, "invalid format string `%s'", p); 15972152Smikeh if (snprintf(fmtp, fmtbuf + sizeof(fmtbuf) - fmtp, "%%%ss", p) 16072152Smikeh >= fmtbuf + sizeof(fmtbuf) - fmtp) 16172152Smikeh errx(1, "no more format space"); 1621590Srgrimes ip->format = fmtp; 1631590Srgrimes } 1641590Srgrimes else 165148713Sjmallett usage(); 1661590Srgrimes break; 1671590Srgrimes default: 168148713Sjmallett usage(); 1691590Srgrimes } 1701590Srgrimes } 1711590Srgrimes ip->fp = NULL; 1721590Srgrimes if (!ip->sepstring) 1731590Srgrimes ip->sepstring = ""; 1741590Srgrimes} 1751590Srgrimes 17681222Smikestatic char * 17772153Smikehpad(struct openfile *ip) 1781590Srgrimes{ 17972152Smikeh char *lp = linep; 1801590Srgrimes 18172152Smikeh strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); 18272152Smikeh lp += strlen(lp); 1831590Srgrimes if (ip->pad) { 18472152Smikeh snprintf(lp, line + sizeof(line) - lp, ip->format, ""); 1851590Srgrimes lp += strlen(lp); 1861590Srgrimes } 1871590Srgrimes return (lp); 1881590Srgrimes} 1891590Srgrimes 19081222Smikestatic char * 19172153Smikehgatherline(struct openfile *ip) 1921590Srgrimes{ 1931590Srgrimes char s[BUFSIZ]; 19472152Smikeh int c; 19572152Smikeh char *p; 19672152Smikeh char *lp = linep; 19772152Smikeh char *end = s + sizeof(s) - 1; 1981590Srgrimes 1991590Srgrimes if (ip->eof) 2001590Srgrimes return (pad(ip)); 2011590Srgrimes for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++) 2021590Srgrimes if ((*p = c) == ip->eol) 2031590Srgrimes break; 2041590Srgrimes *p = '\0'; 2051590Srgrimes if (c == EOF) { 2061590Srgrimes ip->eof = 1; 2071590Srgrimes if (ip->fp == stdin) 2081590Srgrimes fclose(stdin); 2091590Srgrimes morefiles--; 2101590Srgrimes return (pad(ip)); 2111590Srgrimes } 21272152Smikeh strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); 2131590Srgrimes lp += strlen(lp); 21472152Smikeh snprintf(lp, line + sizeof(line) - lp, ip->format, s); 21572152Smikeh lp += strlen(lp); 2161590Srgrimes return (lp); 2171590Srgrimes} 2181590Srgrimes 21927497Scharnierstatic void 220201382Sedusage(void) 2211590Srgrimes{ 22227497Scharnier fprintf(stderr, "%s\n%s\n", 22327497Scharnier"usage: lam [ -f min.max ] [ -s sepstring ] [ -t c ] file ...", 22427497Scharnier" lam [ -p min.max ] [ -s sepstring ] [ -t c ] file ..."); 2251590Srgrimes exit(1); 2261590Srgrimes} 227