/***************************************************************
 *
 *      A crude text formatter.
 *
 *      Formats the text read from stdin to fit within the
 *      line length M and writes it to stdout.
 *
 *      This formatter makes several dubious assumptions:
 *
 *          1.  Paragraphs are separated by blank lines.
 *          2.  The space and newline characters are the only
 *              characters that aren't part of a word.
 *          3.  No paragraph is more than BUFSIZE characters long.
 *          4.  No word is longer than the line length M.
 *
 **************************************************************/
 
#include <stdio.h>
#include "linebreaks.h"

int M = 50;    /*  Maximum length of a formatted line.  */

#define BUFSIZE 10000
#define MAXWORDS 5000

char paragraphBuffer[BUFSIZE];
int paragraphIndex;    /*  active length of paragraphBuffer  */
int paragraphWords;    /*  active length of paragraphWordLengths  */
int paragraphWordLengths[MAXWORDS];
int paragraphLineBreaks[MAXWORDS];

int peekchar();
void FlushWhitespace();
int EndOfParagraph();
void ReadWord();
void ReadParagraph();
void FormatParagraph(int);
void WriteParagraph();

main() {
    FlushWhitespace();
    while (peekchar() != EOF) {
        ReadParagraph();
        FormatParagraph(M);
        WriteParagraph();
        printf ("\n\n");
    }
}

int peekchar() {
    int c = getchar();
    ungetc(c, stdin);
    return c;
}

void FlushWhitespace() {
    int c = peekchar();
    while ((c != EOF) && ((c == ' ') || (c == '\n'))) {
        getchar();
        c = peekchar();
    }
}

/* Paragraphs. */

int EndOfParagraph() {
    int c = peekchar();
    while ((c == ' ') || (c == '\n')) {
        if (c == ' ') {
            getchar();
            c = peekchar();
        }
        else {
            getchar();
            c = peekchar();
            if ((c == EOF) || (c == '\n'))
                return 1;
            else;
        }
    }
    return c == EOF;
}

void ReadWord() {
    int c = peekchar();
    while ((c != EOF) && (c != ' ') && (c != '\n')) {
        paragraphBuffer [paragraphIndex] = c;
        paragraphIndex = paragraphIndex + 1;
        getchar();
        c = peekchar();
    }
    paragraphBuffer [paragraphIndex] = ' ';
    paragraphIndex = paragraphIndex + 1;
    paragraphWords = paragraphWords + 1;
}

void ReadParagraph() {
    paragraphIndex = 0;
    paragraphWords = 0;
    while (! EndOfParagraph())
        ReadWord();
}

void FormatParagraph(int M) {
    int i = 0;
    int thisword = 0;
    int index = 0;
    /*  Compute word lengths.  */
    while (index < paragraphIndex) {
        if (paragraphBuffer [index] == ' ') {
            paragraphWordLengths [i] = thisword;
            i = i + 1;
            thisword = 0;
            index = index + 1;
        }
        else {
            thisword = thisword + 1;
            index = index + 1;
        }
    }
    paragraphIndex = paragraphIndex - 1;
    /*  Choose line breaks.  */
    ChooseLineBreaks (paragraphWords,
                      paragraphWordLengths,
                      M,
                      paragraphLineBreaks);
    /*  Replace the chosen spaces by newlines.  */
    for (index = -1, i = 0;
         i < paragraphWords;
         index = index + 1 + paragraphWordLengths [i], i = i + 1) {
        if (paragraphLineBreaks [i])
            paragraphBuffer [index + 1 + paragraphWordLengths [i]] = '\n';
    }
}

void WriteParagraph() {
    int index;
    for (index = 0; index < paragraphIndex; index = index + 1) {
        putchar (paragraphBuffer [index]);
    }
}