aboutsummaryrefslogtreecommitdiff
path: root/ch1/1-21_entab.c
blob: 6037a147e9e587a6ca767ae01dfa11803af88679 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>

/* The C Programming Language: 2nd Edition
 * Exercise 1-21:
 * "Write a program `entab` that replaces strings of blanks by the minimum
 * number of tabs and blanks to achieve the same spacing. Use the same tab
 * stops as for `detab`. When either a tab or a single blank would suffice to
 * reach a tab stop, which should be given preference?"
 *
 * Answer: A blank. A tab character that comes after (tabstop - 1) blanks makes
 * little-to-no sense and could mess up alignment in some environments.
 *
 */

#define TABWIDTH 8

int main(void) {
	int column, c, spaces;
	spaces = column = 0;
	while ((c = getchar()) != EOF) {
		// First thing's first, advance by a column.
		column++;

		if (c == ' ') {
			/* Add to 'spaces' immediately, we'll decide if it needs to be
			 * output later.
			 */
			spaces++;

			if (column % TABWIDTH == 0 && spaces > 0) {
				putchar('\t');
				spaces = 0; // No spaces are left when we tab!
			}

		} else {
			/* Be sure to output any leftover spaces when we come across a
			 * non-space character. This should allow for spaces between words
			 * that don't fall along the tabstop lines.
			 */

			while (spaces > 0) {
				putchar(' ');
				spaces--;
			}

			// As usual, reset things on a newline.
			if (c == '\n') {
				column = 0;
				spaces = 0;
			}

			// Now we can output whatever it is.
			putchar(c);
		}
	}
	return 0;
}