<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf8">
<title>/usr/web/sources/contrib/mjl/nfmt.c - Plan 9 from Bell Labs</title>
<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
<!-- EDIT sources.tr INSTEAD. -->
</meta>
</head>
<body>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /usr/web/sources/contrib/mjl/nfmt.c</span></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
Copyright © 2009 Alcatel-Lucent.<br />
Distributed under the
<a href="/plan9/license.html">Lucent Public License version 1.02</a>.
<br />
<a href="/plan9/download.html">Download the Plan 9 distribution.</a>
</font>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<table width="100%" cellspacing=0 border=0><tr><td align="center">
<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
<pre>
<!-- END HEADER -->
/*
8c -Fw nfmt.c &amp;&amp; 8l -o /386/bin/nfmt nfmt.8

make lists more readable.  lists start with "* " or "- ".  indent the
lines following the first with two more spaces after the usual indent.
*/
#include &lt;u.h&gt;
#include &lt;libc.h&gt;
#include &lt;bio.h&gt;
#include &lt;ctype.h&gt;

/*
 * block up paragraphs, possibly with indentation
 */

int extraindent = 0;		/* how many spaces to indent all lines */
int indent = 0;			/* current value of indent, before extra indent */
int length = 70;		/* how many columns per output line */
int join = 1;			/* can lines be joined? */
int maxtab = 8;
Biobuf bin;
Biobuf bout;

typedef struct Word Word;
struct Word{
	int	bol;
	int	indent;
	int	issoft;	/* different indent from previous word should not break line */
	char	text[1];
};

void	fmt(void);

void
usage(void)
{
	fprint(2, "usage: %s [-j] [-i indent] [-l length] [file...]\n", argv0);
	exits("usage");
}

void
main(int argc, char **argv)
{
	int i, f;
	char *s, *err;

	ARGBEGIN{
	case 'i':
		extraindent = atoi(EARGF(usage()));
		break;
	case 'j':
		join = 0;
		break;
	case 'w':
	case 'l':
		length = atoi(EARGF(usage()));
		break;
	default:
		usage();
	}ARGEND

	if(length &lt;= indent){
		fprint(2, "%s: line length&lt;=indentation\n", argv0);
		exits("length");
	}

	s=getenv("tabstop");
	if(s!=nil &amp;&amp; atoi(s)&gt;0)
		maxtab=atoi(s);
	err = nil;
	Binit(&amp;bout, 1, OWRITE);
	if(argc &lt;= 0){
		Binit(&amp;bin, 0, OREAD);
		fmt();
	}else{
		for(i=0; i&lt;argc; i++){
			f = open(argv[i], OREAD);
			if(f &lt; 0){
				fprint(2, "%s: can't open %s: %r\n", argv0, argv[i]);
				err = "open";
			}else{
				Binit(&amp;bin, f, OREAD);
				fmt();
				Bterm(&amp;bin);
				if(i != argc-1)
					Bputc(&amp;bout, '\n');
			}
		}
	}
	exits(err);
}

int
indentof(char **linep, int *ind1)
{
	int i, ind;
	char *line;
	char *p;

	ind = 0;
	line = *linep;
	for(i=0; line[i]; i++)
		switch(line[i]){
		default:
			*ind1 = ind;
			if(strncmp(line+i, "- ", 2) == 0 || strncmp(line+i, "* ", 2) == 0) {
				ind += 2;
			} else {
				strtol(line+i, &amp;p, 10);
				if(p &gt; line+i &amp;&amp; strncmp(p, ". ", 2) == 0)
					ind += p-(line+i)+3;
			}
			*linep = line;
			return ind;
		case ' ':
			ind++;
			break;
		case '\t':
			ind += maxtab;
			ind -= ind%maxtab;
			break;
		}
			
	/* plain white space doesn't change the indent */
	*linep = "";
	*ind1 = indent;
	return indent;
}

