Exercise 1.22 - fold long lines¶
Question¶
Write a program to fold
long input lines into two or more shorter lines
after the last non-blank character that occurs before the n-th column of input.
Make sure your program does something ntelligent with very long lines, and if
there are no blanks or tabs before the specified column.
Solution¶
#include <stdio.h>
#define MAXCOL 35 /* folded line length */
#define TABVAL 8 /* standard tab length */
#define CURTAB(c) (TABVAL - ((c) % TABVAL)) /* current tab size */
#define NO_BLANK -1 /* signifies no blank found */
/* finds the last whitespace character in an array
and returns the position */
int lastblank(const char arr[], int len) {
int i, lbc;
lbc = -1;
for (i = 0; i < len; ++i)
if (arr[i] == ' ' || arr[i] == '\t' || arr[i] == '\n')
lbc = i;
return lbc;
}
/* folds long input lines into two or more shorter lines */
int main(void) {
int c; /* character variable */
int i, j; /* indexing variable(s) */
int pos; /* current position in array */
int col; /* current column of output */
int lbc; /* last blank character position */
char line[MAXCOL + 1]; /* fold array */
pos = col = 0;
while ((c = getchar()) != EOF) {
/* process line array, keep track of line length by columns */
line[pos++] = c;
col += (c == '\t') ? CURTAB(col) : 1;
/* create fold */
if (col >= MAXCOL || c == '\n') {
line[pos] = '\0';
if ((lbc = lastblank(line, pos)) == NO_BLANK) {
/* split word if no blank characters */
for (i = 0; i < pos; ++i)
putchar(line[i]);
/* reset column value and array position */
col = pos = 0;
} else {
/* print array up until last blank character */
for (i = 0; i < lbc; ++i)
putchar(line[i]);
/* feed remaining characters into buffer */
for (i = 0, j = lbc + 1, col = 0; j < pos; ++i, ++j) {
line[i] = line[j];
/* set new column value */
col += (c == '\t') ? CURTAB(col) : 1;
}
/* set array position after remaining characters */
pos = i;
}
/* finish folded line with newline character */
putchar('\n');
}
}
return 0;
}
Explanation¶
We determine the column to fold in the MAXCOL variable.
2. Since tab character can occur too and folding a tab character means folding it in mid-way, we also replace the tabs in the line with spaces.
3. Every character of the file is filled into a line[MAXCOL]
array and that
line is acted upon by the program.
4. We start at pos=0
and take each character and place it in line[pos]
and
then we analyze the character to act upon the condition.
6. If the character is \t
. We go and expand the tab character in the
line[pos]
and get newposition. So, when line[t] at pos = 0, it will be now
line[' ', ' ', ' ',' ',' ',' ',' ',' '] and pos = 8
7. If character is \n
then we print the entire line contents reset the pos
back to 0.
otherwise, we get into our program.
When we are folding, we should not be folding in between the word. So we have to track the previous space occuring in a line. The logic follows.
1. When our position is greater than MAXCOL, then we look for previous blank
space by using getblank
and we get the position of that blank.
2. We then fold
, getblank will return the pos which is not greater than
MAXCOL. So, the print the characters we have in line and then print newline.
3. We determine the new position based the return value of getblank. If the
return value of getblank was greater than MAXCOL, then our new position is 0,
which is a newline. We will replace the contents of line starting from 0, mark
this as i
, and place the folded contents by the last for loop
in the program
and after placing the folded contents we return the new value of i
, which is
our updated pos
.
With our new position we continue with the rest of the program.