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
Post a Comment