1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*7c2fbfb3SApril Chin * Copyright (c) 1992-2008 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 7*7c2fbfb3SApril 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 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 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