So far I have reached chapter 5 of the K&R Book, Edition 2 from which I have been learning C. I spent a few days thinking of a solution to this program. I wrote two or three versions of the same program, And the truth is that I couldn't bring myself to think of a better solution for this exercise:
Exercise 5-11. 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.
And well, I assumed that this was the best one I had written. Here is the solution for the exercise (Chapter 5, Ex-5.11):
I would like to know how to improve it to take it "further?" or if I'm taking the right approach:
/*-
* detab.c - expand tabs to equivalent spaces
*
* The-C-Programming-Language Book 2nd Edition.
*
* Created by jr.chavez on 9/22/22.
*/
#include <stdio.h>
#include <stdlib.h>
#define DTAB_STOP 8 /* DEFAULT TAB STOP */
#define MAX_TAB_STOP 100
enum escapes { BACKSPACE = '\b', TAB = '\t', NEWLINE = '\n', RETURN = '\r' };
static int
getstops(char *cp)
{
int n;
n = 0;
while (*cp) {
if (*cp < '0' || *cp > '9')
return -1;
if (*cp >= '0' && *cp <= '9')
n = n * 10 + *cp - '0';
cp++;
}
return n;
}
int
main(int argc, char *argv[])
{
int ch;
int n, col; /* n, columns */
int nstops;
int tabstops[MAX_TAB_STOP];
nstops = argc - 1;
if (nstops > MAX_TAB_STOP) {
fprintf(stderr, "error: too many args.\n");
exit(EXIT_FAILURE);
}
for (int indx = 1; indx < argc; indx++) {
tabstops[indx - 1] = getstops(argv[indx]) - 1;
}
col = 0;
while ((ch = getchar()) != EOF) {
switch (ch) {
case TAB:
if (nstops == 0) {
while (col < DTAB_STOP) {
printf("\u25A0");
col++;
}
continue;
}
for (n = 0; n < nstops; n++)
if (col < tabstops[n])
break;
if (n == nstops) {
printf("\u25A0");
col++;
continue;
}
while (col < tabstops[n]) {
printf("\u25A0");
col++;
}
break;
case BACKSPACE:
if (col > 0)
--col;
putchar(BACKSPACE);
break;
case RETURN:
case NEWLINE:
putchar(ch);
col = 0;
continue;
default:
putchar(ch);
break;
}
}
if (ferror(stdin)) {
perror("stdin");
return EXIT_FAILURE;
}
return 0;
}
I did some "tests":
cat test.txt | ./bin/detab 4 9 29
Input File:
# # #
# # #
# # # # #
# # #
Output:
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■#■■#
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■#■■#
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■#■#■■■#■#
#■■■#■■■■■■■■■■■■■■■■■■■■■■■■■■#
These are the results I get with the expand command: (Of course, I never intended the results to be accurate in the first place - but for now I'd just like to improve it.)
cat test.txt | expand -t 4,9,29
output:
# # #
# # #
# # # # #
# # #
Note:
I've only written the detab program, for now.
I had focused on doing something "similar" to what the "expand" command does. (I don't get the same output, but something similar). I also didn't add flags or read from a file. (I still haven't reached Chapter 7.).