"Fossies" - the Fresh Open Source Software Archive 
Member "schily-2021-09-18/paste/paste.c" (20 Aug 2021, 6833 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:
1 /* @(#)paste.c 1.22 21/08/20 Copyright 1985-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static const char sccsid[] =
5 "@(#)paste.c 1.22 21/08/20 Copyright 1985-2021 J. Schilling";
6 #endif
7 /*
8 * Paste some files together
9 *
10 * Copyright (c) 1985-2021 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/mconfig.h>
27 #include <schily/stdio.h>
28 #include <schily/stdlib.h>
29 #include <schily/unistd.h> /* For sys/types.h to make off_t available */
30 #include <schily/standard.h>
31 #define GT_COMERR /* #define comerr gtcomerr */
32 #define GT_ERROR /* #define error gterror */
33 #include <schily/schily.h>
34 #include <schily/nlsdefs.h>
35
36 #define MIN_LINELEN 4096 /* Min line size */
37 #define INCR_LINELEN 4096 /* Increment for line size */
38 #define MAX_FILES (256-3) /* Max # of files */
39
40 LOCAL BOOL eofp[MAX_FILES]; /* Files that did hit EOF */
41 LOCAL FILE *filep[MAX_FILES] = {0}; /* Files to work on */
42 LOCAL char *delim;
43 LOCAL int delimlen;
44 LOCAL int empty;
45
46 LOCAL char *line; /* Output line */
47 LOCAL size_t linelen = MIN_LINELEN;
48 LOCAL int linesize = -1;
49
50 LOCAL void usage __PR((int exitcode));
51 EXPORT int main __PR((int ac, char ** av));
52 LOCAL void paste __PR((int n));
53 LOCAL void spaste __PR((FILE *f));
54 LOCAL int parsedelim __PR((char *d));
55
56 LOCAL void
57 usage(exitcode)
58 int exitcode;
59 {
60 error("Usage: paste [options] file1...filen\n");
61 error("Options:\n");
62 error("\td=list\t\tuse 'list' as delimiter instead of 'tab'.\n");
63 error("\t-e\t\tdo not output empty lines.\n");
64 error("\t-s\t\tpaste lines of one file instead of one line per file.\n");
65 error("\twidth=#,w=#\tmaximum output linewidth (default infinite).\n");
66 error("\t-help\t\tPrint this help.\n");
67 error("\t-version\tPrint version information and exit.\n");
68 exit(exitcode);
69 }
70
71 EXPORT int
72 main(ac, av)
73 int ac;
74 char *av[];
75 {
76 int i = 0; /* Count # of input files */
77
78 char *options = "help,version,d*,e,s,width#,w#";
79 int help = 0;
80 int prvers = 0;
81 int ser = 0;
82 int cac;
83 char * const *cav;
84
85 save_args(ac, av);
86
87 (void) setlocale(LC_ALL, "");
88
89 #ifdef USE_NLS
90 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
91 #define TEXT_DOMAIN "paste" /* Use this only if it weren't */
92 #endif
93 { char *dir;
94 dir = searchfileinpath("share/locale", F_OK,
95 SIP_ANY_FILE|SIP_NO_PATH, NULL);
96 if (dir)
97 (void) bindtextdomain(TEXT_DOMAIN, dir);
98 else
99 #if defined(PROTOTYPES) && defined(INS_BASE)
100 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
101 #else
102 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
103 #endif
104 (void) textdomain(TEXT_DOMAIN);
105 }
106 #endif /* USE_NLS */
107
108 cac = --ac;
109 cav = ++av;
110
111 if (getallargs(&cac, &cav, options, &help, &prvers,
112 &delim, &empty, &ser,
113 &linesize, &linesize) < 0) {
114 errmsgno(EX_BAD, "Bad flag: %s.\n", cav[0]);
115 usage(EX_BAD);
116 }
117 if (help)
118 usage(0);
119
120 if (prvers) {
121 /* CSTYLED */
122 gtprintf("Paste release %s (%s-%s-%s) Copyright (C) 1985-2021 %s\n",
123 "1.22",
124 HOST_CPU, HOST_VENDOR, HOST_OS,
125 _("Jörg Schilling"));
126 exit(0);
127 }
128
129 if (delim) {
130 delimlen = parsedelim(delim);
131 if (delimlen == 0)
132 comerrno(EX_BAD, "No delimiter.\n");
133 } else {
134 delim = "\t";
135 delimlen = 1;
136 }
137 cac = ac;
138 cav = av;
139 for (; getfiles(&cac, &cav, options); cac--, cav++) {
140 if (i >= MAX_FILES)
141 comerrno(EX_BAD, "Cannot paste more than %d files.\n",
142 MAX_FILES);
143 if (streql(*cav, "-"))
144 filep[i++] = stdin;
145 else if ((filep[i++] = fileopen(*cav, "r")) == (FILE *)NULL)
146 comerr("Cannot open '%s'.\n", *cav);
147 if (ser)
148 spaste(filep[i-1]);
149 }
150
151 if (i == 0) {
152 errmsgno(EX_BAD, "No files given.\n");
153 usage(EX_BAD);
154 }
155 if (ser)
156 return (0);
157
158 if (linesize > 0)
159 linelen = linesize;
160 if ((line = malloc(linelen+2)) == NULL)
161 comerr("Cannot malloc space for line.\n");
162
163 paste(i);
164 return (0);
165 }
166
167 LOCAL void
168 paste(n)
169 int n; /* # of files to read from */
170 {
171 int k;
172 register char *lp; /* pointer to line */
173 register char *ep; /* pointer to end of line */
174 register int c;
175 register FILE *fp;
176 register int i;
177
178 for (i = 0; i < n; i++)
179 eofp[i] = FALSE;
180 ep = &line[linelen];
181
182 for (k = 0; k < n; ) { /* Stop when all files hit EOF */
183 lp = line;
184 for (i = 0; i < n; i++) {
185 if (!eofp[i]) { /* No EOF on this file yet? */
186 fp = filep[i];
187 again:
188 while ((c = getc(fp)) != EOF &&
189 c != '\n' && lp < ep)
190 *lp++ = c;
191
192 if (lp >= ep) {
193 char *new = NULL;
194 static BOOL didwarn = FALSE;
195
196 if (linesize < 0) {
197 /*
198 * Use dynamic line length,
199 */
200 linelen += INCR_LINELEN;
201 new = realloc(line,
202 linelen+2 + INCR_LINELEN);
203 } else {
204 didwarn = TRUE;
205 }
206 if (new == NULL) {
207 if (!didwarn)
208 errmsg(
209 "Cannot realloc space for line.\n");
210 didwarn = TRUE;
211 } else {
212 linelen += INCR_LINELEN;
213 lp += new - line;
214 ep = &new[linelen];
215 line = new;
216 goto again;
217 }
218 while ((c = getc(fp)) != EOF &&
219 c != '\n')
220 ;
221 }
222 } else { /* Avoid EOFing twice */
223 c = '\n'; /* so pretend eol. */
224 }
225
226 if (c == EOF) {
227 eofp[i] = EOF;
228 k++; /* One file less */
229 }
230
231 if (i == (n-1)) { /* Last file in line? */
232 *lp++ = '\n';
233 *lp = '\0';
234 break; /* Quit loop to print line */
235 } else { /* Add field delimiter */
236 c = delim[i%delimlen];
237 if (c)
238 *lp++ = c;
239 }
240 }
241
242 /*
243 * Print only if at least one file did have a line (k < n).
244 * With -e, print only lines that have more than delimiters.
245 */
246 if (lp-line > n || (!empty && k < n))
247 filewrite(stdout, line, lp-line);
248 }
249 }
250
251 LOCAL void
252 spaste(f)
253 FILE *f;
254 {
255 register int len;
256 register int i;
257 register int c;
258
259 if ((len = fgetaline(f, &line, &linelen)) > 0) {
260 for (i = 0; ; i++) {
261 if (line[len-1] == '\n')
262 len--;
263 filewrite(stdout, line, len);
264 if ((len = fgetaline(f, &line, &linelen)) <= 0)
265 break;
266 c = delim[i%delimlen];
267 if (c)
268 putchar(c);
269 }
270 }
271 putchar('\n');
272 fclose(f);
273 }
274
275 LOCAL int
276 parsedelim(d)
277 char *d;
278 {
279 int len = 0;
280 int c;
281 static char del[MAX_FILES];
282
283 while (*d) {
284 if ((c = *d++) != '\\') {
285 del[len++] = c;
286 } else {
287 switch (c = *d++) {
288
289 case '0':
290 c = 0;
291 break;
292 case 't':
293 c = '\t';
294 break;
295 case 'n':
296 c = '\n';
297 break;
298 }
299 del[len++] = c;
300 }
301 if (len >= MAX_FILES)
302 break;
303 }
304 delim = del;
305 return (len);
306 }