Hi, everyone.
I am writing a word-wrapping program. The idea is that it will read in text, and ensure that no output line is longer than a given limit. Where a line of text contains at least one space, it will split the line at the rightmost space. If the line contains no spaces, it will hyphenate and split the line.
I'm doing this as an exercise, based on (but not identical to) exercise 1-22 of K&R.
This is my present effort. I wanted to implement it in such a way as never to waste storage space by buffering text that need not be buffered. Note that subsequent_word_handler() is still buggy. I simply want to know: Is this approach a good thing? Or should my code be much simpler?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define LINE_MAX 10
char buffer[LINE_MAX];
unsigned int bufpos = 0;
struct update left_column_handler(char c, unsigned int column);
struct update blanks_handler(char c, unsigned int column);
struct update initial_word_handler(char c, unsigned int column);
struct update subsequent_word_handler(char c, unsigned int column);
struct update
{
struct update (*handler)(char c, unsigned int column);
unsigned int column;
};
void push_char(char c)
{
assert(bufpos < LINE_MAX);
assert((c != ' ') && (c != '\n'));
buffer[bufpos] = c;
++bufpos;
}
void print_buffer(void)
{
unsigned int i;
for (i = 0; i < bufpos; ++i)
putchar(buffer[i]);
bufpos = 0; /* invalidate buffer data */
}
struct update left_column_handler(char c, unsigned int column)
{
struct update update;
putchar(c);
if (c == ' ')
{
update.handler = blanks_handler;
update.column = 1;
}
else if (c == '\n')
{
update.handler = left_column_handler;
update.column = 0;
}
else /* c != ' ' && c != '\n' */
{
update.handler = initial_word_handler;
update.column = 1;
}
return update;
}
struct update blanks_handler(char c, unsigned int column)
{
struct update update;
if (c == ' ')
{
putchar(c);
++column;
if (column < LINE_MAX)
{
update.handler = blanks_handler;
update.column = column;
}
else /* column == LINE_MAX */
{
putchar('\n');
update.handler = left_column_handler;
update.column = 0;
}
}
else if (c == '\n')
{
putchar(c);
update.handler = left_column_handler;
update.column = 0;
}
else /* c != ' ' && c != '\n' */
{
push_char(c);
update.handler = subsequent_word_handler;
update.column = column; /* has not been incremented */
}
return update;
}
struct update initial_word_handler(char c, unsigned int column)
{
struct update update;
if (c == ' ')
{
putchar(c);
++column;
if (column == LINE_MAX)
{
putchar('\n');
update.handler = left_column_handler;
update.column = 0;
}
else
{
update.handler = blanks_handler;
update.column = column;
}
}
else if (c == '\n')
{
putchar(c);
update.handler = left_column_handler;
update.column = 0;
}
else /* c != ' ' && c != '\n' */
{
if (column == LINE_MAX - 1)
{
int d = getchar(); /* lookahead */
ungetc(d, stdin);
if ((d != ' ') && (d != '\n'))
{
printf("-\n%c", c);
update.handler = initial_word_handler;
update.column = 1;
}
else
{
printf("%c\n", c);
if ((d == '\n') || (d == ' '))
(void) getchar(); /* dispose of extra whitespace */
update.handler = left_column_handler;
update.column = 0;
}
}
else /* column < LINE_MAX - 1 */
{
putchar(c);
++column;
update.handler = initial_word_handler;
update.column = column;
}
}
return update;
}
struct update subsequent_word_handler(char c, unsigned int column)
{
struct update update;
unsigned int room = LINE_MAX - column;
if (c == ' ')
{
if (bufpos > room) /* change to >= to include trailing spaces */
{
putchar('\n');
column = 0;
}
column += bufpos;
print_buffer();
if (column < LINE_MAX)
{
putchar(c);
++column;
update.handler = blanks_handler;
update.column = column;
}
else
{
putchar('\n');
update.handler = left_column_handler;
update.column = 0;
}
}
else if (c == '\n')
{
if (bufpos > room) /* change to >= to include trailing spaces */
{
putchar('\n');
column = 0;
}
column += bufpos;
print_buffer();
putchar(c);
update.handler = left_column_handler;
update.column = 0;
}
else /* c != ' ' && c != '\n' */
{
push_char(c);
if (bufpos == room)
{
int d = getchar(); /* lookahead */
ungetc(d, stdin);
if ((d != ' ') && (d != '\n'))
{
putchar('\n');
column = 0;
}
column += bufpos;
print_buffer();
if (column == LINE_MAX)
{
putchar('\n');
column = 0;
}
}
update.handler = subsequent_word_handler;
update.column = column;
}
return update;
}
int main(void)
{
char c;
unsigned int column = 0;
struct update (*handler)(char c, unsigned int column)
= left_column_handler;
while (c = getchar(), c != EOF)
{
struct update update = handler(c, column);
handler = update.handler;
column = update.column;
}
return EXIT_SUCCESS;
}
Richard