Skip to content

Instantly share code, notes, and snippets.

@atr000
Created February 5, 2010 01:55
Show Gist options
  • Save atr000/295400 to your computer and use it in GitHub Desktop.
Save atr000/295400 to your computer and use it in GitHub Desktop.
/*
* A word wrapper
* Copyright (C) 2009
* Andreas Harnack (ah8 at freenet dot de)
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this library; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *progname;
int getint(const char* p) { return p ? atoi(p) : 0; }
int getval(int v, int d) { return v > 0 ? v : d; }
int ws(int ch) {
return isspace(ch);
}
void putb(char* buffer, char* end, FILE *out) {
while ( buffer < end ) putc(*buffer++, out);
}
int wordwrap(char *buffer, char *lineend, FILE *in, FILE *out)
{
/* Note: the first character of a line is never being buffered, */
/* the buffer is expected to be of size linelength - 1, */
/* lineend is expected to point at buffer[sizeof(buffer)] */
char *token; /* points to the first character of a buffered token */
char *index; /* points to the position where the next character is */
/* going to be buffered, the current line length is */
/* given by (index-buffer) + 1 */
int ch = 0;
state_0:
/* read white-spaces at the beginning of a line */
/* i.e. before the first character of the first */
/* token has been seen */
if ( (ch = getc(in)) == EOF )
/* line hasn't started yet, no need to terminate one */
return 0;
else if ( ws(ch) )
goto state_0;
else {
/* print first character of token */
putc(ch, out);
/* index is used to count line length */
/* buffer points to the second character in the line */
index = buffer;
goto state_1;
}
state_1:
/* read the first token of a line, it is neither buffered */
/* nor truncated but printed as it is read, only the length */
/* is being counted; it might exceed the line length */
if ( (ch = getc(in)) == EOF ) {
/* terminate line */
putc('\n', out);
return 0;
}
else if ( ws(ch) ) {
/* reserve space for whitespace and check line length*/
if ( ++index < lineend )
/* some space left: continue line */
goto state_2;
else {
/* no space left: terminate line */
putc('\n', out);
goto state_0;
}
}
else {
/* print token character */
putc(ch, out);
/* count line length, stop at line end */
if ( index < lineend )
++index;
goto state_1;
}
state_2:
/* read white-spaces between two tokens, it might be the */
/* end of the line; the output is just behind the previous */
/* token, the index at the beginning of the next (after a */
/* potential separating white-space); there is guarantied */
/* to be space for at least one more character on the */
/* current line */
if ( (ch = getc(in)) == EOF ) {
/* terminate line */
putc('\n', out);
return 0;
}
else if ( ws(ch) )
goto state_2;
else {
/* remember current index */
token = index;
/* buffer token character */
*index++ = ch;
goto state_3;
}
state_3:
/* read subsequent token on the line; the token is */
/* buffered and checked for length, the buffered token */
/* is guarantied to fit on the current line; if the token */
/* exceeds he line length , the line is terminated and the */
/* buffered part printed at the beginning of the next line */
if ( (ch = getc(in)) == EOF ) {
/* print buffered token, terminate line */
putc(' ', out);
putb(token, index, out);
putc('\n', out);
return 0;
}
else if ( ws(ch) ) {
/* print buffered token */
putc(' ', out);
putb(token, index, out);
/* reserve space for whitespace and check line length*/
if ( ++index < lineend )
/* some space left: continue line */
goto state_2;
else {
/* no space left: terminate line */
putc('\n', out);
goto state_0;
}
}
else {
/* check line length */
if ( index < lineend ) {
/* some space left: buffer token character */
*index++ = ch;
goto state_3;
}
else {
/* no space left: terminate line, print token */
putc('\n', out);
putb(token, index, out);
putc(ch, out);
/* adjust index to token length */
index = buffer + (index-token);
goto state_1;
}
}
}
const char *helptext =
" -help: this text\n"
" -<num>: set line width to <num>\n"
;
int main(int argc, char *argv[])
{
char *buffer, *lineend;
int pagewidth = 72;
progname = *argv;
pagewidth = getval(getint(getenv("PAGEWIDTH")), pagewidth);
for( ++argv; *argv!=NULL && **argv=='-'; ++argv) {
if((*((*argv)+1))=='\0')
break; /* stdin */
else if ( strcmp(*argv, "-help") == 0 ) {
fprintf(stdout, helptext);
exit(0);
}
else if ( (pagewidth=atoi(*argv+1)) > 0 )
;
else {
fprintf(stderr, "%s: unknown option: %s\n"
" (see -help for details)\n", progname, *argv);
exit(1);
}
}
buffer = malloc(--pagewidth);
if ( ! buffer ) {
fprintf(stderr, "%s: can't allocate buffer\n", progname);
exit(2);
}
lineend = buffer+pagewidth;
if( *argv == NULL )
return wordwrap(buffer, lineend, stdin, stdout);
else for(; *argv != NULL; argv++) {
int retcode = 0;
FILE *fp;
if ( strcmp(*argv, "-") == 0 )
retcode = wordwrap(buffer, lineend, stdin, stdout);
else if( (fp=fopen(*argv, "r")) != NULL ) {
retcode = wordwrap(buffer, lineend, stdin, stdout);
fclose(fp);
}
else {
fprintf(stderr, "%s: can't open %s\n", progname, *argv);
exit(2);
}
if ( retcode )
return retcode;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment