Word Wrap Filter Repair

As a programmer, always be thinking: What can go wrong? What would be an exception? Where have I made assumptions? You can’t avoid bugs by making such challenges, but you can diminish their possibilities.

A case in point is the word wrap filter, presented in last week’s Lesson. As I pointed out, that code has two major flaws. These are discovered either through extensive testing or by reviewing the code in your noggin and trying to figure out ways to break it.

The first flaw occurs when a newline is encountered in the buffer, before the wrapping point. In that case, you can end up with filter output that looks jagged and sloppy:

He has
abdicated Government here, by declaring
us out of his Protection and waging War
against us.
He has plundered our seas,
ravaged our Coasts, burnt our towns, and
destroyed the lives of our people.
He is
at this time transporting large Armies

Instead of:

He has abdicated Government here, by
declaring us out of his Protection and
waging War against us.
He has plundered our seas, ravaged our
Coasts, burnt our towns, and destroyed
the lives of our people.
He is at this time transporting large
Armies

The second flaw happens when no whitespace characters are encountered before the right margin. In that case, the code would overflow and you might see one of those notorious Segmentation Fault errors.

One fix at a time!

To deal with a newline character encountered before the right_margin, the following code can be added after Line 31. That’s where the character received is placed into the buffer.

 		/* check for newline before margin */
 		if(*space == '\n')
 		{
 			*space = '\0';
 			x = 0;
 			while(*(buffer+x))
 			{
 				if( *(buffer+x)==EOF)
 					exit(0);
 				putchar(*(buffer+x));
 				x++;
 			}
 			putchar('\n');
 			position=0;
 		}

When a newline is encountered, the buffer is immediately capped with a null character, \0. Then the buffer is displayed, again confirming that an EOF isn’t lurking somewhere. The program then continues looking for input.

Click here to view the full version of this code.

The fix to determine whether any whitespace character was encountered — such as when a very, very long word appears in the text — is more extensive: It involves a structural change the program. That’s because when no place to wrap exists, then the text must be output as one chunk, without wrapping. That may not be the best way to handle such a situation, but it’s my choice as programmer.

In the original code, a decision must be made when the position pointer passes the right_margin, indicating that the buffer is full and word wrap is necessary:

        /* check to see if the margin has been reached */
        if(position > right_margin)
        {
            /* Check to see whether any words found */
            if(buffer == space)

The if test above determines whether the space pointer has moved forward or not. If not, then the buffer contains one huge word that cannot be wrapped. Therefore the statements belonging to if merely display the text-chunk, no wrapping:

            if(buffer == space)
            {
                for(x=0;x<right_margin;x++)
                {
                    if( *(buffer+x)==EOF)
                        exit(0);
                    putchar(*(buffer+x));
                }
                *buffer = *(buffer+x);
                position=1;
            }

This code spits out the buffer‘s contents to standard output. If an EOF is encountered, then output terminates and the program quits with an exit() function. Otherwise, the final character in the buffer is copied back to the start, so that the process can continue.

An else follows the if test. Its statements basically process the buffer, displaying characters up until the space pointer, as was shown in the original code.

Click here to view the final version of the word wrap filter.

Is this filter perfect? I dunno.

I’m not being silly: On your own you can guess which parts of the code might fail or you can experiment on a variety of interesting situations. My goal is not to create perfect code as much as I want to create well-running code. If it needs to be fixed later, then that’s part of the process. The better you can anticipate problems and bugs, and the more elegant your code, the better it is to fix problems in the future.

Leave a Reply