The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 1.22 on page 34
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 intelligent with very long lines, and if there are no blanks or tabs before the specified column.
Solution by Rick Dearman
Category 1 Solution
/****************************************************** KnR 1-22 -------- Write a program that wraps very long lines of input into two or more shorter lines. Author: Rick Dearman email: rick@ricken.demon.co.uk ******************************************************/ #include <stdio.h> #define MAXLINE 1000 /* max input line size */ char line[MAXLINE]; /*current input line*/ int getline(void); /* taken from the KnR book. */ int main() { int t,len; int location,spaceholder; const int FOLDLENGTH=70; /* The max length of a line */ while (( len = getline()) > 0 ) { if( len < FOLDLENGTH ) { } else { /* if this is an extra long line then we ** loop through it replacing a space nearest ** to the foldarea with a newline. */ t = 0; location = 0; while(t<len) { if(line[t] == ' ') spaceholder = t; if(location==FOLDLENGTH) { line[spaceholder] = '\n'; location = 0; } location++; t++; } } printf ( "%s", line); } return 0; } /* getline: specialized version */ int getline(void) { int c, i; extern char line[]; for ( i=0;i<MAXLINE-1 && ( c=getchar()) != EOF && c != '\n'; ++i) line[i] = c; if(c == '\n') { line[i] = c; ++i; } line[i] = '\0'; return i; }
/********************************************************************* Mr Dearman's code assumes that there will be at least one blank before the 'Fold-point". Since this assumption is unfounded, his code will fail on the first long line. In addition, he fails to initialize a variable 'spaceholder' that he subsequently uses as an array index. I hope this is a better algorithm. -- Pilcrow *********************************************************************/ #include <stdio.h> #define MAXLINE 1000 /* input line max */ #define LINEFOLD 70 /* fold point max */ char line[MAXLINE+1]; char fold_segment[MAXLINE+1]; int getline(void); int main(void) { int space_spot, f_move, col, lapse; int len; /* len is len of input line or segment still unfolded */ int last_space; /* index of rightmost space before fold point */ while((len = getline()) > 0) { while(len){ if(len > LINEFOLD) { /* folding needed */ last_space = LINEFOLD-1; /* fold here if no spaces */ /* find last space (if any) before LINEFOLD */ for(space_spot = LINEFOLD-1; space_spot > 0; space_spot--) { if(line[space_spot] == ' ') { last_space = space_spot; break; } } /* format & print segment before last_space */ for(f_move=0; f_move <= last_space; ++f_move) fold_segment[f_move] = line[f_move]; fold_segment[f_move] = '\0';/* terminate new line */ puts(fold_segment); /* and output it */ /* collapse input line to eliminate segment printed */ for(col=0, lapse = f_move; lapse <= len; ++col, ++lapse) line[col] = line[lapse]; len -= last_space; /* adjust remaining line length */ }else{ int l; for(l=0; line[l] != '\0'; l++); /* homegrown strlen */ if(l > 0)puts(line);/* short segment out */ len = 0; /* force more input */ } } } return 0; } int getline(void) { int c, i; for(i = 0; i < MAXLINE && (c=getchar()) != EOF && c != '\n'; ++i) line[i] = c; line[i] = '\0'; if(c == '\n') ++i; return i; }
Here another solution to this exercice, not as elegant as it could be, but well... at least this one does not depend of a max lenght in the input lines
TheSunShadow
#include <stdio.h> #define TAB 4 // This is the size of the tab columns. #define MAXSITE 40 // Max number of characters in a line, // must be larger than the longest word. main() { int site = 0, last = 0, c, i, col = 0; char line[MAXSITE]; while((c = getchar()) != EOF){ line[site] = c; // We store each line in a temporary array if(c == '\t' && col <= MAXSITE - TAB){ // This controls the // correct spacing for(i = col%TAB; i < TAB ; ++i){ // of the text with line[site] = ' '; // the tabs sizes. ++site; } col += (TAB - col%TAB); } if(c != '\t'){ ++site; ++col; } if(c == ' ' || c == '\t') last = site - 1; // This is a marker of the last // white space in a line. if(c == '\n'){ // Lines shorter than the max line[site] = '\0'; // lenght are written 'as is'. printf("%s", line); site = last = 0; col = 0; } if(site == MAXSITE){ // Lines longer than the max lenght // are written until the last space. for(i = 0; i < last; ++i) printf("%c", line[i]); putchar('\n'); for(i = 0; i < MAXSITE - last; ++i) if(line[last + i + 1] != ' ' || line[last + i + 1] != '\t') line[i] = line[last + i + 1]; site = MAXSITE - last - 1; col = site; } } for(i = 0; i < site; ++i) // This writes the last input line. printf("%c", line[i]); putchar('\n'); }
Donald Goodman's Solution
This solution is "Category 1" also, because it implements recursion. It also puts the line breaking into its own function, which is appropriate even at the end of the tutorial; it's a separate task, so it deserves its own function. In any case, recursion greatly simplified the problem, so I hope this helps others.
One issue with this program is that it takes no account of double spaces, after periods or elsewhere; so if a break is done after a period followed by a double space, the new line will begin with a space, which is not optimal. Also, tabs should probably be reduced; this program does not do so, treating them simply as normal characters. Thus, while the lines are in fact broken after a given number of characters, tabs will make them appear longer.
The default line length is very short here; this reduces the amount that needs to be typed in testing.
If you have any improvements or suggestions, please post them to my User:Dgoodmaniii profile page.
/* +AMDG */ /* * A program to fold long input lines at the nearest space * prior to the length limit. Lines longer than the limit * without any spaces are put all by themselves and not * broken. * */ #include<stdio.h> #include<string.h> #define MAXLINE 10000 #define LIMIT 20 int getline(char s[], int lim); int cut(char s[], int start); int main(void) { int i; int length; char string[MAXLINE]; while ((length = getline(string,MAXLINE)) > 0) { if (length > LIMIT) { cut(string, 0); printf("%s",string); } else printf("%s",string); } return 0; } int cut(char s[], int start) { int i,j; int spaces = 0; for(i=start+LIMIT; i > start && s[i] != ' ' && s[i] != '\t'; --i); if (i == start) { for(i=start; s[i] != ' ' && s[i] != '\t'; ++i); s[i] = '\n'; } if ((strlen(s) - i) <= LIMIT) { s[i] = '\n'; } else if (i > start && i != start) { s[i] = '\n'; cut(s, i); } return 0; } int getline(char s[], int lim) { int c, i; for (i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i) s[i] = c; if (c == '\n') s[i++] = c; s[i] = '\0'; return i; }










