/* * VTEXFMT * * Given a page/locus/line format file (see below) of Voynich text, format * one or more pages into TeX format for printing. * * Usage: vtexfmt [] * * e.g. vtexfmt f1r f5v * * Input: stdin = text file in p/l/l format * Output: stdout = formatted text (.tex) for input to TeX for * printing * * The printed page will have a title, a line indicating the 'locus' * (area of the page) and the lines with numbers. Extra spacing * between lines indicates the end of a paragraph (indicated in the * input file by a line ending in '#' instead of '-'.) * * 'voycur16' TeX font for Voynich is available from Jim Reeds' Web page * at http://netlib.att.com/netlib/att/math/people/reeds/voynich.html * -------------------------------------------------------------------------- * Page/locus/line format - This is raw text consisting of an address * string enclosed in <> followed immediately by words separated by * periods and terminated with the character '-' or '#'. The character * '*' indicates an unreadable character. * * The address consists of a page string (not necessarily a number), * a locus code (indicating an area of the page), and a line number * within the locus. The line number is numeric and many be followed * by one alpha character indicating the 'hand'. (The manuscript appears * to be written in at least two different handwriting styles.) * * Periods separate the page code, the locus code, and the line number. * (There is no period between line number and hand code.) If the locus * code is omitted, its period is also dropped. (The largest section of * the page generally has a null locus code.) * * Here are sample lines: * * ABDKE.EHDJS.EWKSJD.EKEJSE.EE- * SJDK.EEE.WKSD.WLE# * -------------------------------------------------------------------------- * Bruce Grant (bgrant@umcc.ais.org) */ #include #include #include /* Fonts to use */ #define ROMAN_FONT "cmr12" #define VOYNICH_FONT "voycur16" #define MAX_READ 1000 #define TRUE 1 #define FALSE 0 /* Limits on fields and total buffer length */ #define MAX_FIELDS 100 #define MAX_LEN 1000 #define NXT_MAX_STR 30 /* Delimiters */ #define WHITESPACE "," #define DELIM ',' /* * Split a line into header and text */ int get_header(char *p, char *hdr, char *text) { if (*p == '<') p++; while (*p != '>' && *p != '\0') { *hdr++ = *p++; } *hdr = '\0'; if (*p == '>') p++; while (*p != '\0') { *text++ = *p++; } *text = '\0'; } /* -------------------------------------------------------------------- * Parse a header string into page, line, locus, and hand fields * * -------------------------------------------------------------------*/ int parse_header(char *header_str, char *page_str, char *locus_str, char *line_str, char *hand_str) { int period1, period2; char header_cpy[20]; int i, k; int ch; char *p; /* Clear output fields in case of error */ strcpy(page_str, ""); strcpy(locus_str, ""); strcpy(line_str, ""); strcpy(hand_str, ""); /* Copy header string and get its length */ strcpy(header_cpy, header_str); /* Remove leading and trailing angle brackets if any */ p = header_cpy; k = strlen(p); /* Find locations of first and (optional) second period in header */ period1 = period2 = -1; for (i = 0; i < k; i++) { if (p[i] == '.') { if (period1 == -1) period1 = i; else if (period2 == -1) period2 = i; else return 0; /* Error: found a third */ } } /* If no period found, return error */ if (period1 == -1) return 0; /* If last character is non-numeric it is the "hand" code */ /* otherwise set the hand code to 'X' */ ch = p[k-1]; if (ch >= '0' && ch <= '9') { hand_str[0] = 'X'; hand_str[1] = '\0'; } else { hand_str[0] = p[k-1]; hand_str[1] = '\0'; p[k-1] = '\0'; k = strlen(p); } /* Replace the periods with nulls and copy the components */ /* * Handle case with one period first (i.e. null locus) */ if (period2 == -1) { p[period1] = '\0'; strcpy(page_str, p); strcpy(locus_str, ""); strcpy(line_str, p+(period1+1)); } /* * Handle two period case (locus is not null) */ else { p[period1] = p[period2] = '\0'; strcpy(page_str, p); strcpy(locus_str, p+(period1+1)); strcpy(line_str, p+(period2+1)); } /* Indicate success */ return 1; } /* --------------------------------------------------------------------- * Get next line from the range of pages to be printed * -------------------------------------------------------------------*/ int get_next_line(char *st_pg, char *end_pg, char *page_str, char *locus_str, char *line_str, char *hand_str, char *text_str) { static int found_first_page = FALSE; static int found_last_page = FALSE; static int eof_found = FALSE; char gnl_bufr[MAX_READ]; char hdr_bufr[MAX_READ]; char text_bufr[MAX_READ]; /* If EOF has already been reported, report it again */ if (eof_found) { return EOF; } /* Read a line and report if EOF */ LOOP: if (fgets(gnl_bufr, MAX_READ, stdin) == NULL) { eof_found = TRUE; return EOF; } /* Separate header and text */ if (!get_header(gnl_bufr, hdr_bufr, text_bufr)) { fprintf(stderr, "--Bad input line format\n"); exit(1); } /* Parse the header */ if (!parse_header(hdr_bufr, page_str, locus_str, line_str, hand_str)) { fprintf(stderr, "--Bad header format\n"); exit(1); } /* Test if this is in start page */ if (strcmp(page_str, st_pg) == 0) found_first_page = TRUE; /* Test if this is the end page */ if (strcmp(page_str, end_pg) == 0) found_last_page = TRUE; if (!found_first_page) goto LOOP; if (found_last_page && strcmp(page_str, end_pg) != 0) return EOF; /* Report OK status */ strcpy(text_str, text_bufr); return 1; } /* ------------------------------------------------------------------ * Emit document header info * -----------------------------------------------------------------*/ void emit_header(char *pg) { printf("\\font\\xr=%s\n", ROMAN_FONT); printf("\\font\\xv=%s\n", VOYNICH_FONT); printf("\\xr\n"); printf( "\\headline={\\xr\\hfil The Voynich Manuscript\\hfil}\n"); printf("\\footline={\\xr\\hfil Page: %s\\hfil}\n", pg); printf("\\baselineskip=18pt\n"); } /*---------------------------------------------------------------- * Emit locus info *---------------------------------------------------------------*/ void emit_locus(char *locus_name) { printf("\\xr Locus: %s\n", locus_name); printf("\\halign{#\\hfil& \\quad#\\hfil\\cr\n"); } /*---------------------------------------------------------------- * Close a locus *----------------------------------------------------------------*/ void emit_end_locus() { printf("}\n"); } /*----------------------------------------------------------------- * Emit text line *----------------------------------------------------------------*/ void emit_line(char *line_no, char *line_body) { char line_bufr[500]; int k; int para_end; para_end = FALSE; strcpy(line_bufr, line_body); k = strlen(line_bufr); if (k > 0 && line_bufr[k-1] == '\n') { line_bufr[k-1] = '\0'; k--; } if (k > 0 && line_bufr[k-1] == '#') para_end = TRUE; if (k > 0 && (line_bufr[k-1] == '#' || line_bufr[k-1] == '-')) { line_bufr[k-1] = '\0'; k--; } printf("\\xr %s&\\xv %s\\cr\n", line_no, line_bufr); if (para_end) { printf("\\noalign{\\vskip9pt}\n"); } } /*----------------------------------------------------------------------- * Start new page *--------------------------------------------------------------------*/ void emit_new_page(char *pg) { printf("\\vfil\\eject\n"); printf("\\footline={\\xr\\hfil Page: %s\\hfil}\n", pg); } void main(int argc, char *argv[]) { #define TRUE 1 #define FALSE 0 char text_str[500]; char start_page[20]; char end_page[20]; char page_str[100]; char locus_str[100]; char line_str[100]; char hand_str[2]; char prev_page[20] = ""; char prev_locus[100] = ""; int found_start_page = FALSE; int found_end_page = FALSE; int first_page = TRUE; /* Verify one or two args - if one it is first page number, * if two, first and last */ if (argc == 2) { strcpy(start_page, argv[1]); strcpy(end_page, argv[1]); } else if (argc == 3) { strcpy(start_page, argv[1]); strcpy(end_page, argv[2]); } else { fprintf(stderr, "Usage: vtexfmt []\n"); exit(1); } /* Emit stuff for header */ emit_header(start_page); /* Read each line and process it */ while (get_next_line(start_page, end_page, page_str, locus_str, line_str, hand_str, text_str) != EOF) { /* If page break (not first page), close locus and go to new page */ if (strcmp(page_str, prev_page) != 0) { strcpy(prev_page, page_str); if (first_page) { first_page = FALSE; } else { emit_end_locus(); emit_new_page(page_str); } emit_locus(locus_str); emit_line(line_str, text_str); strcpy(prev_locus, locus_str); } else if (strcmp(locus_str, prev_locus) != 0) { emit_end_locus(); emit_locus(locus_str); emit_line(line_str, text_str); strcpy(prev_locus, locus_str); } else { emit_line(line_str, text_str); } } /* Finish last locus */ if (!first_page) { emit_end_locus(); } /* Emit bye */ printf("\\bye"); }