1 /*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)lam.c 8.1 (Berkeley) 6/6/93"; 43 #endif 44 static const char rcsid[] = 45 "$FreeBSD$"; 46 #endif /* not lint */ 47 48 /* 49 * lam - laminate files 50 * Author: John Kunze, UCB 51 */ 52 53 #include <ctype.h> 54 #include <err.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 59 #define MAXOFILES 20 60 #define BIGBUFSIZ 5 * BUFSIZ 61 62 struct openfile { /* open file structure */ 63 FILE *fp; /* file pointer */ 64 short eof; /* eof flag */ 65 short pad; /* pad flag for missing columns */ 66 char eol; /* end of line character */ 67 const char *sepstring; /* string to print before each line */ 68 const char *format; /* printf(3) style string spec. */ 69 } input[MAXOFILES]; 70 71 int morefiles; /* set by getargs(), changed by gatherline() */ 72 int nofinalnl; /* normally append \n to each output line */ 73 char line[BIGBUFSIZ]; 74 char *linep; 75 76 static char *gatherline(struct openfile *); 77 static void getargs(char *[]); 78 static char *pad(struct openfile *); 79 static void usage(void); 80 81 int 82 main(int argc __unused, char *argv[]) 83 { 84 struct openfile *ip; 85 86 getargs(argv); 87 if (!morefiles) 88 usage(); 89 for (;;) { 90 linep = line; 91 for (ip = input; ip->fp != NULL; ip++) 92 linep = gatherline(ip); 93 if (!morefiles) 94 exit(0); 95 fputs(line, stdout); 96 fputs(ip->sepstring, stdout); 97 if (!nofinalnl) 98 putchar('\n'); 99 } 100 } 101 102 static void 103 getargs(char *av[]) 104 { 105 struct openfile *ip = input; 106 char *p, *c; 107 static char fmtbuf[BUFSIZ]; 108 char *fmtp = fmtbuf; 109 int P, S, F, T; 110 111 P = S = F = T = 0; /* capitalized options */ 112 while ((p = *++av) != NULL) { 113 if (*p != '-' || !p[1]) { 114 if (++morefiles >= MAXOFILES) 115 errx(1, "too many input files"); 116 if (*p == '-') 117 ip->fp = stdin; 118 else if ((ip->fp = fopen(p, "r")) == NULL) { 119 err(1, "%s", p); 120 } 121 ip->pad = P; 122 if (!ip->sepstring) 123 ip->sepstring = (S ? (ip-1)->sepstring : ""); 124 if (!ip->format) 125 ip->format = ((P || F) ? (ip-1)->format : "%s"); 126 if (!ip->eol) 127 ip->eol = (T ? (ip-1)->eol : '\n'); 128 ip++; 129 continue; 130 } 131 c = ++p; 132 switch (tolower(*c)) { 133 case 's': 134 if (*++p || (p = *++av)) 135 ip->sepstring = p; 136 else 137 errx(1, "need string after -%s", c); 138 S = (*c == 'S' ? 1 : 0); 139 break; 140 case 't': 141 if (*++p || (p = *++av)) 142 ip->eol = *p; 143 else 144 errx(1, "need character after -%s", c); 145 T = (*c == 'T' ? 1 : 0); 146 nofinalnl = 1; 147 break; 148 case 'p': 149 ip->pad = 1; 150 P = (*c == 'P' ? 1 : 0); 151 /* FALLTHROUGH */ 152 case 'f': 153 F = (*c == 'F' ? 1 : 0); 154 if (*++p || (p = *++av)) { 155 fmtp += strlen(fmtp) + 1; 156 if (fmtp >= fmtbuf + sizeof(fmtbuf)) 157 errx(1, "no more format space"); 158 /* restrict format string to only valid width formatters */ 159 if (strspn(p, "-.0123456789") != strlen(p)) 160 errx(1, "invalid format string `%s'", p); 161 if (snprintf(fmtp, fmtbuf + sizeof(fmtbuf) - fmtp, "%%%ss", p) 162 >= fmtbuf + sizeof(fmtbuf) - fmtp) 163 errx(1, "no more format space"); 164 ip->format = fmtp; 165 } 166 else 167 errx(1, "need string after -%s", c); 168 break; 169 default: 170 errx(1, "what do you mean by -%s?", c); 171 break; 172 } 173 } 174 ip->fp = NULL; 175 if (!ip->sepstring) 176 ip->sepstring = ""; 177 } 178 179 static char * 180 pad(struct openfile *ip) 181 { 182 char *lp = linep; 183 184 strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); 185 lp += strlen(lp); 186 if (ip->pad) { 187 snprintf(lp, line + sizeof(line) - lp, ip->format, ""); 188 lp += strlen(lp); 189 } 190 return (lp); 191 } 192 193 static char * 194 gatherline(struct openfile *ip) 195 { 196 char s[BUFSIZ]; 197 int c; 198 char *p; 199 char *lp = linep; 200 char *end = s + sizeof(s) - 1; 201 202 if (ip->eof) 203 return (pad(ip)); 204 for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++) 205 if ((*p = c) == ip->eol) 206 break; 207 *p = '\0'; 208 if (c == EOF) { 209 ip->eof = 1; 210 if (ip->fp == stdin) 211 fclose(stdin); 212 morefiles--; 213 return (pad(ip)); 214 } 215 strlcpy(lp, ip->sepstring, line + sizeof(line) - lp); 216 lp += strlen(lp); 217 snprintf(lp, line + sizeof(line) - lp, ip->format, s); 218 lp += strlen(lp); 219 return (lp); 220 } 221 222 static void 223 usage() 224 { 225 fprintf(stderr, "%s\n%s\n", 226 "usage: lam [ -f min.max ] [ -s sepstring ] [ -t c ] file ...", 227 " lam [ -p min.max ] [ -s sepstring ] [ -t c ] file ..."); 228 exit(1); 229 } 230