Exercise 5-12-2 (entabn with command-line arguments)

Chapter_5     Exercise_5-12-1 Exercise_5-13







Exercise 5-12     K&R, p. 118


Exercise 5-12. Extend entab and detab to accept the shorthand
    entab -m +n
to mean tab stops every n columns, starting at column m. Choose convenient (for the user) default behavior.




CONTENTS:     spaces.txt     entabn.c     output.txt




Note:  We decided to extend the program entab from Chapter_1 (and not from the previous_exercise) to keep it simpler and easier to understand. To simplify things even further, the program now works with only 2 command-line arguments.




spaces.txt         download


1234567 123456  12345   1234    123     12      1       0
a       ab      abc     abcd    abcde   abcdef  abcdefg h





entabn.c         download


#include <stdio.h> // for getchar(), putchar(), printf(), EOF
#include <stdlib.h> // for atoi()

#define TAB 4 // 4 spaces
// For every chunk of TAB chars,
// trailing spaces [+'\t'] become '\t',
// [trailing spaces +] '\t' become '\t':
// entabn(" ") == "\t" // 4 spaces
// entabn(" \t") == "\t" // 3 spaces
// entabn(" \t") == "\t" // 2 spaces
// entabn(" \t") == "\t" // 1 space
// entabn("a ") == "a\t" // 3 spaces
// entabn("a \t") == "a\t" // 2 spaces
// entabn("ab ") == "ab\t" // 2 spaces
// entabn("abc ") == "abc\t" // 1 space
// entabn("\t") == "\t"
// entabn("a\t") == "a\t"
// entabn("*a\t") == "*a\t" // '*' is not '\t',
// entabn("**a\t") == "**a\t" // but can be ' '

// we consider first column to be 1, just like first line is 1, not 0
void entabn(int col, int tab); // turn spaces into tabs
// use TAB before reaching column col, then use tab

int main(int argc, char *argv[])
{
if (argc != 3 || *argv[1] != '-' || *argv[2] != '+')
{
printf("Usage: ./entabn -m +n\n");
printf("m = column number, n = tab size\n");

return 1; // end program, signalling error
}

argv[1]++, argv[2]++; // move past '-' or '+'

int col = atoi(argv[1]);
int tab = atoi(argv[2]);

if (col <= 0 || tab <= 0)
{
printf("Usage: ./entabn -m +n\n");
printf("m = column number > 0, n = tab size > 0\n");

return 1; // end program, signalling error
}

entabn(col, tab);

return 0;
}

// use TAB before reaching column col, then use tab
void entabn(int col, int tab) // turn spaces into tabs
{ // col > 0, tab > 0
int c, i;
int chunk = 0; // count up to tab chars (next tab stop)
int count = 1; // count up to col-1 chars, start at column 1
// if col == 1, entabn(1, tab) is entab(tab)
int spaces = 0; // consecutive trailing spaces until '\t' or tab stop
// (chunk of tab chars), spaces <= chunk
int tabsize = TAB; // default value until count >= col
// starting at column col, tabsize = tab

if (count >= col) // if (count == col)
{
tabsize = tab;
// chunk = 0; // restart counting
}

while((c = getchar()) != EOF)
{
if (c == '\n') // chunk < tabsize
{
while (spaces > 0) // add trailing spaces at the end of line
{
putchar(' ');
spaces--;
} // here spaces == 0
chunk = 0; // reset, go to next line
count = 1; // reset to column 1
tabsize = TAB; // reset to default

if (count >= col) // if (count == col)
{
tabsize = tab;
// chunk = 0; // restart counting
}

putchar(c); // putchar('\n');
}
else if (c == '\t') // advance to next tab stop, chunk < tabsize
{ // replace ([trailing spaces +] '\t') with '\t':
spaces = chunk = 0; // reset, go to next chunk of tab chars
putchar(c); // putchar('\t');

if (count < col)
{ // count columns in the original file, so we don't subtract removed spaces
count++; // for the added '\t'
// we don't subtract spaces from count
if (count >= col) // if (count == col)
{
tabsize = tab;
// chunk = 0; // restart counting
}
}
}
else if (c == ' ')
{
spaces++, chunk++;

if (chunk >= tabsize) // if (chunk == tabsize)
{ // replace trailing spaces with '\t'
putchar('\t');
spaces = chunk = 0; // reset, go to next chunk of tab chars
} // else continue;

if (count < col)
{ // count columns in the original file, so we don't subtract removed spaces
count++; // for the added ' '
// we don't subtract spaces from count
if (count >= col) // if (count == col)
{
tabsize = tab;
chunk = 0; // restart counting
}
}
}
else
{
while (spaces > 0) // add trailing spaces before char
{
putchar(' ');
spaces--;
} // here spaces == 0

putchar(c);
chunk++;

if (chunk >= tabsize) // if (chunk == tabsize)
{chunk = 0;} // reset, go to next chunk of tab chars

if (count < col)
{
count++; // for the added char

if (count >= col) // if (count == col)
{
tabsize = tab;
chunk = 0; // restart counting
}
}
}
}
}
/*
gcc entabn.c -o entabn
./entabn
Usage: ./entabn -m +n
m = column number, n = tab size

./entabn 1 8
Usage: ./entabn -m +n
m = column number, n = tab size

./entabn -i +8
Usage: ./entabn -m +n
m = column number > 0, n = tab size > 0

./entabn -1 +-8
Usage: ./entabn -m +n
m = column number > 0, n = tab size > 0

./entabn -1 +8 // input from the keyboard
1234567 123456 12345 1234 123 12 1 0 // Enter (spaces)
1234567 123456 12345 1234 123 12 1 0 // tabs (tab = 8)
// Ctrl^D or Ctrl^C in Linux, Ctrl^Z + Enter in Windows (EOF)

./entabn -1 +8 < spaces.txt
1234567 123456 12345 1234 123 12 1 0 // tab = 8
a ab abc abcd abcde abcdef abcdefg h

./entabn -1 +8 < spaces.txt > tabs.txt

./entabn -5 +4 < spaces.txt > output.txt

./entabn -5 +7 < entabn.c // input from source file

./entabn -3 +4 < entabn // input from binary file
*/











output.txt         download


1234567 123456 12345 1234 123 12 1 0
a ab abc abcd abcde abcdef abcdefg h





Notes:

In output.txt, first line, column 5 is marked by digit 5. After reading 4, count is 5 (count==col), tabsize=4, chunk=0. After reading ' ' after 7, chunk == tabsize, so we replace ' ' by '\t'.
On the second line, a is followed by 7 spaces. After reading a and the first 3 spaces, chunk==TAB==4, so we replace the 3 trailing spaces with '\t'. Then tabsize=4, chunk=0 (count==col). After reading the next 4 spaces, upon reaching a from ab, chunk==tabsize, so we replace the 4 read spaces by '\t'. As such, there are two tabs between a and ab.









Chapter_5     Exercise_5-12-1 BACK_TO_TOP Exercise_5-13



Comments

Popular posts from this blog

Contents

Blogger Page Margins in Contempo