#include #include #include #include #include "config.h" /* Set in config.h */ extern const char *en; extern const char *es; /* Read a tag into a character array and return its length. */ int readtag(char *tag, FILE *in, FILE *out) { char ch; int i = 0; /* Data after a space in a tag is irrelevant. */ while ((ch = fgetc(in)) != '>' && ch != ' ') { fputc(ch, out); tag[i] = ch; ++i; } if (ch == ' ') { /* Seek to the end of the tag. */ while (ch != '>' && ch != EOF) { fputc(ch, out); ch = fgetc(in); } if (ch == EOF) { return -1; } fputc(ch, out); } else fputc(ch, out); tag[i] = '\0'; return i; } int cmptag(char *tag2, FILE *in, FILE *out) { char tag1[MAXWLEN]; readtag(tag1, in, out); return strcmp(tag1, tag2); } int checktag(char *tag, int tagamt, FILE *in, FILE *out) { int i; for (i = 0; i < tagamt; ++i) if (strcmp(tag, taglist[i]) == 0) return i; return -1; } /* Check if a character should be skipped. */ int checkskip(char ch, int skiplen) { int i; for (i = 0; i < skiplen; ++i) if (ch == skip[i]) return 1; return 0; } const char *punct = "';.,\"!?:"; /* Check if a character is punctuation. */ int checkpunct(char ch) { int i; for (i = 0; punct[i] != '\0'; ++i) if (ch == punct[i]) return 1; return 0; } const char *blank = " \n\r\t"; /* Check if a character is a blank. */ int checkblank(char ch) { int i; for (i = 0; blank[i] != '\0'; ++i) if (ch == blank[i]) return 1; return 0; } /* Loop until the body is found. */ int findbody(FILE *in, FILE *out) { char ch; while ((ch = fgetc(in)) != EOF) { fputc(ch, out); if (ch == '<' && cmptag("body", in, out) == 0) return 1; } return 0; } /* Hyphenate a word, by means of hyphen library. This is done so as to leverage sufficient hyphenation patterns, with the ones used here having been taken from those developed for TeX. */ void hypword(char *word, int len, FILE *in, FILE *out, HyphenDict *dict) { if (len < MINWLEN) { fprintf(out, "%s", word); return; } char *hyphens = calloc(len + 6, sizeof(char)); char *hyphword = calloc(len << 1, sizeof(char)); char **rep = NULL; int *pos = NULL, *cut = NULL; hnj_hyphen_hyphenate2(dict, word, len, hyphens, hyphword, &rep, &pos, &cut); /* fprintf(stderr, "%s\n%s\n%s\n", word, hyphens, hyphword); */ /* Process the given hyphenation. */ int i; char oldch = ' ', oldoldch = '\0'; for (i = 0; i < strlen(hyphword); ++i) { if (hyphword[i] == '=' && oldch != ' ' && oldoldch != ' ') fputs("­", out); else if (hyphword[i] != '=') fputc(hyphword[i], out); oldoldch = oldch; oldch = hyphword[i]; } free(hyphens); free(hyphword); } /* Hyphenate the words within a tag. */ void hyptag(FILE *in, FILE *out, int skiplen, char *tag, HyphenDict *dict) { char ch, word[MAXWLEN], term[MAXWLEN] = "/"; int i = 0; strcat(term, tag); while ((ch = fgetc(in)) != EOF) { if (i < 0) { fputc(ch, out); ++i; if (checkskip(ch, skiplen)) i -= 3; continue; } if (checkblank(ch)) { word[i] = '\0'; hypword(word, i, in, out, dict); i = 0; } if (checkpunct(ch)) { word[i] = '\0'; hypword(word, i, in, out, dict); fputc(ch, out); i = 0; } else if (checkskip(ch, skiplen)) { word[i] = '\0'; fputs(word, out); fputc(ch, out); /* A simple way of working around HTML character codes. Each is 5 ( epsiv ) or 6 ( hellip ) characters long, plus '&' and ';'. */ i = -3; } /* Check for closing tag. */ else if (ch == '<') { word[i] = ch; ++i; word[i] = '\0'; hypword(word, i, in, out, dict); i = 0; readtag(word, in, out); if (strcmp(word, term) == 0) break; } else { word[i] = ch; ++i; } if (i == MAXWLEN - 1) { word[i] = '\0'; hypword(word, i, in, out, dict); i = 0; } } } void usage() { fprintf(stderr, "%s\n", "hyp [-l language] [input] [output]"); } void fail(char *error) { fprintf(stderr, "%s\n", error); usage(); } /* Hyphenate HTML input via `­'. hyp [in] [out] */ int main(int argc, char **argv) { FILE *in = stdin; FILE *out = stdout; char *dictpath = calloc(pathbuf, sizeof(char)); for (argv++; *argv != NULL; argv++) { if (strcmp(*argv, "-l") == 0) { argv++; if (*argv == NULL) { fail("Incomplete language argument."); return -1; } if (strcmp(*argv, "en") == 0) { sprintf(dictpath, "%s/%s", buildpath, en); } else if (strcmp(*argv, "es") == 0) { sprintf(dictpath, "%s/%s", buildpath, es); } else { fail("Unknown language."); return -1; } } else if (in == stdin) { in = fopen(*argv, "r"); } else if (out == stdout) { out = fopen(*argv, "w"); } else { fail("Too many arguments."); return -1; } } if (in == NULL || out == NULL) { fail("Inaccessible file."); return -1; } /* Default language. */ if (*dictpath == '\0') { sprintf(dictpath, "%s/%s", buildpath, en); } if (findbody(in, out) == 0) { fputs("There is no body.", stderr); return 3; } HyphenDict *dict = hnj_hyphen_load(dictpath); if (dict == NULL) { fputs("Dict not readable.", stderr); return 4; } int tagamt = 0; while (taglist[tagamt][0] != '\0') ++tagamt; int skiplen = strlen(skip); char ch, tag[MAXWLEN]; int len; while ((ch = fgetc(in)) != EOF) { fputc(ch, out); if (ch == '<' && (len = readtag(tag, in, out)) > 0 && checktag(tag, tagamt, in, out) != -1) { hyptag(in, out, skiplen, tag, dict); } } return 0; }