A few conveniences for using weaving with TeX.


§1. Post-processing TeX console output.

Pattern commands post-processing TeX tend to run TeX-like tools in "scrollmode", so that any errors whizz by rather than interrupting or halting the session. Prime among errors is the "overfull hbox error", a defect of TeX resulting from its inability to adjust letter spacing, so that it requires us to adjust the copy to fit the margins of the page properly. (In practice we get this here by having code lines which are too wide to display.)

Also, TeX helpfully reports the size and page count of what it produces, and we're not too proud to scrape that information out of the console file, besides the error messages (which begin with an exclamation mark in column 1).

This structure will store what we find:

classdef tex_results {
    int overfull_hbox_count;
    int tex_error_count;
    int page_count;
    int pdf_size;
    struct filename *PDF_filename;
}

§2.

tex_results *TeXUtilities::new_results(weave_order *wv, filename *CF) {
    tex_results *res = CREATE(tex_results);
    res->overfull_hbox_count = 0;
    res->tex_error_count = 0;
    res->page_count = 0;
    res->pdf_size = 0;
    res->PDF_filename = Filenames::set_extension(CF, I".pdf");
    return res;
}

§3.

So, then, here's the function called from Patterns\inwebendlink} in response to the special PROCESS command:

void TeXUtilities::scan_TeX_log(weave_order *wv, filename *CF) {
    wv->post_processing_results = TeXUtilities::new_results(wv, CF);
    TextFiles::read(CF, FALSE,
        "can't open TeX log file", TRUE, TeXUtilities::scan_console_line, NULL,
        (void *) wv->post_processing_results);
}

§4.

void TeXUtilities::scan_console_line(text_stream *line, text_file_position *tfp,
    void *res_V) {
    tex_results *res = (tex_results *) res_V;
    match_results mr = Regexp::create_mr();
    if (Regexp::match(&mr, line,
        U"Output written %c*? %((%d+) page%c*?(%d+) bytes%).")) {
        res->page_count = Str::atoi(mr.exp[0], 0);
        res->pdf_size = Str::atoi(mr.exp[1], 0);
    }
    if (Regexp::match(&mr, line, U"%c+verfull \\hbox%c+"))
        res->overfull_hbox_count++;
    else if (Str::get_first_char(line) == '!') {
        res->tex_error_count++;
    }
    Regexp::dispose_of(&mr);
}

§5. Reporting.

void TeXUtilities::report_on_post_processing(weave_order *wv) {
    tex_results *res = wv->post_processing_results;
    if (res) {
        PRINT(": %dpp %dK", res->page_count, res->pdf_size/1024);
        if (res->overfull_hbox_count > 0)
            PRINT(", %d overfull hbox(es)", res->overfull_hbox_count);
        if (res->tex_error_count > 0)
            PRINT(", %d error(s)", res->tex_error_count);
    }
}

§6.

And here are some details to do with the results of post-processing.

int TeXUtilities::substitute_post_processing_data(text_stream *to, weave_order *wv,
    text_stream *detail) {
    if (wv) {
        tex_results *res = wv->post_processing_results;
        if (res) {
            if (Str::eq_wide_string(detail, U"PDF Size")) {
                WRITE_TO(to, "%dKB", res->pdf_size/1024);
            } else if (Str::eq_wide_string(detail, U"Extent")) {
                WRITE_TO(to, "%dpp", res->page_count);
            } else if (Str::eq_wide_string(detail, U"Leafname")) {
                Str::copy(to, Filenames::get_leafname(res->PDF_filename));
            } else if (Str::eq_wide_string(detail, U"Errors")) {
                Str::clear(to);
                if ((res->overfull_hbox_count > 0) || (res->tex_error_count > 0))
                    WRITE_TO(to, ": ");
                if (res->overfull_hbox_count > 0)
                    WRITE_TO(to, "%d overfull line%s",
                        res->overfull_hbox_count,
                        (res->overfull_hbox_count>1)?"s":"");
                if ((res->overfull_hbox_count > 0) && (res->tex_error_count > 0))
                    WRITE_TO(to, ", ");
                if (res->tex_error_count > 0)
                    WRITE_TO(to, "%d TeX error%s",
                        res->tex_error_count,
                        (res->tex_error_count>1)?"s":"");
            } else return FALSE;
            return TRUE;
        }
    }
    return FALSE;
}