Word**
addword(Word **words, int *nwordp, char *s, int l, int indent, int issoft, int bol)
{
	Word *w;

	w = malloc(sizeof(Word)+l+1);
	memmove(w-&gt;text, s, l);
	w-&gt;text[l] = '\0';
	w-&gt;indent = indent;
	w-&gt;issoft = issoft;
	w-&gt;bol = bol;
	words = realloc(words, (*nwordp+1)*sizeof(Word*));
	words[(*nwordp)++] = w;
	return words;
}

Word**
parseline(char *line, Word **words, int *nwordp)
{
	int ind, l, bol, issoft, n;

	ind = indentof(&amp;line, &amp;indent);
	issoft = ind != indent;
	bol = 1;
	n = 0;
	for(;;){
		/* find next word */
		while(*line==' ' || *line=='\t')
			line++;
		if(*line == '\0'){
			if(bol)
				return addword(words, nwordp, "", 0, -1, 0, bol);
			break;
		}
		/* how long is this word? */
		for(l=0; line[l]; l++)
			if(line[l]==' ' || line[l]=='\t')
				break;
		words = addword(words, nwordp, line, l, indent, n != 0 &amp;&amp; issoft, bol);
		bol = 0;
		line += l;
		indent = ind;
		n++;
	}
	return words;
}

void
printindent(int w)
{
	while(w &gt;= maxtab){
		Bputc(&amp;bout, '\t');
		w -= maxtab;
	}
	while(w &gt; 0){
		Bputc(&amp;bout, ' ');
		w--;
	}
}

/* give extra space if word ends with period, etc. */
int
nspaceafter(char *s)
{
	int n;

	n = strlen(s);
	if(n &lt; 2)
		return 1;
	if(isupper(s[0]) &amp;&amp; n &lt; 4)
		return 1;
	if(strchr(".!?", s[n-1]) != nil)
		return 2;
	return 1;
}
	

void
printwords(Word **w, int nw)
{
	int i, j, n, col, nsp;

	/* one output line per loop */
	for(i=0; i&lt;nw; ){
		/* if it's a blank line, print it */
		if(w[i]-&gt;indent == -1){
			Bputc(&amp;bout, '\n');
			if(++i == nw)	/* out of words */
				break;
		}
		/* emit leading indent */
		col = extraindent+w[i]-&gt;indent;
		printindent(col);
		/* emit words until overflow; always emit at least one word */
		for(n=0;; n++){
			Bprint(&amp;bout, "%s", w[i]-&gt;text);
			col += utflen(w[i]-&gt;text);
			if(++i == nw)
				break;	/* out of words */
			if(w[i]-&gt;indent != w[i-1]-&gt;indent &amp;&amp; !w[i]-&gt;issoft)
				break;	/* indent change */
			nsp = nspaceafter(w[i-1]-&gt;text);
			if(col+nsp+utflen(w[i]-&gt;text) &gt; extraindent+length)
				break;	/* fold line */
			if(!join &amp;&amp; w[i]-&gt;bol)
				break;
			for(j=0; j&lt;nsp; j++)
				Bputc(&amp;bout, ' ');	/* emit space; another word will follow */
			col += nsp;
		}
		/* emit newline */
		Bputc(&amp;bout, '\n');
	}
}

void
fmt(void)
{
	char *s;
	int i, nw;
	Word **w;

	nw = 0;
	w = nil;
	while((s = Brdstr(&amp;bin, '\n', 1)) != nil){
		w = parseline(s, w, &amp;nw);
		free(s);
	}
	printwords(w, nw);
	for(i=0; i&lt;nw; i++)
		free(w[i]);
	free(w);
}
<!-- BEGIN TAIL -->
</pre>
</td></tr></table>
</td></tr></table>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"></span></p>
<p style="margin-top: 0; margin-bottom: 0.50in"></p>
<p style="margin-top: 0; margin-bottom: 0.33in"></p>
<center><table border="0"><tr>
<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
</a></td>
<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
</a></td>
<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
</td>
</tr></table></center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center>
<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
<span style="font-size: 10pt">All Rights Reserved.</span>
<br />
<span style="font-size: 10pt">Comments to</span>
<span style="font-size: 10pt"><a href="mailto:webmaster@plan9.bell-labs.com">webmaster@plan9.bell-labs.com</a>.</span>
</font></center>
</body>
</html>

