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