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