Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libcmd/paste.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1992-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* *
20
***********************************************************************/
21
#pragma prototyped
22
/*
23
* David Korn
24
* AT&T Bell Laboratories
25
*
26
* paste [-s] [-d delim] [file] ...
27
*
28
* paste lines from files together
29
*/
30
31
static const char usage[] =
32
"[-?\n@(#)$Id: paste (AT&T Research) 2010-06-12 $\n]"
33
USAGE_LICENSE
34
"[+NAME?paste - merge lines of files]"
35
"[+DESCRIPTION?\bpaste\b concatenates the corresponding lines of a "
36
"given input file and writes the resulting lines to standard "
37
"output. By default \bpaste\b replaces the newline character of "
38
"every line other than the last input file with the TAB character.]"
39
"[+?Unless the \b-s\b option is specified, if an end-of-file is encountered "
40
"on one or more input files, but not all input files, \bpaste\b "
41
"behaves as if empty lines were read from the file(s) on which "
42
"end-of-file was detected.]"
43
"[+?Unless the \b-s\b option is specified, \bpaste\b is limited by "
44
"the underlying operating system on how many \afile\a operands "
45
"can be specified.]"
46
"[+?If no \afile\a operands are given or if the \afile\a is \b-\b, \bpaste\b "
47
"reads from standard input. The start of the file is defined as the "
48
"current offset.]"
49
50
"[s:serial?Paste the lines of one file at a time rather than one line "
51
"from each file. In this case if the \b-d\b option is "
52
"specified the delimiter will be reset to the first in the "
53
"list at the beginning of each file.]"
54
"[d:delimiters]:[list?\alist\a specifies a list of delimiters. These "
55
"delimiters are used circularly instead of TAB to replace "
56
"the newline character of the input lines. Unless the \b-s\b "
57
"option is specified, the delimiter will be reset to the first "
58
"element of \alist\a each time a line is processed from each file. "
59
"The delimiter characters corresponding to \alist\a will be found "
60
"by treating \alist\a as an ANSI-C string, except that the \b\\0\b "
61
"sequence will insert the empty string instead of the null character.]"
62
"\n"
63
"\n[file ...]\n"
64
"\n"
65
"[+EXIT STATUS?]{"
66
"[+0?All files processed successfully.]"
67
"[+>0?An error occurred.]"
68
"}"
69
"[+SEE ALSO?\bcut\b(1), \bcat\b(1), \bjoin\b(1)]"
70
;
71
72
#include <cmd.h>
73
74
typedef struct Delim_s
75
{
76
const char* chr;
77
size_t len;
78
} Delim_t;
79
80
/*
81
* paste the lines of the <nstreams> defined in <streams> and put results
82
* to <out>
83
*/
84
85
static int paste(int nstream,Sfio_t* streams[],Sfio_t *out, register const char *delim, int dsiz, int dlen, Delim_t* mp)
86
{
87
register const char *cp;
88
register int d, n, i, z, more=1;
89
register Sfio_t *fp;
90
do
91
{
92
d = (dlen>0?0:-1);
93
for(n=more-1,more=0; n < nstream;)
94
{
95
if(fp=streams[n])
96
{
97
if(cp = sfgetr(fp,'\n',0))
98
{
99
if(n==0)
100
more = 1;
101
else if(!more) /* first stream with output */
102
{
103
if(dsiz == 1)
104
sfnputc(out, *delim, n);
105
else if(dlen>0)
106
{
107
for(d=n; d>dlen; d-=dlen)
108
sfwrite(out,delim,dsiz);
109
if(d)
110
{
111
if(mp)
112
for (i = z = 0; i < d; i++)
113
z += mp[i].len;
114
else
115
z = d;
116
sfwrite(out,delim,z);
117
}
118
}
119
more = n+1;
120
}
121
if(sfwrite(out,cp,sfvalue(fp)-((n+1)<nstream)) < 0)
122
return(-1);
123
}
124
else
125
streams[n] = 0;
126
}
127
if(++n<nstream && more && d>=0)
128
{
129
register int c;
130
if(d >= dlen)
131
d = 0;
132
if(mp)
133
sfwrite(out,mp[d].chr,mp[d].len);
134
else if(c=delim[d])
135
sfputc(out,c);
136
d++;
137
}
138
else if(n==nstream && !streams[n-1] && more)
139
sfputc(out,'\n');
140
}
141
} while(more);
142
return(0);
143
}
144
145
/*
146
* Handles paste -s, for file <in> to file <out> using delimiters <delim>
147
*/
148
static int spaste(Sfio_t *in,register Sfio_t* out,register const char *delim,int dsiz,int dlen,Delim_t* mp)
149
{
150
register const char *cp;
151
register int d=0;
152
if((cp = sfgetr(in,'\n',0)) && sfwrite(out,cp,sfvalue(in)-1) < 0)
153
return(-1);
154
while(cp=sfgetr(in, '\n',0))
155
{
156
if(dlen)
157
{
158
register int c;
159
if(d >= dlen)
160
d = 0;
161
if(mp)
162
sfwrite(out,mp[d].chr,mp[d].len);
163
else if(c=delim[d])
164
sfputc(out,c);
165
d++;
166
}
167
if(sfwrite(out,cp,sfvalue(in)-1) < 0)
168
return(-1);
169
}
170
sfputc(out,'\n');
171
return(0);
172
}
173
174
int
175
b_paste(int argc, char** argv, Shbltin_t* context)
176
{
177
register int n, sflag=0;
178
register Sfio_t *fp, **streams;
179
register char *cp, *delim;
180
char *ep;
181
Delim_t *mp;
182
int dlen, dsiz;
183
char defdelim[2];
184
185
cmdinit(argc, argv, context, ERROR_CATALOG, 0);
186
delim = 0;
187
for (;;)
188
{
189
switch (optget(argv, usage))
190
{
191
case 'd':
192
delim = opt_info.arg;
193
continue;
194
case 's':
195
sflag++;
196
continue;
197
case ':':
198
error(2, "%s", opt_info.arg);
199
break;
200
case '?':
201
error(ERROR_usage(2), "%s", opt_info.arg);
202
break;
203
}
204
break;
205
}
206
argv += opt_info.index;
207
if(error_info.errors)
208
error(ERROR_usage(2),"%s", optusage(NiL));
209
if(!delim || !*delim)
210
{
211
delim = defdelim;
212
delim[0] = '\t';
213
delim[1] = 0;
214
}
215
if (!(delim = strdup(delim)))
216
error(ERROR_system(1), "out of space");
217
dlen = dsiz = stresc(delim);
218
mp = 0;
219
if (mbwide())
220
{
221
cp = delim;
222
ep = delim + dlen;
223
dlen = 0;
224
while (cp < ep)
225
{
226
mbchar(cp);
227
dlen++;
228
}
229
if(dlen < dsiz)
230
{
231
if (!(mp = newof(0, Delim_t, dlen, 0)))
232
{
233
free(delim);
234
error(ERROR_system(1), "out of space");
235
}
236
cp = delim;
237
dlen = 0;
238
while (cp < ep)
239
{
240
mp[dlen].chr = cp;
241
mbchar(cp);
242
mp[dlen].len = cp - mp[dlen].chr;
243
dlen++;
244
}
245
}
246
}
247
if(cp = *argv)
248
{
249
n = argc - opt_info.index;
250
argv++;
251
}
252
else
253
n = 1;
254
if(!sflag)
255
{
256
if (!(streams = (Sfio_t**)stakalloc(n*sizeof(Sfio_t*))))
257
error(ERROR_exit(1), "out of space");
258
n = 0;
259
}
260
do
261
{
262
if(!cp || streq(cp,"-"))
263
fp = sfstdin;
264
else if(!(fp = sfopen(NiL,cp,"r")))
265
error(ERROR_system(0),"%s: cannot open",cp);
266
if(fp && sflag)
267
{
268
if(spaste(fp,sfstdout,delim,dsiz,dlen,mp) < 0)
269
error(ERROR_system(0),"write failed");
270
if(fp!=sfstdin)
271
sfclose(fp);
272
}
273
else if(!sflag)
274
streams[n++] = fp;
275
} while(cp= *argv++);
276
if(!sflag)
277
{
278
if(error_info.errors==0 && paste(n,streams,sfstdout,delim,dsiz,dlen,mp) < 0)
279
error(ERROR_system(0),"write failed");
280
while(--n>=0)
281
if((fp=streams[n]) && fp!=sfstdin)
282
sfclose(fp);
283
}
284
if (mp)
285
free(mp);
286
free(delim);
287
return(error_info.errors);
288
}
289
290