Blame src/lib/libcmd/fold.c

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