aboutsummaryrefslogtreecommitdiffstats
path: root/z43.c
diff options
context:
space:
mode:
Diffstat (limited to 'z43.c')
-rw-r--r--z43.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/z43.c b/z43.c
new file mode 100644
index 0000000..67013ef
--- /dev/null
+++ b/z43.c
@@ -0,0 +1,402 @@
+/*@z43.c:Language Service:LanguageChange, LanguageString@*********************/
+/* */
+/* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.17) */
+/* COPYRIGHT (C) 1991, 1999 Jeffrey H. Kingston */
+/* */
+/* Jeffrey H. Kingston (jeff@cs.usyd.edu.au) */
+/* Basser Department of Computer Science */
+/* The University of Sydney 2006 */
+/* AUSTRALIA */
+/* */
+/* This program is free software; you can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either Version 2, or (at your option) */
+/* any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
+/* */
+/* FILE: z43.c */
+/* MODULE: Language Service */
+/* EXTERNS: LanguageInit(), LanguageDefine(), LanguageChange(), */
+/* LanguageString(), LanguageHyph() */
+/* */
+/*****************************************************************************/
+#include "externs.h"
+#define INIT_LANGUAGE_NUM 100
+
+
+/*****************************************************************************/
+/* */
+/* LANGUAGE_TABLE */
+/* */
+/* A symbol table permitting access to language name records. */
+/* The table will automatically enlarge to accept any number of entries. */
+/* */
+/* ltab_new(newsize) New empty table, newsize capacity */
+/* ltab_insert(x, &S) Insert new language name object x into S */
+/* ltab_retrieve(str, S) Retrieve language name object named str */
+/* ltab_debug(S, fp) Debug print of table S to file fp */
+/* */
+/*****************************************************************************/
+
+typedef struct
+{ int langtab_size; /* size of table */
+ int langtab_count; /* number of objects held */
+ OBJECT langtab_item[1];
+} *LANGUAGE_TABLE;
+
+#define ltab_size(S) (S)->langtab_size
+#define ltab_count(S) (S)->langtab_count
+#define ltab_item(S, i) (S)->langtab_item[i]
+
+#define hash(pos, str, S) \
+{ FULL_CHAR *p = str; \
+ pos = *p++; \
+ while( *p ) pos += *p++; \
+ pos = pos % ltab_size(S); \
+}
+
+static LANGUAGE_TABLE ltab_new(int newsize)
+{ LANGUAGE_TABLE S; int i;
+ ifdebug(DMA, D, DebugRegisterUsage(MEM_LANG_TAB, 1,
+ 2*sizeof(int) + newsize * sizeof(OBJECT)));
+ S = (LANGUAGE_TABLE)
+ malloc(2*sizeof(int) + newsize * sizeof(OBJECT));
+ if( S == (LANGUAGE_TABLE) NULL )
+ Error(43, 1, "run out of memory enlarging language table", FATAL, no_fpos);
+ ltab_size(S) = newsize;
+ ltab_count(S) = 0;
+ for( i = 0; i < newsize; i++ ) ltab_item(S, i) = nilobj;
+ return S;
+} /* end ltab_new */
+
+static void ltab_insert(OBJECT x, LANGUAGE_TABLE *S);
+
+static LANGUAGE_TABLE ltab_rehash(LANGUAGE_TABLE S, int newsize)
+{ LANGUAGE_TABLE NewS; int i;
+ NewS = ltab_new(newsize);
+ for( i = 1; i <= ltab_size(S); i++ )
+ { if( ltab_item(S, i) != nilobj )
+ ltab_insert(ltab_item(S, i), &NewS);
+ }
+ free(S);
+ return NewS;
+} /* end ltab_rehash */
+
+static void ltab_insert(OBJECT x, LANGUAGE_TABLE *S)
+{ int pos; OBJECT z, link, y;
+ if( ltab_count(*S) == ltab_size(*S) - 1 ) /* one less since 0 unused */
+ *S = ltab_rehash(*S, 2*ltab_size(*S));
+ hash(pos, string(x), *S);
+ if( ltab_item(*S, pos) == nilobj ) New(ltab_item(*S, pos), ACAT);
+ z = ltab_item(*S, pos);
+ for( link = Down(z); link != z; link = NextDown(link) )
+ { Child(y, link);
+ if( StringEqual(string(x), string(y)) )
+ { Error(43, 2, "language name %s used twice (first at%s)",
+ FATAL, &fpos(x), string(x), EchoFilePos(&fpos(y)));
+ }
+ }
+ Link(ltab_item(*S, pos), x);
+} /* end ltab_insert */
+
+static OBJECT ltab_retrieve(FULL_CHAR *str, LANGUAGE_TABLE S)
+{ OBJECT x, link, y; int pos;
+ hash(pos, str, S);
+ x = ltab_item(S, pos);
+ if( x == nilobj ) return nilobj;
+ for( link = Down(x); link != x; link = NextDown(link) )
+ { Child(y, link);
+ if( StringEqual(str, string(y)) ) return y;
+ }
+ return nilobj;
+} /* end ltab_retrieve */
+
+#if DEBUG_ON
+static void ltab_debug(LANGUAGE_TABLE S, FILE *fp)
+{ int i; OBJECT x, link, y;
+ fprintf(fp, " table size: %d; current number of keys: %d\n",
+ ltab_size(S), ltab_count(S));
+ for( i = 0; i < ltab_size(S); i++ )
+ { x = ltab_item(S, i);
+ fprintf(fp, "ltab_item(S, %d) =", i);
+ if( x == nilobj )
+ fprintf(fp, " <nilobj>");
+ else if( type(x) != ACAT )
+ fprintf(fp, " not ACAT!");
+ else for( link = Down(x); link != x; link = NextDown(link) )
+ { Child(y, link);
+ fprintf(fp, " %s",
+ is_word(type(y)) ? string(y) : AsciiToFull("not-WORD!"));
+ }
+ fprintf(fp, "\n");
+ }
+} /* end ltab_debug */
+#endif
+
+
+static LANGUAGE_TABLE names_tab; /* the language names */
+static OBJECT *hyph_tab; /* arry of hyph filenames */
+static OBJECT *canonical_tab; /* array of lang names */
+static int lang_tabsize; /* size of prev two arrays */
+static int lang_count; /* number of languages */
+static OBJECT lang_ends[MAX_LANGUAGE];/* sentence endings */
+
+/*@@**************************************************************************/
+/* */
+/* BOOLEAN LanguageSentenceEnds[] */
+/* */
+/* LanguageSentenceEnds[ch] is TRUE if there exists a language in which */
+/* character ch could occur at the end of a sentence. */
+/* */
+/*****************************************************************************/
+
+BOOLEAN LanguageSentenceEnds[MAX_CHARS];
+
+
+/*@::LanguageInit(), LanguageDefine()@****************************************/
+/* */
+/* LanguageInit() */
+/* */
+/* Initialize this module. */
+/* */
+/*****************************************************************************/
+
+void LanguageInit(void)
+{ int i;
+ debug0(DLS, D, "LanguageInit()");
+ names_tab = ltab_new(INIT_LANGUAGE_NUM);
+ lang_count = 0;
+ lang_tabsize = INIT_LANGUAGE_NUM;
+ ifdebug(DMA, D, DebugRegisterUsage(MEM_LANG_TAB, 0,
+ INIT_LANGUAGE_NUM * sizeof(OBJECT)));
+ hyph_tab = (OBJECT *) malloc(INIT_LANGUAGE_NUM * sizeof(OBJECT));
+ ifdebug(DMA, D, DebugRegisterUsage(MEM_LANG_TAB, 0,
+ INIT_LANGUAGE_NUM * sizeof(OBJECT)));
+ canonical_tab = (OBJECT *) malloc(INIT_LANGUAGE_NUM * sizeof(OBJECT));
+ for( i = 0; i < MAX_CHARS; i++ ) LanguageSentenceEnds[i] = FALSE;
+ debug0(DLS, D, "LanguageInit returning.");
+} /* end LanguageInit */
+
+
+/*****************************************************************************/
+/* */
+/* LanguageDefine(names, inside) */
+/* */
+/* Define a language whose names are given by ACAT of words names, and */
+/* whose associated hyphenation patterns file name is hyph_file. */
+/* */
+/*****************************************************************************/
+
+void LanguageDefine(OBJECT names, OBJECT inside)
+{ OBJECT link, y, hyph_file; BOOLEAN junk; FULL_CHAR ch;
+ int len;
+ assert( names != nilobj && type(names) == ACAT, "LanguageDefine: names!");
+ assert( Down(names) != names, "LanguageDefine: names is empty!");
+ debug2(DLS, D, "LanguageDefine(%s, %s)",
+ EchoObject(names), EchoObject(inside));
+
+ /* double table size if overflow */
+ if( ++lang_count >= lang_tabsize )
+ {
+ ifdebug(DMA, D, DebugRegisterUsage(MEM_LANG_TAB, 0,
+ -lang_tabsize * sizeof(OBJECT)));
+ ifdebug(DMA, D, DebugRegisterUsage(MEM_LANG_TAB, 0,
+ -lang_tabsize * sizeof(OBJECT)));
+ lang_tabsize *= 2;
+ ifdebug(DMA, D, DebugRegisterUsage(MEM_LANG_TAB, 0,
+ lang_tabsize * sizeof(OBJECT)));
+ ifdebug(DMA, D, DebugRegisterUsage(MEM_LANG_TAB, 0,
+ lang_tabsize * sizeof(OBJECT)));
+ hyph_tab = (OBJECT *) realloc(hyph_tab, lang_tabsize * sizeof(OBJECT) );
+ canonical_tab = (OBJECT *) realloc(canonical_tab, lang_tabsize * sizeof(OBJECT) );
+ }
+
+ /* insert each language name into names_tab */
+ for( link = Down(names); link != names; link = NextDown(link) )
+ { Child(y, link);
+ assert( is_word(type(y)), "LanguageDefine: type(y) != WORD!" );
+ word_language(y) = lang_count;
+ ltab_insert(y, &names_tab);
+ }
+
+ /* initialize canonical language name entry */
+ Child(y, Down(names));
+ canonical_tab[lang_count] = y;
+
+ /* make inside an ACAT if it isn't already */
+ if( type(inside) != ACAT )
+ { New(y, ACAT);
+ FposCopy(fpos(y), fpos(inside));
+ Link(y, inside);
+ inside = y;
+ }
+
+ /* initialize hyphenation file entry (first child of inside) */
+ Child(hyph_file, Down(inside));
+ DeleteLink(Down(inside));
+ if( !is_word(type(hyph_file)) )
+ Error(43, 3, "hyphenation file name expected here",
+ FATAL, &fpos(inside));
+ if( StringEqual(string(hyph_file), STR_EMPTY) ||
+ StringEqual(string(hyph_file), STR_HYPHEN) )
+ { Dispose(hyph_file);
+ hyph_tab[lang_count] = nilobj;
+ }
+ else hyph_tab[lang_count] = hyph_file;
+
+ /* initialize sentence ends */
+ lang_ends[lang_count] = inside;
+ for( link = Down(inside); link != inside; link = NextDown(link) )
+ { Child(y, link);
+ if( type(y) == GAP_OBJ )
+ { link = PrevDown(link);
+ DisposeChild(NextDown(link));
+ continue;
+ }
+ if( !is_word(type(y)) )
+ { debug2(DLS, D, "word patterns failing on %s %s", Image(type(y)),
+ EchoObject(y));
+ Error(43, 4, "expected word ending pattern here", FATAL, &fpos(y));
+ }
+ len = StringLength(string(y));
+ if( len == 0 )
+ Error(43, 5, "empty word ending pattern", FATAL, &fpos(y));
+ ch = string(y)[len - 1];
+ LanguageSentenceEnds[ch] = TRUE;
+ }
+
+ /* if initializing run, initialize the hyphenation table */
+ if( InitializeAll )
+ { if( hyph_tab[lang_count] != nilobj )
+ junk = ReadHyphTable(lang_count);
+ }
+
+ debug0(DLS, D, "LanguageDefine returning.");
+} /* end LanguageDefine */
+
+
+/*****************************************************************************/
+/* */
+/* BOOLEAN LanguageWordEndsSentence(OBJECT wd, BOOLEAN lc_prec) */
+/* */
+/* Returns TRUE if word ends a sentence in the current language. This is */
+/* so if it ends with a string in the list associated with the current */
+/* language. If lc_prec is TRUE, it is also necessary for the character */
+/* preceding this suffix to be lower-case. */
+/* */
+/*****************************************************************************/
+
+BOOLEAN LanguageWordEndsSentence(OBJECT wd, BOOLEAN lc_prec)
+{ OBJECT x, y, link; int pos;
+ assert( is_word(type(wd)), "LanguageWordEndsSentence: wd!" );
+ debug2(DLS, D, "LanguageWordEndsSentence(%d %s)",
+ word_language(wd), EchoObject(wd));
+ x = lang_ends[word_language(wd)];
+ for( link = Down(x); link != x; link = NextDown(link) )
+ { Child(y, link);
+ if( StringEndsWith(string(wd), string(y)) )
+ {
+ if( !lc_prec )
+ { debug0(DLS, D, "LanguageWordEndsSentence returning TRUE (!lc_prec)");
+ return TRUE;
+ }
+
+ /* now check whether the preceding character is lower case */
+ pos = StringLength(string(wd)) - StringLength(string(y)) - 1;
+ if( pos >= 0 &&
+ MapIsLowerCase(string(wd)[pos], FontMapping(word_font(wd), &fpos(wd))))
+ {
+ debug0(DLS, D, "LanguageWordEndsSentence returning TRUE (!lc_prec)");
+ return TRUE;
+ }
+ }
+ }
+ debug0(DLS, D, "LanguageWordEndsSentence returning FALSE");
+ return FALSE;
+} /* end LanguageWordEndsSentence */
+
+
+/*@::LanguageChange(), LanguageString(), LanguageHyph()@**********************/
+/* */
+/* LanguageChange(style, x) */
+/* */
+/* Change the current style to contain the language of language command x. */
+/* */
+/*****************************************************************************/
+
+void LanguageChange(STYLE *style, OBJECT x)
+{ OBJECT lname;
+ debug2(DLS, D, "LanguageChange(%s, %s)", EchoStyle(style), EchoObject(x));
+
+ /* if argument is not a word, fail and exit */
+ if( !is_word(type(x)) )
+ { Error(43, 6, "%s ignored (illegal left parameter)", WARN, &fpos(x),
+ KW_LANGUAGE);
+ debug0(DLS, D, "LanguageChange returning (language unchanged)");
+ return;
+ }
+
+ /* if argument is empty, return unchanged */
+ if( StringEqual(string(x), STR_EMPTY) )
+ { debug0(DLS, D, "LanguageChange returning (empty, language unchanged)");
+ return;
+ }
+
+ /* retrieve language record if present, else leave style unchanged */
+ lname = ltab_retrieve(string(x), names_tab);
+ if( lname == nilobj )
+ Error(43, 7, "%s ignored (unknown language %s)", WARN, &fpos(x),
+ KW_LANGUAGE, string(x));
+ else language(*style) = word_language(lname);
+
+ debug1(DLS, D, "LanguageChange returning (language = %s)", string(lname));
+ ifdebug(DLS, DD, ltab_debug(names_tab, stderr));
+} /* LanguageChange */
+
+
+/*****************************************************************************/
+/* */
+/* FULL_CHAR *LanguageString(lnum) */
+/* */
+/* Return the canonical name of language lnum. */
+/* */
+/*****************************************************************************/
+
+FULL_CHAR *LanguageString(LANGUAGE_NUM lnum)
+{ FULL_CHAR *res;
+ debug1(DLS, D, "LanguageString(%d)", lnum);
+ assert( lnum > 0 && lnum <= lang_count, "LanguageString: unknown number" );
+
+ res = string(canonical_tab[lnum]);
+
+ debug1(DLS, D, "LanguageString returning %s", res);
+ return res;
+} /* end LanguageString */
+
+
+/*****************************************************************************/
+/* */
+/* OBJECT LanguageHyph(lnum) */
+/* */
+/* Return the hyphenation file name object for language lnum. */
+/* */
+/*****************************************************************************/
+
+OBJECT LanguageHyph(LANGUAGE_NUM lnum)
+{ OBJECT res;
+ debug1(DLS, D, "LanguageHyph(%d)", lnum);
+ assert( lnum > 0 && lnum <= lang_count, "LanguageHyph: unknown number" );
+
+ res = hyph_tab[lnum];
+
+ debug1(DLS, D, "LanguageHyph returning %s", EchoObject(res));
+ return res;
+} /* end LanguageHyph */