Variable Tab Width, Part I

The tab character, 0x08 or ^I (Control-I), is always the same width, no?

If you write a program and include a tab character in the output, can you always expect that tab to line up your text? Hopefully! Not every terminal is the same, but that’s a mandate that’s pretty much been forgotten. The old and various teletypes and VDUs of the 1970s are pretty much gone now, but as a programmer, you can code in flexibility.

Here’s an example:

#include <stdio.h>

int main()
{
    char *text[3] = {
      "\tHello\tHello",
      "\tHi\tHi",
      "\tFelicitations\tFelicitations"
    };
    int x;

    for(x=0;x<3;x++)
        printf("%s\n",text[x]);

    return(0);
}

The code above displays three strings, each of which has two tab characters, \t, and other text of varying length. Here's the output:

	Hello	Hello
	Hi	Hi
	Felicitations	Felicitations

The long word Felicitations messes up the otherwise neat columns generated by the tabs. That's to be expected; anyone who's formatted documents on a computer has faced that problem when dealing with fixed-width tab stops. Above, and on most terminals, the tab stops are set every 8 characters.

Of course, you won't find any fixed tab stops across a terminal window; it's the terminal output routines that calculate tab stops. Also, you'll note that the tab character isn't just 8 consecutive spaces. The width varies, depending on the cursor's horizontal position.

If you wanted to code your own tab stop routine, you'd have to start by modifying the code so that it outputs one character at a time. That makes it easier to fetch and deal with a tab character. Here's the first step in the modification:

#include <stdio.h>

int main()
{
    char *text[3] = {
      "\tHello\tHello",
      "\tHi\tHi",
      "\tFelicitations\tFelicitations"
    };
    int x,i;

    for(x=0;x<3;x++)
    {
        i = 0;
        while(*(text[x]+i))
        {
            putchar(*(text[x]+i));
            i++;
        }
        putchar('\n');
    }

    return(0);
}

Above, I've replaced the printf() function with a while() loop that churns through the string, one character at a time. The putchar() function handles display of each character. A second putchar() handles the newline.

The second step is to isolate the tab character and whisk it off to a function for separate handling. This modification handles that step by employing the tabby() function:

#include <stdio.h>

void tabby(void);

int main()
{
    char *text[3] = {
      "\tHello\tHello",
      "\tHi\tHi",
      "\tFelicitations\tFelicitations"
    };
    int x,i;

    for(x=0;x<3;x++)
    {
        i = 0;
        while(*(text[x]+i))
        {
            if( *(text[x]+i) == '\t')
                tabby();
            else
                putchar(*(text[x]+i));
            i++;
        }
        putchar('\n');
    }

    return(0);
}

/* calculate and display a tab */
void tabby(void)
{
    putchar('\t');
}

At this stage in the process, the tabby() function merely displays the tab character \t. The code's output is still the same as the first example, but the tabby() function is primed for a better solution. I'll cover one such solution in next week's Lesson, although you're free to concoct your own in the meantime.

Leave a Reply