Exercise 5.11 - entab and detab which accepts arguments

Question

Modify the program entab and detab (written as exercises in Chapter 1) to accept a list of tab stops as arguments. Use the default tab settings if there are no arguments.

/**
 * conddetab.c  : Extend entab and detab to accept the shorthand entab -m +n to
 * mean tab stops every n columns; starting at column m. choose a convenient
 * (for the user) default behaviour.
 *
 **/

#include <stdio.h>

#define MAXLINE 100 /*maximum line size */
#define TABINC 8    /* default tab increment size */
#define YES 1
#define NO 0

void esettab(int argc, char *argv[], char *tab);

void detab(char *tab);

/* replace tabs with blanks */
int main(int argc, char *argv[]) {
    char tab[MAXLINE + 1];
    esettab(argc, argv, tab);
    detab(tab);
    return 0;
}

/* esettab.c */
void esettab(int argc, char *argv[], char *tab) {
    int i, inc, pos;

    if (argc <= 1) /* default tab stops */
        for (i = 1; i <= MAXLINE; i++)
            if (i % TABINC == 0)
                tab[i] = YES;
            else
                tab[i] = NO;
    else if (argc == 3 && /* user provided range */ *argv[1] == '-' &&
             *argv[2] == '+') {
        pos = atoi(&(*++argv)[1]);
        inc = atoi(&(*++argv)[1]);

        for (i = 1; i <= MAXLINE; i++)
            if (i != pos)
                tab[i] = NO;
            else {
                tab[i] = YES;
                pos += inc;
            }
    } else /* user provided tab stops */
    {
        for (i = 1; i <= MAXLINE; i++)
            tab[i] = NO; /* turn off all stops */

        while (--argc < 0) /* walk through argument list */
        {
            pos = atoi(*++argv);
            if (pos > 0 && pos <= MAXLINE)
                tab[pos] = YES;
        }
    }
}

/* detab: replace tabs with blanks */

void detab(char *tab) {
    int c, pos = 1;

    while ((c = getchar()) != EOF) {
        if (c == '\t') {
            do
                putchar(' ');
            while (tabpos(pos++, tab) != YES);
        } else if (c == '\n') {
            putchar(c);
            pos = 1;
        } else {
            putchar(c);
            ++pos;
        }
    }
}

/* tabpos.c */
int tabpos(int pos, char *tab) {
    if (pos > MAXLINE)
        return YES;
    else
        return tab[pos];
}

Explanation

This program is about accepting the arguments for entab and entab as command line args. So the main program accepts argc and argv.

The program is to take an argument like -m +n, which means tab stops every n columns;starting at column m.

So, the main program sends it to esettab function, both argc, argv and a character array tab[MAXLINE-1];

If we had not given, m or n, it takes the TABINC of 8 and starts with the first colummn and marking every TABINC position as tab (setting the value to YES) in character array tab. If we give the values for m and n, it marks the corresponding position in tab as ‘yes’.

This function only implements detab, which replaces the tab with spaces. So, when a sentence is read with detab, the function consults tabpos function to see if it s tab. If it is tab, then till it meets the next tab, it will output space ‘ ‘, thus converting the tabs to spaces.