summaryrefslogtreecommitdiff
path: root/usr/src/lib/libcmd/common/fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libcmd/common/fold.c')
-rw-r--r--usr/src/lib/libcmd/common/fold.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/usr/src/lib/libcmd/common/fold.c b/usr/src/lib/libcmd/common/fold.c
new file mode 100644
index 0000000000..459ad35850
--- /dev/null
+++ b/usr/src/lib/libcmd/common/fold.c
@@ -0,0 +1,242 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1992-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* A copy of the License is available at *
+* http://www.opensource.org/licenses/cpl1.0.txt *
+* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/*
+ * David Korn
+ * AT&T Bell Laboratories
+ *
+ * fold
+ */
+
+static const char usage[] =
+"[-?\n@(#)$Id: fold (AT&T Research) 2004-11-18 $\n]"
+USAGE_LICENSE
+"[+NAME?fold - fold lines]"
+"[+DESCRIPTION?\bfold\b is a filter that folds lines from its input, "
+ "breaking the lines to have a maximum of \awidth\a column "
+ "positions (or bytes if the \b-b\b option is specified). Lines "
+ "are broken by the insertion of a newline character such that "
+ "each output line is the maximum width possible that does not "
+ "exceed the specified number of column positions, (or bytes). A line "
+ "will not be broken in the middle of a character.] "
+"[+?Unless the \b-b\b option is specified, the following will be treated "
+ "specially:]{"
+ "[+carriage-return?The current count of line width will be set "
+ "to zero. \bfold\b will not insert a newline immediately "
+ "before or after a carriage-return.]"
+ "[+backspace?If positive, the current count of line width will be "
+ "decremented by one. \bfold\b will not insert a newline "
+ "immediately before or after a backspace.]"
+ "[+tab?Each tab character encountered will advance the column "
+ "position to the next tab stop. Tab stops are at each "
+ "column position \an\a, where \an\a modulo 8 equals 1.]"
+ "}"
+"[+?If no \afile\a is given, or if the \afile\a is \b-\b, \bfold\b "
+ "reads from standard input. The start of the file is defined "
+ "as the current offset.]"
+
+"[b:bytes?Count bytes rather than columns so that each carriage-return, "
+ "backspace, and tab counts as 1.]"
+"[c:continue?Emit \atext\a at line splits.]:[text:='\\n']"
+"[d:delimiter?Break at \adelim\a boundaries.]:[delim]"
+"[s:spaces?Break at word boundaries. If the line contains any blanks, "
+ "(spaces or tabs), within the first \awidth\a column positions or "
+ "bytes, the line is broken after the last blank meeting the "
+ "\awidth\a constraint.]"
+"[w:width]#[width:=80?Use a maximum line length of \awidth\a columns "
+ "instead of the default.]"
+"\n"
+"\n[file ...]\n"
+"\n"
+"[+EXIT STATUS?]{"
+ "[+0?All files processed successfully.]"
+ "[+>0?An error occurred.]"
+"}"
+"[+SEE ALSO?\bpaste\b(1)]"
+;
+
+
+#include <cmd.h>
+
+#define WIDTH 80
+#define TABSIZE 8
+
+#define T_EOF 1
+#define T_NL 2
+#define T_BS 3
+#define T_TAB 4
+#define T_SP 5
+#define T_RET 6
+
+static void fold(Sfio_t *in, Sfio_t *out, register int width, const char *cont, size_t contsize, char *cols)
+{
+ register char *cp, *first;
+ register int n, col=0, x=0;
+ register char *last_space=0;
+ cols[0] = 0;
+ for (;;)
+ {
+ if (!(cp = sfgetr(in,'\n',0)))
+ {
+ if (!(cp = sfgetr(in,'\n',-1)) || (n = sfvalue(in)) <= 0)
+ break;
+ x = cp[--n];
+ cp[n] = '\n';
+ }
+ /* special case -b since no column adjustment is needed */
+ if(cols['\b']==0 && (n=sfvalue(in))<=width)
+ {
+ sfwrite(out,cp,n);
+ continue;
+ }
+ first = cp;
+ col = 0;
+ last_space = 0;
+ for(;;)
+ {
+ while((n=cols[*(unsigned char*)cp++])==0);
+ while((cp-first) > (width-col))
+ {
+ if(last_space)
+ col = last_space - first;
+ else
+ col = width-col;
+ sfwrite(out,first,col);
+ first += col;
+ col = 0;
+ last_space = 0;
+ if(cp>first+1 || (n!=T_NL && n!=T_BS))
+ sfwrite(out, cont, contsize);
+ }
+ switch(n)
+ {
+ case T_NL:
+ if(x)
+ *(cp-1) = x;
+ break;
+ case T_RET:
+ col = 0;
+ continue;
+ case T_BS:
+ if((cp+(--col)-first)>0)
+ col--;
+ continue;
+ case T_TAB:
+ n = (TABSIZE-1) - (cp+col-1-first)&(TABSIZE-1);
+ col +=n;
+ if((cp-first) > (width-col))
+ {
+ sfwrite(out,first,(--cp)-first);
+ sfwrite(out, cont, contsize);
+ first = cp;
+ col = TABSIZE-1;
+ last_space = 0;
+ continue;
+ }
+ if(cols[' '])
+ last_space = cp;
+ continue;
+ case T_SP:
+ last_space = cp;
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ sfwrite(out,first,cp-first);
+ }
+}
+
+int
+b_fold(int argc, char *argv[], void* context)
+{
+ register int n, width=WIDTH;
+ register Sfio_t *fp;
+ register char *cp;
+ char *cont="\n";
+ size_t contsize = 1;
+ char cols[1<<CHAR_BIT];
+
+ cmdinit(argc, argv, context, ERROR_CATALOG, 0);
+ memset(cols, 0, sizeof(cols));
+ cols['\t'] = T_TAB;
+ cols['\b'] = T_BS;
+ cols['\n'] = T_NL;
+ cols['\r'] = T_RET;
+ for (;;)
+ {
+ switch (optget(argv, usage))
+ {
+ case 0:
+ break;
+ case 'b':
+ cols['\r'] = cols['\b'] = 0;
+ cols['\t'] = cols[' '];
+ continue;
+ case 'c':
+ contsize = stresc(cont = strdup(opt_info.arg));
+ continue;
+ case 'd':
+ if (n = *opt_info.arg)
+ cols[n] = T_SP;
+ continue;
+ case 's':
+ cols[' '] = T_SP;
+ if(cols['\t']==0)
+ cols['\t'] = T_SP;
+ continue;
+ case 'w':
+ if ((width = opt_info.num) <= 0)
+ error(2, "%d: width must be positive", opt_info.num);
+ continue;
+ case ':':
+ error(2, "%s", opt_info.arg);
+ continue;
+ case '?':
+ error(ERROR_usage(2), "%s", opt_info.arg);
+ continue;
+ }
+ break;
+ }
+ argv += opt_info.index;
+ argc -= opt_info.index;
+ if(error_info.errors)
+ error(ERROR_usage(2),"%s", optusage(NiL));
+ if(cp = *argv)
+ argv++;
+ do
+ {
+ if(!cp || streq(cp,"-"))
+ fp = sfstdin;
+ else if(!(fp = sfopen(NiL,cp,"r")))
+ {
+ error(ERROR_system(0),"%s: cannot open",cp);
+ error_info.errors = 1;
+ continue;
+ }
+ fold(fp,sfstdout,width,cont,contsize,cols);
+ if(fp!=sfstdin)
+ sfclose(fp);
+ }
+ while(cp= *argv++);
+ return(error_info.errors);
+}