ldd(1): Raise WARNS to 2 and fix warnings.
[dragonfly.git] / usr.bin / paste / paste.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Adam S. Moskowitz of Menlo Consulting.
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.
16  * 3. Neither the name of the University nor the names of its contributors
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  * @(#) Copyright (c) 1989, 1993 The Regents of the University of California.  All rights reserved.
33  * @(#)paste.c  8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.bin/paste/paste.c,v 1.6.2.2 2002/07/14 15:16:00 tjr Exp $
35  * $DragonFly: src/usr.bin/paste/paste.c,v 1.3 2004/12/15 23:11:06 cpressey Exp $
36  */
37
38 #include <sys/types.h>
39
40 #include <err.h>
41 #include <errno.h>
42 #include <limits.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 char *delim;
49 int delimcnt;
50
51 int parallel(char **);
52 int sequential(char **);
53 int tr(char *);
54 static void usage(void);
55
56 char tab[] = "\t";
57
58 int
59 main(int argc, char *argv[])
60 {
61         int ch, rval, seq;
62
63         seq = 0;
64         while ((ch = getopt(argc, argv, "d:s")) != -1)
65                 switch(ch) {
66                 case 'd':
67                         delimcnt = tr(delim = optarg);
68                         break;
69                 case 's':
70                         seq = 1;
71                         break;
72                 case '?':
73                 default:
74                         usage();
75                 }
76         argc -= optind;
77         argv += optind;
78
79         if (*argv == NULL)
80                 usage();
81         if (!delim) {
82                 delimcnt = 1;
83                 delim = tab;
84         }
85
86         if (seq)
87                 rval = sequential(argv);
88         else
89                 rval = parallel(argv);
90         exit(rval);
91 }
92
93 typedef struct _list {
94         struct _list *next;
95         FILE *fp;
96         int cnt;
97         char *name;
98 } LIST;
99
100 int
101 parallel(char **argv)
102 {
103         LIST *lp;
104         int cnt;
105         char ch, *buf, *p;
106         LIST *head, *tmp;
107         int opencnt, output;
108         size_t len;
109
110         tmp = NULL;
111         for (cnt = 0, head = NULL; (p = *argv); ++argv, ++cnt) {
112                 if ((lp = malloc(sizeof(LIST))) == NULL)
113                         err(1, NULL);
114                 if (p[0] == '-' && !p[1])
115                         lp->fp = stdin;
116                 else if (!(lp->fp = fopen(p, "r")))
117                         err(1, "%s", p);
118                 lp->next = NULL;
119                 lp->cnt = cnt;
120                 lp->name = p;
121                 if (!head)
122                         head = tmp = lp;
123                 else {
124                         tmp->next = lp;
125                         tmp = lp;
126                 }
127         }
128
129         for (opencnt = cnt; opencnt;) {
130                 for (output = 0, lp = head; lp; lp = lp->next) {
131                         if (!lp->fp) {
132                                 if (output && lp->cnt &&
133                                     (ch = delim[(lp->cnt - 1) % delimcnt]))
134                                         putchar(ch);
135                                 continue;
136                         }
137                         if ((buf = fgetln(lp->fp, &len)) == NULL) {
138                                 if (!--opencnt)
139                                         break;
140                                 lp->fp = NULL;
141                                 if (output && lp->cnt &&
142                                     (ch = delim[(lp->cnt - 1) % delimcnt]))
143                                         putchar(ch);
144                                 continue;
145                         }
146                         /*
147                          * make sure that we don't print any delimiters
148                          * unless there's a non-empty file.
149                          */
150                         if (!output) {
151                                 output = 1;
152                                 for (cnt = 0; cnt < lp->cnt; ++cnt)
153                                         if ((ch = delim[cnt % delimcnt]))
154                                                 putchar(ch);
155                         } else if ((ch = delim[(lp->cnt - 1) % delimcnt]))
156                                 putchar(ch);
157                         if (buf[len - 1] == '\n')
158                                 len--;
159                         fwrite(buf, 1, len, stdout);
160                 }
161                 if (output)
162                         putchar('\n');
163         }
164
165         return (0);
166 }
167
168 int
169 sequential(char **argv)
170 {
171         FILE *fp;
172         int cnt, failed, needdelim;
173         char *buf, *p;
174         size_t len;
175
176         failed = 0;
177         for (; (p = *argv); ++argv) {
178                 if (p[0] == '-' && !p[1])
179                         fp = stdin;
180                 else if (!(fp = fopen(p, "r"))) {
181                         warn("%s", p);
182                         failed = 1;
183                         continue;
184                 }
185                 cnt = needdelim = 0;
186                 while ((buf = fgetln(fp, &len)) != NULL) {
187                         if (needdelim) {
188                                 needdelim = 0;
189                                 if (delim[cnt] != '\0')
190                                         putchar(delim[cnt]);
191                                 if (++cnt == delimcnt)
192                                         cnt = 0;
193                         }
194                         if (buf[len - 1] == '\n')
195                                 len--;
196                         fwrite(buf, 1, len, stdout);
197                         needdelim = 1;
198                 }
199                 if (needdelim)
200                         putchar('\n');
201                 if (fp != stdin)
202                         (void)fclose(fp);
203         }
204
205         return (failed != 0);
206 }
207
208 int
209 tr(char *arg)
210 {
211         int cnt;
212         char ch, *p;
213
214         for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
215                 if (ch == '\\')
216                         switch(ch = *p++) {
217                         case 'n':
218                                 *arg = '\n';
219                                 break;
220                         case 't':
221                                 *arg = '\t';
222                                 break;
223                         case '0':
224                                 *arg = '\0';
225                                 break;
226                         default:
227                                 *arg = ch;
228                                 break;
229                 } else
230                         *arg = ch;
231
232         if (!cnt)
233                 errx(1, "no delimiters specified");
234         return(cnt);
235 }
236
237 static void
238 usage(void)
239 {
240         (void)fprintf(stderr, "usage: paste [-s] [-d delimiters] file ...\n");
241         exit(1);
242 }