1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1992-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * *
20da2e3ebdSchin ***********************************************************************/
21da2e3ebdSchin #pragma prototyped
22da2e3ebdSchin /*
23da2e3ebdSchin * David Korn
24da2e3ebdSchin * AT&T Bell Laboratories
25da2e3ebdSchin *
26da2e3ebdSchin * fold
27da2e3ebdSchin */
28da2e3ebdSchin
29da2e3ebdSchin static const char usage[] =
30da2e3ebdSchin "[-?\n@(#)$Id: fold (AT&T Research) 2004-11-18 $\n]"
31da2e3ebdSchin USAGE_LICENSE
32da2e3ebdSchin "[+NAME?fold - fold lines]"
33da2e3ebdSchin "[+DESCRIPTION?\bfold\b is a filter that folds lines from its input, "
34da2e3ebdSchin "breaking the lines to have a maximum of \awidth\a column "
35da2e3ebdSchin "positions (or bytes if the \b-b\b option is specified). Lines "
36da2e3ebdSchin "are broken by the insertion of a newline character such that "
37da2e3ebdSchin "each output line is the maximum width possible that does not "
38da2e3ebdSchin "exceed the specified number of column positions, (or bytes). A line "
39da2e3ebdSchin "will not be broken in the middle of a character.] "
40da2e3ebdSchin "[+?Unless the \b-b\b option is specified, the following will be treated "
41da2e3ebdSchin "specially:]{"
42da2e3ebdSchin "[+carriage-return?The current count of line width will be set "
43da2e3ebdSchin "to zero. \bfold\b will not insert a newline immediately "
44da2e3ebdSchin "before or after a carriage-return.]"
45da2e3ebdSchin "[+backspace?If positive, the current count of line width will be "
46da2e3ebdSchin "decremented by one. \bfold\b will not insert a newline "
47da2e3ebdSchin "immediately before or after a backspace.]"
48da2e3ebdSchin "[+tab?Each tab character encountered will advance the column "
49da2e3ebdSchin "position to the next tab stop. Tab stops are at each "
50da2e3ebdSchin "column position \an\a, where \an\a modulo 8 equals 1.]"
51da2e3ebdSchin "}"
52da2e3ebdSchin "[+?If no \afile\a is given, or if the \afile\a is \b-\b, \bfold\b "
53da2e3ebdSchin "reads from standard input. The start of the file is defined "
54da2e3ebdSchin "as the current offset.]"
55da2e3ebdSchin
56da2e3ebdSchin "[b:bytes?Count bytes rather than columns so that each carriage-return, "
57da2e3ebdSchin "backspace, and tab counts as 1.]"
58da2e3ebdSchin "[c:continue?Emit \atext\a at line splits.]:[text:='\\n']"
59da2e3ebdSchin "[d:delimiter?Break at \adelim\a boundaries.]:[delim]"
60da2e3ebdSchin "[s:spaces?Break at word boundaries. If the line contains any blanks, "
61da2e3ebdSchin "(spaces or tabs), within the first \awidth\a column positions or "
62da2e3ebdSchin "bytes, the line is broken after the last blank meeting the "
63da2e3ebdSchin "\awidth\a constraint.]"
64da2e3ebdSchin "[w:width]#[width:=80?Use a maximum line length of \awidth\a columns "
65da2e3ebdSchin "instead of the default.]"
66da2e3ebdSchin "\n"
67da2e3ebdSchin "\n[file ...]\n"
68da2e3ebdSchin "\n"
69da2e3ebdSchin "[+EXIT STATUS?]{"
70da2e3ebdSchin "[+0?All files processed successfully.]"
71da2e3ebdSchin "[+>0?An error occurred.]"
72da2e3ebdSchin "}"
73da2e3ebdSchin "[+SEE ALSO?\bpaste\b(1)]"
74da2e3ebdSchin ;
75da2e3ebdSchin
76da2e3ebdSchin
77da2e3ebdSchin #include <cmd.h>
78da2e3ebdSchin
79da2e3ebdSchin #define WIDTH 80
80da2e3ebdSchin #define TABSIZE 8
81da2e3ebdSchin
82da2e3ebdSchin #define T_EOF 1
83da2e3ebdSchin #define T_NL 2
84da2e3ebdSchin #define T_BS 3
85da2e3ebdSchin #define T_TAB 4
86da2e3ebdSchin #define T_SP 5
87da2e3ebdSchin #define T_RET 6
88da2e3ebdSchin
fold(Sfio_t * in,Sfio_t * out,register int width,const char * cont,size_t contsize,char * cols)89da2e3ebdSchin static void fold(Sfio_t *in, Sfio_t *out, register int width, const char *cont, size_t contsize, char *cols)
90da2e3ebdSchin {
91da2e3ebdSchin register char *cp, *first;
92da2e3ebdSchin register int n, col=0, x=0;
93da2e3ebdSchin register char *last_space=0;
94da2e3ebdSchin cols[0] = 0;
95da2e3ebdSchin for (;;)
96da2e3ebdSchin {
97da2e3ebdSchin if (!(cp = sfgetr(in,'\n',0)))
98da2e3ebdSchin {
99da2e3ebdSchin if (!(cp = sfgetr(in,'\n',-1)) || (n = sfvalue(in)) <= 0)
100da2e3ebdSchin break;
101da2e3ebdSchin x = cp[--n];
102da2e3ebdSchin cp[n] = '\n';
103da2e3ebdSchin }
104da2e3ebdSchin /* special case -b since no column adjustment is needed */
105da2e3ebdSchin if(cols['\b']==0 && (n=sfvalue(in))<=width)
106da2e3ebdSchin {
107da2e3ebdSchin sfwrite(out,cp,n);
108da2e3ebdSchin continue;
109da2e3ebdSchin }
110da2e3ebdSchin first = cp;
111da2e3ebdSchin col = 0;
112da2e3ebdSchin last_space = 0;
113da2e3ebdSchin for(;;)
114da2e3ebdSchin {
115da2e3ebdSchin while((n=cols[*(unsigned char*)cp++])==0);
116da2e3ebdSchin while((cp-first) > (width-col))
117da2e3ebdSchin {
118da2e3ebdSchin if(last_space)
119da2e3ebdSchin col = last_space - first;
120da2e3ebdSchin else
121da2e3ebdSchin col = width-col;
122da2e3ebdSchin sfwrite(out,first,col);
123da2e3ebdSchin first += col;
124da2e3ebdSchin col = 0;
125da2e3ebdSchin last_space = 0;
126da2e3ebdSchin if(cp>first+1 || (n!=T_NL && n!=T_BS))
127da2e3ebdSchin sfwrite(out, cont, contsize);
128da2e3ebdSchin }
129da2e3ebdSchin switch(n)
130da2e3ebdSchin {
131da2e3ebdSchin case T_NL:
132da2e3ebdSchin if(x)
133da2e3ebdSchin *(cp-1) = x;
134da2e3ebdSchin break;
135da2e3ebdSchin case T_RET:
136da2e3ebdSchin col = 0;
137da2e3ebdSchin continue;
138da2e3ebdSchin case T_BS:
139da2e3ebdSchin if((cp+(--col)-first)>0)
140da2e3ebdSchin col--;
141da2e3ebdSchin continue;
142da2e3ebdSchin case T_TAB:
143da2e3ebdSchin n = (TABSIZE-1) - (cp+col-1-first)&(TABSIZE-1);
144da2e3ebdSchin col +=n;
145da2e3ebdSchin if((cp-first) > (width-col))
146da2e3ebdSchin {
147da2e3ebdSchin sfwrite(out,first,(--cp)-first);
148da2e3ebdSchin sfwrite(out, cont, contsize);
149da2e3ebdSchin first = cp;
150da2e3ebdSchin col = TABSIZE-1;
151da2e3ebdSchin last_space = 0;
152da2e3ebdSchin continue;
153da2e3ebdSchin }
154da2e3ebdSchin if(cols[' '])
155da2e3ebdSchin last_space = cp;
156da2e3ebdSchin continue;
157da2e3ebdSchin case T_SP:
158da2e3ebdSchin last_space = cp;
159da2e3ebdSchin continue;
160da2e3ebdSchin default:
161da2e3ebdSchin continue;
162da2e3ebdSchin }
163da2e3ebdSchin break;
164da2e3ebdSchin }
165da2e3ebdSchin sfwrite(out,first,cp-first);
166da2e3ebdSchin }
167da2e3ebdSchin }
168da2e3ebdSchin
169da2e3ebdSchin int
b_fold(int argc,char * argv[],void * context)170da2e3ebdSchin b_fold(int argc, char *argv[], void* context)
171da2e3ebdSchin {
172da2e3ebdSchin register int n, width=WIDTH;
173da2e3ebdSchin register Sfio_t *fp;
174da2e3ebdSchin register char *cp;
175da2e3ebdSchin char *cont="\n";
176da2e3ebdSchin size_t contsize = 1;
177da2e3ebdSchin char cols[1<<CHAR_BIT];
178da2e3ebdSchin
179da2e3ebdSchin cmdinit(argc, argv, context, ERROR_CATALOG, 0);
180da2e3ebdSchin memset(cols, 0, sizeof(cols));
181da2e3ebdSchin cols['\t'] = T_TAB;
182da2e3ebdSchin cols['\b'] = T_BS;
183da2e3ebdSchin cols['\n'] = T_NL;
184da2e3ebdSchin cols['\r'] = T_RET;
185da2e3ebdSchin for (;;)
186da2e3ebdSchin {
187da2e3ebdSchin switch (optget(argv, usage))
188da2e3ebdSchin {
189da2e3ebdSchin case 0:
190da2e3ebdSchin break;
191da2e3ebdSchin case 'b':
192da2e3ebdSchin cols['\r'] = cols['\b'] = 0;
193da2e3ebdSchin cols['\t'] = cols[' '];
194da2e3ebdSchin continue;
195da2e3ebdSchin case 'c':
196da2e3ebdSchin contsize = stresc(cont = strdup(opt_info.arg));
197da2e3ebdSchin continue;
198da2e3ebdSchin case 'd':
199da2e3ebdSchin if (n = *opt_info.arg)
200da2e3ebdSchin cols[n] = T_SP;
201da2e3ebdSchin continue;
202da2e3ebdSchin case 's':
203da2e3ebdSchin cols[' '] = T_SP;
204da2e3ebdSchin if(cols['\t']==0)
205da2e3ebdSchin cols['\t'] = T_SP;
206da2e3ebdSchin continue;
207da2e3ebdSchin case 'w':
208da2e3ebdSchin if ((width = opt_info.num) <= 0)
209da2e3ebdSchin error(2, "%d: width must be positive", opt_info.num);
210da2e3ebdSchin continue;
211da2e3ebdSchin case ':':
212da2e3ebdSchin error(2, "%s", opt_info.arg);
213da2e3ebdSchin continue;
214da2e3ebdSchin case '?':
215da2e3ebdSchin error(ERROR_usage(2), "%s", opt_info.arg);
216da2e3ebdSchin continue;
217da2e3ebdSchin }
218da2e3ebdSchin break;
219da2e3ebdSchin }
220da2e3ebdSchin argv += opt_info.index;
221da2e3ebdSchin argc -= opt_info.index;
222da2e3ebdSchin if(error_info.errors)
223da2e3ebdSchin error(ERROR_usage(2),"%s", optusage(NiL));
224da2e3ebdSchin if(cp = *argv)
225da2e3ebdSchin argv++;
226da2e3ebdSchin do
227da2e3ebdSchin {
228da2e3ebdSchin if(!cp || streq(cp,"-"))
229da2e3ebdSchin fp = sfstdin;
230da2e3ebdSchin else if(!(fp = sfopen(NiL,cp,"r")))
231da2e3ebdSchin {
232da2e3ebdSchin error(ERROR_system(0),"%s: cannot open",cp);
233da2e3ebdSchin error_info.errors = 1;
234da2e3ebdSchin continue;
235da2e3ebdSchin }
236da2e3ebdSchin fold(fp,sfstdout,width,cont,contsize,cols);
237da2e3ebdSchin if(fp!=sfstdin)
238da2e3ebdSchin sfclose(fp);
239da2e3ebdSchin }
240da2e3ebdSchin while(cp= *argv++);
241da2e3ebdSchin return(error_info.errors);
242da2e3ebdSchin }
243