14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1992-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * * 204887Schin ***********************************************************************/ 214887Schin #pragma prototyped 224887Schin /* 234887Schin * David Korn 244887Schin * AT&T Bell Laboratories 254887Schin * 264887Schin * paste [-s] [-d delim] [file] ... 274887Schin * 284887Schin * paste lines from files together 294887Schin */ 304887Schin 314887Schin static const char usage[] = 32*8462SApril.Chin@Sun.COM "[-?\n@(#)$Id: paste (AT&T Research) 2008-04-01 $\n]" 334887Schin USAGE_LICENSE 344887Schin "[+NAME?paste - merge lines of files]" 354887Schin "[+DESCRIPTION?\bpaste\b concatenates the corresponding lines of a " 364887Schin "given input file and writes the resulting lines to standard " 374887Schin "output. By default \bpaste\b replaces the newline character of " 384887Schin "every line other than the last input file with the TAB character.]" 394887Schin "[+?Unless the \b-s\b option is specified, if an end-of-file is encountered " 404887Schin "on one or more input files, but not all input files, \bpaste\b " 414887Schin "behaves as if empty lines were read from the file(s) on which " 424887Schin "end-of-file was detected.]" 434887Schin "[+?Unless the \b-s\b option is specified, \bpaste\b is limited by " 444887Schin "the underlying operating system on how many \afile\a operands " 454887Schin "can be specified.]" 464887Schin "[+?If no \afile\a operands are given or if the \afile\a is \b-\b, \bpaste\b " 474887Schin "reads from standard input. The start of the file is defined as the " 484887Schin "current offset.]" 494887Schin 504887Schin "[s:serial?Paste the lines of one file at a time rather than one line " 514887Schin "from each file. In this case if the \b-d\b option is " 524887Schin "specified the delimiter will be reset to the first in the " 534887Schin "list at the beginning of each file.]" 544887Schin "[d:delimiters]:[list?\alist\a specifies a list of delimiters. These " 554887Schin "delimiters are used circularly instead of TAB to replace " 564887Schin "the newline character of the input lines. Unless the \b-s\b " 574887Schin "option is specified, the delimiter will be reset to the first " 584887Schin "element of \alist\a each time a line is processed from each file. " 594887Schin "The delimiter characters corresponding to \alist\a will be found " 604887Schin "by treating \alist\a as an ANSI-C string, except that the \b\\0\b " 614887Schin "sequence will insert the empty string instead of the null character.]" 624887Schin "\n" 634887Schin "\n[file ...]\n" 644887Schin "\n" 654887Schin "[+EXIT STATUS?]{" 664887Schin "[+0?All files processed successfully.]" 674887Schin "[+>0?An error occurred.]" 684887Schin "}" 694887Schin "[+SEE ALSO?\bcut\b(1), \bcat\b(1), \bjoin\b(1)]" 704887Schin ; 714887Schin 724887Schin 734887Schin #include <cmd.h> 744887Schin 754887Schin /* 764887Schin * paste the lines of the <nstreams> defined in <streams> and put results 774887Schin * to <out> 784887Schin */ 794887Schin 804887Schin static int paste(int nstream,Sfio_t* streams[],Sfio_t *out, register const char *delim,int dlen) 814887Schin { 824887Schin register const char *cp; 834887Schin register int d, n, more=1; 844887Schin register Sfio_t *fp; 854887Schin do 864887Schin { 874887Schin d = (dlen>0?0:-1); 884887Schin for(n=more-1,more=0; n < nstream;) 894887Schin { 904887Schin if(fp=streams[n]) 914887Schin { 924887Schin if(cp = sfgetr(fp,'\n',0)) 934887Schin { 944887Schin if(n==0) 954887Schin more = 1; 964887Schin else if(!more) /* first stream with output */ 974887Schin { 984887Schin if(dlen==1) 994887Schin sfnputc(out, *delim, n); 1004887Schin else if(dlen>0) 1014887Schin { 1024887Schin for(d=n; d>dlen; d-=dlen) 1034887Schin sfwrite(out,delim,dlen); 1044887Schin if(d) 1054887Schin sfwrite(out,delim,d); 1064887Schin } 1074887Schin more = n+1; 1084887Schin } 1094887Schin if(sfwrite(out,cp,sfvalue(fp)-((n+1)<nstream)) < 0) 1104887Schin return(-1); 1114887Schin } 1124887Schin else 1134887Schin streams[n] = 0; 1144887Schin } 1154887Schin if(++n<nstream && more && d>=0) 1164887Schin { 1174887Schin register int c; 1184887Schin if(d >= dlen) 1194887Schin d = 0; 1204887Schin if(c=delim[d++]) 1214887Schin sfputc(out,c); 1224887Schin } 1234887Schin else if(n==nstream && !streams[n-1] && more) 1244887Schin sfputc(out,'\n'); 1254887Schin } 1264887Schin } 1274887Schin while(more); 1284887Schin return(0); 1294887Schin } 1304887Schin 1314887Schin /* 1324887Schin * Handles paste -s, for file <in> to file <out> using delimiters <delim> 1334887Schin */ 1344887Schin static int spaste(Sfio_t *in,register Sfio_t* out,register const char *delim,int dlen) 1354887Schin { 1364887Schin register const char *cp; 1374887Schin register int d=0; 1384887Schin if(cp = sfgetr(in,'\n',0)) 1394887Schin { 1404887Schin if(sfwrite(out,cp,sfvalue(in)-1) < 0) 1414887Schin return(-1); 1424887Schin } 1434887Schin while(cp=sfgetr(in, '\n',0)) 1444887Schin { 1454887Schin if(dlen) 1464887Schin { 1474887Schin register int c; 1484887Schin if(d >= dlen) 1494887Schin d = 0; 1504887Schin if(c=delim[d++]) 1514887Schin sfputc(out,c); 1524887Schin } 1534887Schin if(sfwrite(out,cp,sfvalue(in)-1) < 0) 1544887Schin return(-1); 1554887Schin } 1564887Schin sfputc(out,'\n'); 1574887Schin return(0); 1584887Schin } 1594887Schin 1604887Schin int 1614887Schin b_paste(int argc,register char *argv[], void* context) 1624887Schin { 1634887Schin register int n, sflag=0; 1644887Schin register Sfio_t *fp, **streams; 1654887Schin register char *cp, *delim; 1664887Schin int dlen; 1674887Schin char defdelim[2]; 1684887Schin 1694887Schin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 1704887Schin delim = 0; 1714887Schin while (n = optget(argv, usage)) switch (n) 1724887Schin { 1734887Schin case 'd': 1744887Schin delim = opt_info.arg; 1754887Schin break; 1764887Schin case 's': 1774887Schin sflag++; 1784887Schin break; 1794887Schin case ':': 1804887Schin error(2, "%s", opt_info.arg); 1814887Schin break; 1824887Schin case '?': 1834887Schin error(ERROR_usage(2), "%s", opt_info.arg); 1844887Schin break; 1854887Schin } 1864887Schin argv += opt_info.index; 1874887Schin if(error_info.errors) 1884887Schin error(ERROR_usage(2),"%s", optusage(NiL)); 1894887Schin if(delim) 1904887Schin dlen = stresc(delim); 1914887Schin else 1924887Schin { 1934887Schin *(delim = defdelim) = '\t'; 1944887Schin dlen = 1; 1954887Schin } 1964887Schin if(cp = *argv) 1974887Schin { 1984887Schin n = argc - opt_info.index; 1994887Schin argv++; 2004887Schin } 2014887Schin else 2024887Schin n = 1; 2034887Schin if(!sflag) 2044887Schin { 2054887Schin if (!(streams = (Sfio_t**)stakalloc(n*sizeof(Sfio_t*)))) 2064887Schin error(ERROR_exit(1), "out of space"); 2074887Schin n = 0; 2084887Schin } 2094887Schin do 2104887Schin { 2114887Schin if(!cp || streq(cp,"-")) 2124887Schin fp = sfstdin; 2134887Schin else if(!(fp = sfopen(NiL,cp,"r"))) 2144887Schin error(ERROR_system(0),"%s: cannot open",cp); 2154887Schin if(fp && sflag) 2164887Schin { 2174887Schin if(spaste(fp,sfstdout,delim,dlen) < 0) 2184887Schin error(ERROR_system(0),"write failed"); 2194887Schin if(fp!=sfstdin) 2204887Schin sfclose(fp); 2214887Schin } 222*8462SApril.Chin@Sun.COM else if(!sflag) 2234887Schin streams[n++] = fp; 224*8462SApril.Chin@Sun.COM } while(cp= *argv++); 2254887Schin if(!sflag) 2264887Schin { 2274887Schin if(error_info.errors==0 && paste(n,streams,sfstdout,delim,dlen) < 0) 2284887Schin error(ERROR_system(0),"write failed"); 2294887Schin while(--n>=0) 2304887Schin if((fp=streams[n]) && fp!=sfstdin) 2314887Schin sfclose(fp); 2324887Schin } 2334887Schin return(error_info.errors); 2344887Schin } 2354887Schin 236