A Word Wrap Filter

Unlike static text, streaming text feeds into a program one character at a time. To wrap that text, you need to know all the basics about wrapping text (covered in this Lesson), but also how to concoct a filter that buffers its output.

A filter is a basic I/O machine. I write about them in my For Dummies C language titles. The program gobbles up input one character at a time, does something to the character(s), then spews output.

Here is a most basic filter:

#include <stdio.h>

int main()
{
    int a;

    while( (a = getchar()) != EOF)
        putchar(a);

    return(0);
}

The code simply takes input from getchar() and sends that to output via putchar(). The while loop keeps working until the input stream generates an EOF (end of file) character.

When using this code to read standard input, the EOF character is Ctrl+D in Unix, Ctrl+Z in Windows. Or just type Ctrl+C to terminate the program.

The problem with the code above is that it doesn’t do anything to modify input, so it’s not a very useful filter.

An example of a more useful filter would be one that wraps text. The code needs to know a wrapping point, what I call the right margin. Then it also needs to determine the proper breaking point at which to wrap. The following code shows one way to handle this task.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main()
{
    char *buffer,*space;
    int c,x,right_margin,position;

    right_margin = 40;      /* make the margin variable */

    /* allocate space for the buffer */
    buffer = malloc(sizeof(char) * right_margin);
    if(buffer==NULL)
    {
        perror("Unable to allocate buffer");
        exit(1);
    }

    *buffer = '\0';         /* initialize buffer */
    space = buffer;         /* Initialize space */
    position = 0;           /*  and position */
    c = 65;                 /* Ensure that it loops */
    while(c)
    {
        c = getchar();          /* fetch character */
        *(buffer+position) = c; /* store character */
        /* if c is white space, save its location */
        if(isspace(c))
            space = buffer+position;
        position++;             /* buffer index */
        /* check to see if the margin has been reached */
        if(position > right_margin)
        {
            /* Display the buffer up to the space */
            for(x=0;x<right_margin;x++)
            {
                if( *(buffer+x)==EOF)   /* exit on EOF */
                    exit(0);
                if(buffer+x == space)   /* stop at w/s char */
                    break;
                putchar(*(buffer+x));
            }
            putchar('\n');
            /* copy the rest of the buffer to the start */
            position = 0;
            space++;
            while(space <= buffer+right_margin)
            {
                *(buffer+position) = *(space);
                position++;
                space++;
            }
            /* Re-initialize the space pointer */
            space = buffer;
        }
    }

    return(0);
}

Yes! That’s a long chunk of code, but it’s doing a lot. The primary difference between this code and last week’s Lesson (on wrapping existing text) is that this example deals with stream input. That ratchets up the difficulty a notch.

To demonstrate how the code works you can run the program and type text at the command prompt, or you can redirect input from a file. As an example, assume that the file preamble.txt contains the Preamble to the Declaration of Independence. Figure 1 illustrates how this code processes that input.

Figure 1. Processing a file redirected as input.

Figure 1. Processing a file redirected as input.

Click here to download a copy of the preamble.txt file.

Next week, I’ll present the blow-by-blow of how this code works, along with a video that visually explains what’s going on. I’ll also offer an explanation of the two conditions that cause this code to malfunction.

Leave a Reply