exc/k&r/01-a-tutorial-introduction/01-22-fold.c

118 lines
2.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TABSTOP 8
#define WIDTH 80
// the RATIO can't be less than 1/2
#define RATIO 2.0/3.0
#define BREAKSTR "-"
int bstrlen = strlen(BREAKSTR);
void fold(int width, int maxind);
void flush_wbuff(int wbi, char wbuff[]);
int insert_break(char buff[], int wbi);
int is_blank(char c);
int mv_cur(int n, char c);
/* fold input, takes one optional argument for max line width (excl \n) */
int main(int argc, char *argv[])
{
int w;
if (argc < 2 || (w = atoi(argv[1])) < 2)
fold(WIDTH, RATIO * WIDTH);
else
fold(w, RATIO * w);
return 0;
}
/* folds input lines to length, where minw <= length <= 'width'
* if a line has no blank spaces after 'minw' chars a BREAKSTR is inserted */
void fold(int width, int minw)
{
int c, n = 0; // n=0 is start of line
int wbi = 0; // word buffer index
char wbuff[width - minw]; // word buffer for words over minw
while ((c = getchar()) != EOF) {
n = mv_cur(n, c);
if (c == '\n' || (n >= width+1 && is_blank(c))) {
// handle newlines
flush_wbuff(wbi, wbuff);
putchar('\n');
n = wbi = 0;
continue;
}
if (n <= minw) // always print chars before minw
putchar(c);
else if (n <= width) {
/* add word (optionaly leading blank) after minw to wbuff
* empty buffer if new blank is found */
if (is_blank(c)) {
flush_wbuff(wbi, wbuff);
wbi = 0;
}
wbuff[wbi] = c;
++wbi;
} else { // one char over edge, c != ' '
n = insert_break(wbuff, wbi) + 1;
putchar(c);
wbi = 0;
}
}
}
void flush_wbuff(int wbi, char wbuff[])
{
printf("%.*s", wbi, wbuff);
}
/* print buff and insert line break where its most fitting,
* return new cursor position
* '\n' is inserted before the last word or 'BREAKSTR\n' is inserted */
int insert_break(char wbuff[], int wbi)
{
int i;
if (wbi == 0) {
putchar('\n');
return 0;
}
if (is_blank(wbuff[0])) {
putchar('\n');
for (i=1; i < wbi; ++i)
putchar(wbuff[i]);
return wbi - 1;
}
flush_wbuff(wbi-bstrlen, wbuff);
printf("%s\n", BREAKSTR);
for (i = wbi-bstrlen; i < wbi; ++i)
putchar(wbuff[i]);
return bstrlen;
}
/* return new cursor position */
int mv_cur(int n, char c)
{
if (c == '\t')
return n + (TABSTOP - n % TABSTOP);
else if (c == '\b')
return n;
return n+1;
}
int is_blank(char c)
{
return (c == ' ' || c == '\t');
}