// linebreak.c                                                                  
// A portable C filter to format voice-to-text output for grep usability.       
// Usage: ./linebreak < input.txt > output.txt                                  
// 20260420 ground/X                                                            
 
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX_WIDTH 80
#define BUFFER_SIZE (MAX_WIDTH + 10)

// --- PeekStream Wrapper ---
// Encapsulates FILE* with one-byte lookahead capability
typedef struct {
    FILE *stream;
    int has_peek;
    int peek_char;
} PeekStream;

void ps_init(PeekStream *ps, FILE *stream) {
    ps->stream = stream;
    ps->has_peek = 0;
    ps->peek_char = 0;
}

int ps_get(PeekStream *ps) {
    if (ps->has_peek) {
        ps->has_peek = 0;
        return ps->peek_char;
    }
    return fgetc(ps->stream);
}

void ps_put(PeekStream *ps, int c) {
    ps->peek_char = c;
    ps->has_peek = 1;
}

// --- ASCII Filter ---
// Returns only 32-126 or \n. Skips everything else silently.
int get_filtered(PeekStream *ps) {
    int c;
    while ((c = ps_get(ps)) != EOF) {
        if (c == '\n' || (c >= 32 && c <= 126)) {
            return c;
        }
        // Drop invalid chars (control codes, high-bit ASCII)
    }
    return EOF;
}

// --- Main Logic ---
int main(void) {
    PeekStream ps;
    ps_init(&ps, stdin);

    char buf[BUFFER_SIZE];
    int len = 0;
    int c;

    while ((c = get_filtered(&ps)) != EOF) {
        
        // 1. Handle Periods (Sentence Break)
        if (c == '.') {
            // --- NEW LOGIC: Collapse consecutive periods ---
            // If we see "..." we only want ONE line break, not three.
            int next;
            while ((next = get_filtered(&ps)) != EOF) {
                if (next == '.') {
                    continue; // Drop extra periods
                } else {
                    ps_put(&ps, next); // Put back non-period char
                    break;
                }
            }
            // -------------------------------------------------

            // Flush current buffer
            if (len > 0) fwrite(buf, 1, len, stdout);
            putchar('.');
            putchar('\n');
            len = 0;

            // Consume whitespace/newlines immediately following the period
            // This prevents leading spaces on the new line
            while ((next = get_filtered(&ps)) != EOF) {
                if (next == ' ' || next == '\n') {
                    continue; // Eat whitespace
                } else {
                    ps_put(&ps, next); // Put back start of next sentence
                    break;
                }
            }
            continue;
        }

        // 2. Handle Existing Newlines
        if (c == '\n') {
            if (len > 0) fwrite(buf, 1, len, stdout);
            putchar('\n');
            len = 0;
            continue;
        }

        // 3. Normal Characters (Buffer & Width Check)
        buf[len++] = (char)c;

        // Enforce Width Limit
        if (len >= MAX_WIDTH) {
            int split = -1;
            // Find last space
            for (int i = len - 1; i >= 0; i--) {
                if (buf[i] == ' ') {
                    split = i;
                    break;
                }
            }

            if (split > 0) {
                // Soft break at space
                fwrite(buf, 1, split, stdout);
                putchar('\n');
                // Move remaining text to start of buffer
                memmove(buf, buf + split + 1, len - (split + 1));
                len = len - (split + 1);
            } else {
                // Hard break (no space found or space at 0)
                fwrite(buf, 1, MAX_WIDTH, stdout);
                putchar('\n');
                memmove(buf, buf + MAX_WIDTH, len - MAX_WIDTH);
                len = len - MAX_WIDTH;
            }
        }
    }

    // 4. Final Flush (POSIX Compliance: Ensure trailing newline)
    if (len > 0) {
        fwrite(buf, 1, len, stdout);
        putchar('\n');
    }

    return 0;
}

