14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1992-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.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 * fold
274887Schin */
284887Schin
294887Schin static const char usage[] =
304887Schin "[-?\n@(#)$Id: fold (AT&T Research) 2004-11-18 $\n]"
314887Schin USAGE_LICENSE
324887Schin "[+NAME?fold - fold lines]"
334887Schin "[+DESCRIPTION?\bfold\b is a filter that folds lines from its input, "
344887Schin "breaking the lines to have a maximum of \awidth\a column "
354887Schin "positions (or bytes if the \b-b\b option is specified). Lines "
364887Schin "are broken by the insertion of a newline character such that "
374887Schin "each output line is the maximum width possible that does not "
384887Schin "exceed the specified number of column positions, (or bytes). A line "
394887Schin "will not be broken in the middle of a character.] "
404887Schin "[+?Unless the \b-b\b option is specified, the following will be treated "
414887Schin "specially:]{"
424887Schin "[+carriage-return?The current count of line width will be set "
434887Schin "to zero. \bfold\b will not insert a newline immediately "
444887Schin "before or after a carriage-return.]"
454887Schin "[+backspace?If positive, the current count of line width will be "
464887Schin "decremented by one. \bfold\b will not insert a newline "
474887Schin "immediately before or after a backspace.]"
484887Schin "[+tab?Each tab character encountered will advance the column "
494887Schin "position to the next tab stop. Tab stops are at each "
504887Schin "column position \an\a, where \an\a modulo 8 equals 1.]"
514887Schin "}"
524887Schin "[+?If no \afile\a is given, or if the \afile\a is \b-\b, \bfold\b "
534887Schin "reads from standard input. The start of the file is defined "
544887Schin "as the current offset.]"
554887Schin
564887Schin "[b:bytes?Count bytes rather than columns so that each carriage-return, "
574887Schin "backspace, and tab counts as 1.]"
584887Schin "[c:continue?Emit \atext\a at line splits.]:[text:='\\n']"
594887Schin "[d:delimiter?Break at \adelim\a boundaries.]:[delim]"
604887Schin "[s:spaces?Break at word boundaries. If the line contains any blanks, "
614887Schin "(spaces or tabs), within the first \awidth\a column positions or "
624887Schin "bytes, the line is broken after the last blank meeting the "
634887Schin "\awidth\a constraint.]"
644887Schin "[w:width]#[width:=80?Use a maximum line length of \awidth\a columns "
654887Schin "instead of the default.]"
664887Schin "\n"
674887Schin "\n[file ...]\n"
684887Schin "\n"
694887Schin "[+EXIT STATUS?]{"
704887Schin "[+0?All files processed successfully.]"
714887Schin "[+>0?An error occurred.]"
724887Schin "}"
734887Schin "[+SEE ALSO?\bpaste\b(1)]"
744887Schin ;
754887Schin
764887Schin
774887Schin #include <cmd.h>
784887Schin
794887Schin #define WIDTH 80
804887Schin #define TABSIZE 8
814887Schin
824887Schin #define T_EOF 1
834887Schin #define T_NL 2
844887Schin #define T_BS 3
854887Schin #define T_TAB 4
864887Schin #define T_SP 5
874887Schin #define T_RET 6
884887Schin
fold(Sfio_t * in,Sfio_t * out,register int width,const char * cont,size_t contsize,char * cols)894887Schin static void fold(Sfio_t *in, Sfio_t *out, register int width, const char *cont, size_t contsize, char *cols)
904887Schin {
914887Schin register char *cp, *first;
924887Schin register int n, col=0, x=0;
934887Schin register char *last_space=0;
944887Schin cols[0] = 0;
954887Schin for (;;)
964887Schin {
974887Schin if (!(cp = sfgetr(in,'\n',0)))
984887Schin {
994887Schin if (!(cp = sfgetr(in,'\n',-1)) || (n = sfvalue(in)) <= 0)
1004887Schin break;
1014887Schin x = cp[--n];
1024887Schin cp[n] = '\n';
1034887Schin }
1044887Schin /* special case -b since no column adjustment is needed */
1054887Schin if(cols['\b']==0 && (n=sfvalue(in))<=width)
1064887Schin {
1074887Schin sfwrite(out,cp,n);
1084887Schin continue;
1094887Schin }
1104887Schin first = cp;
1114887Schin col = 0;
1124887Schin last_space = 0;
1134887Schin for(;;)
1144887Schin {
1154887Schin while((n=cols[*(unsigned char*)cp++])==0);
1164887Schin while((cp-first) > (width-col))
1174887Schin {
1184887Schin if(last_space)
1194887Schin col = last_space - first;
1204887Schin else
1214887Schin col = width-col;
1224887Schin sfwrite(out,first,col);
1234887Schin first += col;
1244887Schin col = 0;
1254887Schin last_space = 0;
1264887Schin if(cp>first+1 || (n!=T_NL && n!=T_BS))
1274887Schin sfwrite(out, cont, contsize);
1284887Schin }
1294887Schin switch(n)
1304887Schin {
1314887Schin case T_NL:
1324887Schin if(x)
1334887Schin *(cp-1) = x;
1344887Schin break;
1354887Schin case T_RET:
1364887Schin col = 0;
1374887Schin continue;
1384887Schin case T_BS:
1394887Schin if((cp+(--col)-first)>0)
1404887Schin col--;
1414887Schin continue;
1424887Schin case T_TAB:
1434887Schin n = (TABSIZE-1) - (cp+col-1-first)&(TABSIZE-1);
1444887Schin col +=n;
1454887Schin if((cp-first) > (width-col))
1464887Schin {
1474887Schin sfwrite(out,first,(--cp)-first);
1484887Schin sfwrite(out, cont, contsize);
1494887Schin first = cp;
1504887Schin col = TABSIZE-1;
1514887Schin last_space = 0;
1524887Schin continue;
1534887Schin }
1544887Schin if(cols[' '])
1554887Schin last_space = cp;
1564887Schin continue;
1574887Schin case T_SP:
1584887Schin last_space = cp;
1594887Schin continue;
1604887Schin default:
1614887Schin continue;
1624887Schin }
1634887Schin break;
1644887Schin }
1654887Schin sfwrite(out,first,cp-first);
1664887Schin }
1674887Schin }
1684887Schin
1694887Schin int
b_fold(int argc,char * argv[],void * context)1704887Schin b_fold(int argc, char *argv[], void* context)
1714887Schin {
1724887Schin register int n, width=WIDTH;
1734887Schin register Sfio_t *fp;
1744887Schin register char *cp;
1754887Schin char *cont="\n";
1764887Schin size_t contsize = 1;
1774887Schin char cols[1<<CHAR_BIT];
1784887Schin
1794887Schin cmdinit(argc, argv, context, ERROR_CATALOG, 0);
1804887Schin memset(cols, 0, sizeof(cols));
1814887Schin cols['\t'] = T_TAB;
1824887Schin cols['\b'] = T_BS;
1834887Schin cols['\n'] = T_NL;
1844887Schin cols['\r'] = T_RET;
1854887Schin for (;;)
1864887Schin {
1874887Schin switch (optget(argv, usage))
1884887Schin {
1894887Schin case 0:
1904887Schin break;
1914887Schin case 'b':
1924887Schin cols['\r'] = cols['\b'] = 0;
1934887Schin cols['\t'] = cols[' '];
1944887Schin continue;
1954887Schin case 'c':
1964887Schin contsize = stresc(cont = strdup(opt_info.arg));
1974887Schin continue;
1984887Schin case 'd':
1994887Schin if (n = *opt_info.arg)
2004887Schin cols[n] = T_SP;
2014887Schin continue;
2024887Schin case 's':
2034887Schin cols[' '] = T_SP;
2044887Schin if(cols['\t']==0)
2054887Schin cols['\t'] = T_SP;
2064887Schin continue;
2074887Schin case 'w':
2084887Schin if ((width = opt_info.num) <= 0)
2094887Schin error(2, "%d: width must be positive", opt_info.num);
2104887Schin continue;
2114887Schin case ':':
2124887Schin error(2, "%s", opt_info.arg);
2134887Schin continue;
2144887Schin case '?':
2154887Schin error(ERROR_usage(2), "%s", opt_info.arg);
2164887Schin continue;
2174887Schin }
2184887Schin break;
2194887Schin }
2204887Schin argv += opt_info.index;
2214887Schin argc -= opt_info.index;
2224887Schin if(error_info.errors)
2234887Schin error(ERROR_usage(2),"%s", optusage(NiL));
2244887Schin if(cp = *argv)
2254887Schin argv++;
2264887Schin do
2274887Schin {
2284887Schin if(!cp || streq(cp,"-"))
2294887Schin fp = sfstdin;
2304887Schin else if(!(fp = sfopen(NiL,cp,"r")))
2314887Schin {
2324887Schin error(ERROR_system(0),"%s: cannot open",cp);
2334887Schin error_info.errors = 1;
2344887Schin continue;
2354887Schin }
2364887Schin fold(fp,sfstdout,width,cont,contsize,cols);
2374887Schin if(fp!=sfstdin)
2384887Schin sfclose(fp);
2394887Schin }
2404887Schin while(cp= *argv++);
2414887Schin return(error_info.errors);
2424887Schin }
243