Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(175)

Unified Diff: third_party/liblouis/overrides/liblouis/compileTranslationTable.c

Issue 67283007: Build liblouis_nacl using gyp. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: Don't copy build artifacts to final location (defered to the cl that lands all of chromevox). Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/liblouis/overrides/liblouis/compileTranslationTable.c
diff --git a/third_party/liblouis/overrides/liblouis/compileTranslationTable.c b/third_party/liblouis/overrides/liblouis/compileTranslationTable.c
new file mode 100644
index 0000000000000000000000000000000000000000..c73890f41d7116ab73b428fd7e00b9b76fd62959
--- /dev/null
+++ b/third_party/liblouis/overrides/liblouis/compileTranslationTable.c
@@ -0,0 +1,5221 @@
+/* liblouis Braille Translation and Back-Translation
+Library
+
+ Based on the Linux screenreader BRLTTY, copyright (C) 1999-2006 by
+ The BRLTTY Team
+
+ Copyright (C) 2004, 2005, 2006
+ ViewPlus Technologies, Inc. www.viewplus.com
+ and
+ JJB Software, Inc. www.jjb-software.com
+ All rights reserved
+
+ This file is free software; you can redistribute it and/or modify it
+ under the terms of the Lesser or Library GNU General Public License
+ as published by the
+ Free Software Foundation; either version 3, or (at your option) any
+ later version.
+
+ This file 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
+ Library GNU General Public License for more details.
+
+ You should have received a copy of the Library GNU General Public
+ License along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ Maintained by John J. Boyer john.boyer@jjb-software.com
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+//#include <unistd.h>
+
+#include "louis.h"
+#include "config.h"
+
+#define QUOTESUB 28 /*Stand-in for double quotes in strings */
+
+
+/* Contributed by Michel Such <michel.such@free.fr */
+#ifdef _WIN32
+
+/* Adapted from BRLTTY code (see sys_progs_wihdows.h) */
+
+#include <shlobj.h>
+
+static void
+noMemory (void)
+{
+ printf ("Insufficient memory: %s", strerror (errno), "\n");
+ exit (3);
+}
+
+static void *
+reallocWrapper (void *address, size_t size)
+{
+ if (!(address = realloc (address, size)) && size)
+ noMemory ();
+ return address;
+}
+
+static char *
+strdupWrapper (const char *string)
+{
+ char *address = strdup (string);
+ if (!address)
+ noMemory ();
+ return address;
+}
+
+char *EXPORT_CALL
+lou_getProgramPath (void)
+{
+ char *path = NULL;
+ HMODULE handle;
+
+ if ((handle = GetModuleHandle (NULL)))
+ {
+ size_t size = 0X80;
+ char *buffer = NULL;
+
+ while (1)
+ {
+ buffer = reallocWrapper (buffer, size <<= 1);
+
+ {
+ DWORD length = GetModuleFileName (handle, buffer, size);
+
+ if (!length)
+ {
+ printf ("GetModuleFileName\n");
+ exit (3);
+ 3;
+ }
+
+ if (length < size)
+ {
+ buffer[length] = 0;
+ path = strdupWrapper (buffer);
+
+ while (length > 0)
+ if (path[--length] == '\\')
+ break;
+
+ strncpy (path, path, length + 1);
+ path[length + 1] = '\0';
+ break;
+ }
+ }
+ }
+
+ free (buffer);
+ }
+ else
+ {
+ printf ("GetModuleHandle\n");
+ exit (3);
+ }
+
+ return path;
+}
+
+#define PATH_SEP ';'
+#define DIR_SEP '\\'
+#else
+#define PATH_SEP ':'
+#define DIR_SEP '/'
+#endif
+/* End of MS contribution */
+
+#ifdef ANDROID
+#include "android/log.h"
+#endif
+
+/* The folowing variables and functions make it possible to specify the
+* path on which all tables for liblouis and all files for liblouisutdml,
+* in their proper directories, will be found.
+*/
+
+static char dataPath[MAXSTRING];
+static char *dataPathPtr;
+
+char *EXPORT_CALL
+lou_setDataPath (char *path)
+{
+ dataPathPtr = NULL;
+ if (path == NULL)
+ return NULL;
+ strcpy (dataPath, path);
+ dataPathPtr = dataPath;
+ return dataPathPtr;
+}
+
+char *EXPORT_CALL
+lou_getDataPath ()
+{
+ return dataPathPtr;
+}
+
+/* End of dataPath code.*/
+
+static char tablePath[MAXSTRING];
+static FILE *logFile = NULL;
+static char initialLogFileName[256];
+
+void EXPORT_CALL
+lou_logFile (const char *fileName)
+{
+ if (fileName == NULL || fileName[0] == 0)
+ return;
+ if (initialLogFileName[0] == 0)
+ strcpy (initialLogFileName, fileName);
+ logFile = fopen (fileName, "wb");
+ if (logFile == NULL && initialLogFileName[0] != 0)
+ logFile = fopen (initialLogFileName, "wb");
+ if (logFile == NULL)
+ {
+ fprintf (stderr, "Cannot open log file %s\n", fileName);
+ logFile = stderr;
+ }
+}
+
+void EXPORT_CALL
+lou_logPrint (char *format, ...)
+{
+#ifndef __SYMBIAN32__
+ va_list argp;
+ if (format == NULL)
+ return;
+ if (logFile == NULL && initialLogFileName[0] != 0)
+ logFile = fopen (initialLogFileName, "wb");
+ if (logFile == NULL)
+ logFile = stderr;
+ va_start (argp, format);
+#ifndef ANDROID
+ vfprintf (logFile, format, argp);
+ fprintf (logFile, "\n");
+#else
+ __android_log_vprint(ANDROID_LOG_DEBUG, "liblouis", format, argp);
+#endif
+ va_end (argp);
+#endif
+}
+
+void EXPORT_CALL
+lou_logEnd (void)
+{
+ if (logFile != NULL)
+ fclose (logFile);
+ logFile = NULL;
+}
+
+static int
+eqasc2uni (const unsigned char *a, const widechar * b, const int len)
+{
+ int k;
+ for (k = 0; k < len; k++)
+ if ((widechar) a[k] != b[k])
+ return 0;
+ return 1;
+}
+
+typedef struct
+{
+ widechar length;
+ widechar chars[MAXSTRING];
+}
+CharsString;
+
+static int errorCount;
+static int warningCount;
+static TranslationTableHeader *table;
+static TranslationTableOffset tableSize;
+static TranslationTableOffset tableUsed;
+
+static const char *characterClassNames[] = {
+ "space",
+ "letter",
+ "digit",
+ "punctuation",
+ "uppercase",
+ "lowercase",
+ "math",
+ "sign",
+ "litdigit",
+ NULL
+};
+
+struct CharacterClass
+{
+ struct CharacterClass *next;
+ TranslationTableCharacterAttributes attribute;
+ widechar length;
+ widechar name[1];
+};
+static struct CharacterClass *characterClasses;
+static TranslationTableCharacterAttributes characterClassAttribute;
+
+static const char *opcodeNames[CTO_None] = {
+ "include",
+ "locale",
+ "undefined",
+ "capsign",
+ "begcaps",
+ "lenbegcaps",
+ "endcaps",
+ "firstwordcaps",
+ "lastwordbeforecaps",
+ "lastwordaftercaps",
+ "lencapsphrase",
+ "letsign",
+ "noletsignbefore",
+ "noletsign",
+ "noletsignafter",
+ "numsign",
+ "firstwordital",
+ "italsign",
+ "lastworditalbefore",
+ "lastworditalafter",
+ "begital",
+ "firstletterital",
+ "endital",
+ "lastletterital",
+ "singleletterital",
+ "italword",
+ "lenitalphrase",
+ "firstwordbold",
+ "boldsign",
+ "lastwordboldbefore",
+ "lastwordboldafter",
+ "begbold",
+ "firstletterbold",
+ "endbold",
+ "lastletterbold",
+ "singleletterbold",
+ "boldword",
+ "lenboldphrase",
+ "firstwordunder",
+ "undersign",
+ "lastwordunderbefore",
+ "lastwordunderafter",
+ "begunder",
+ "firstletterunder",
+ "endunder",
+ "lastletterunder",
+ "singleletterunder",
+ "underword",
+ "lenunderphrase",
+ "begcomp",
+ "compbegemph1",
+ "compendemph1",
+ "compbegemph2",
+ "compendemph2",
+ "compbegemph3",
+ "compendemph3",
+ "compcapsign",
+ "compbegcaps",
+ "compendcaps",
+ "endcomp",
+ "multind",
+ "compdots",
+ "comp6",
+ "class",
+ "after",
+ "before",
+ "noback",
+ "nofor",
+ "swapcc",
+ "swapcd",
+ "swapdd",
+ "space",
+ "digit",
+ "punctuation",
+ "math",
+ "sign",
+ "letter",
+ "uppercase",
+ "lowercase",
+ "grouping",
+ "uplow",
+ "litdigit",
+ "display",
+ "replace",
+ "context",
+ "correct",
+ "pass2",
+ "pass3",
+ "pass4",
+ "repeated",
+ "repword",
+ "capsnocont",
+ "always",
+ "exactdots",
+ "nocross",
+ "syllable",
+ "nocont",
+ "compbrl",
+ "literal",
+ "largesign",
+ "word",
+ "partword",
+ "joinnum",
+ "joinword",
+ "lowword",
+ "contraction",
+ "sufword",
+ "prfword",
+ "begword",
+ "begmidword",
+ "midword",
+ "midendword",
+ "endword",
+ "prepunc",
+ "postpunc",
+ "begnum",
+ "midnum",
+ "endnum",
+ "decpoint",
+ "hyphen",
+ "nobreak"
+};
+static short opcodeLengths[CTO_None] = { 0 };
+
+typedef enum
+{ noEncoding, bigEndian, littleEndian, ascii8 } EncodingType;
+
+
+typedef struct
+{
+ const char *fileName;
+ FILE *in;
+ int lineNumber;
+ EncodingType encoding;
+ int status;
+ int linelen;
+ int linepos;
+ int checkencoding[2];
+ widechar line[MAXSTRING];
+}
+FileInfo;
+
+static char scratchBuf[MAXSTRING];
+
+char *
+showString (widechar const *chars, int length)
+{
+/*Translate a string of characters to the encoding used in character
+* operands */
+ int charPos;
+ int bufPos = 0;
+ scratchBuf[bufPos++] = '\'';
+ for (charPos = 0; charPos < length; charPos++)
+ {
+ if (chars[charPos] >= 32 && chars[charPos] < 127)
+ scratchBuf[bufPos++] = (char) chars[charPos];
+ else
+ {
+ char hexbuf[20];
+ int hexLength;
+ char escapeLetter;
+
+ int leadingZeros;
+ int hexPos;
+ hexLength = sprintf (hexbuf, "%x", chars[charPos]);
+ switch (hexLength)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ escapeLetter = 'x';
+ leadingZeros = 4 - hexLength;
+ break;
+ case 5:
+ escapeLetter = 'y';
+ leadingZeros = 0;
+ break;
+ case 6:
+ case 7:
+ case 8:
+ escapeLetter = 'z';
+ leadingZeros = 8 - hexLength;
+ break;
+ default:
+ escapeLetter = '?';
+ leadingZeros = 0;
+ break;
+ }
+ if ((bufPos + leadingZeros + hexLength + 4) >= sizeof (scratchBuf))
+ break;
+ scratchBuf[bufPos++] = '\\';
+ scratchBuf[bufPos++] = escapeLetter;
+ for (hexPos = 0; hexPos < leadingZeros; hexPos++)
+ scratchBuf[bufPos++] = '0';
+ for (hexPos = 0; hexPos < hexLength; hexPos++)
+ scratchBuf[bufPos++] = hexbuf[hexPos];
+ }
+ }
+ scratchBuf[bufPos++] = '\'';
+ scratchBuf[bufPos] = 0;
+ return scratchBuf;
+}
+
+char *
+showDots (widechar const *dots, int length)
+{
+/* Translate a sequence of dots to the encoding used in dots operands.
+*/
+ int bufPos = 0;
+ int dotsPos;
+ for (dotsPos = 0; bufPos < sizeof (scratchBuf) && dotsPos < length;
+ dotsPos++)
+ {
+ if ((dots[dotsPos] & B1))
+ scratchBuf[bufPos++] = '1';
+ if ((dots[dotsPos] & B2))
+ scratchBuf[bufPos++] = '2';
+ if ((dots[dotsPos] & B3))
+ scratchBuf[bufPos++] = '3';
+ if ((dots[dotsPos] & B4))
+ scratchBuf[bufPos++] = '4';
+ if ((dots[dotsPos] & B5))
+ scratchBuf[bufPos++] = '5';
+ if ((dots[dotsPos] & B6))
+ scratchBuf[bufPos++] = '6';
+ if ((dots[dotsPos] & B7))
+ scratchBuf[bufPos++] = '7';
+ if ((dots[dotsPos] & B8))
+ scratchBuf[bufPos++] = '8';
+ if ((dots[dotsPos] & B9))
+ scratchBuf[bufPos++] = '9';
+ if ((dots[dotsPos] & B10))
+ scratchBuf[bufPos++] = 'A';
+ if ((dots[dotsPos] & B11))
+ scratchBuf[bufPos++] = 'B';
+ if ((dots[dotsPos] & B12))
+ scratchBuf[bufPos++] = 'C';
+ if ((dots[dotsPos] & B13))
+ scratchBuf[bufPos++] = 'D';
+ if ((dots[dotsPos] & B14))
+ scratchBuf[bufPos++] = 'E';
+ if ((dots[dotsPos] & B15))
+ scratchBuf[bufPos++] = 'F';
+ if ((dots[dotsPos] == B16))
+ scratchBuf[bufPos++] = '0';
+ if (dotsPos != length - 1)
+ scratchBuf[bufPos++] = '-';
+ }
+ scratchBuf[bufPos] = 0;
+ return &scratchBuf[0];
+}
+
+char *
+showAttributes (TranslationTableCharacterAttributes a)
+{
+/* Show attributes using the letters used after the $ in multipass
+* opcodes. */
+ int bufPos = 0;
+ if ((a & CTC_Space))
+ scratchBuf[bufPos++] = 's';
+ if ((a & CTC_Letter))
+ scratchBuf[bufPos++] = 'l';
+ if ((a & CTC_Digit))
+ scratchBuf[bufPos++] = 'd';
+ if ((a & CTC_Punctuation))
+ scratchBuf[bufPos++] = 'p';
+ if ((a & CTC_UpperCase))
+ scratchBuf[bufPos++] = 'U';
+ if ((a & CTC_LowerCase))
+ scratchBuf[bufPos++] = 'u';
+ if ((a & CTC_Math))
+ scratchBuf[bufPos++] = 'm';
+ if ((a & CTC_Sign))
+ scratchBuf[bufPos++] = 'S';
+ if ((a & CTC_LitDigit))
+ scratchBuf[bufPos++] = 'D';
+ if ((a & CTC_Class1))
+ scratchBuf[bufPos++] = 'w';
+ if ((a & CTC_Class2))
+ scratchBuf[bufPos++] = 'x';
+ if ((a & CTC_Class3))
+ scratchBuf[bufPos++] = 'y';
+ if ((a & CTC_Class4))
+ scratchBuf[bufPos++] = 'z';
+ scratchBuf[bufPos] = 0;
+ return scratchBuf;
+}
+
+static void compileError (FileInfo * nested, char *format, ...);
+
+static int
+getAChar (FileInfo * nested)
+{
+/*Read a big endian, little *ndian or ASCII 8 file and convert it to
+* 16- or 32-bit unsigned integers */
+ int ch1 = 0, ch2 = 0;
+ widechar character;
+ if (nested->encoding == ascii8)
+ if (nested->status == 2)
+ {
+ nested->status++;
+ return nested->checkencoding[1];
+ }
+ while ((ch1 = fgetc (nested->in)) != EOF)
+ {
+ if (nested->status < 2)
+ nested->checkencoding[nested->status] = ch1;
+ nested->status++;
+ if (nested->status == 2)
+ {
+ if (nested->checkencoding[0] == 0xfe
+ && nested->checkencoding[1] == 0xff)
+ nested->encoding = bigEndian;
+ else if (nested->checkencoding[0] == 0xff
+ && nested->checkencoding[1] == 0xfe)
+ nested->encoding = littleEndian;
+ else if (nested->checkencoding[0] < 128
+ && nested->checkencoding[1] < 128)
+ {
+ nested->encoding = ascii8;
+ return nested->checkencoding[0];
+ }
+ else
+ {
+ compileError (nested,
+ "encoding is neither big-endian, little-endian nor ASCII 8.");
+ ch1 = EOF;
+ break;;
+ }
+ continue;
+ }
+ switch (nested->encoding)
+ {
+ case noEncoding:
+ break;
+ case ascii8:
+ return ch1;
+ break;
+ case bigEndian:
+ ch2 = fgetc (nested->in);
+ if (ch2 == EOF)
+ break;
+ character = (ch1 << 8) | ch2;
+ return (int) character;
+ break;
+ case littleEndian:
+ ch2 = fgetc (nested->in);
+ if (ch2 == EOF)
+ break;
+ character = (ch2 << 8) | ch1;
+ return (int) character;
+ break;
+ }
+ if (ch1 == EOF || ch2 == EOF)
+ break;
+ }
+ return EOF;
+}
+
+static int
+getALine (FileInfo * nested)
+{
+/*Read a line of widechar's from an input file */
+ int ch;
+ int pch = 0;
+ nested->linelen = 0;
+ while ((ch = getAChar (nested)) != EOF)
+ {
+ if (ch == 13)
+ continue;
+ if (pch == '\\' && ch == 10)
+ {
+ nested->linelen--;
+ continue;
+ }
+ if (ch == 10 || nested->linelen >= MAXSTRING)
+ break;
+ nested->line[nested->linelen++] = (widechar) ch;
+ pch = ch;
+ }
+ nested->line[nested->linelen] = 0;
+ nested->linepos = 0;
+ if (ch == EOF)
+ return 0;
+ nested->lineNumber++;
+ return 1;
+}
+
+static int lastToken;
+static int
+getToken (FileInfo * nested, CharsString * result, const char *description)
+{
+/*Find the next string of contiguous non-whitespace characters. If this
+ * is the last token on the line, return 2 instead of 1. */
+ while (nested->line[nested->linepos] && nested->line[nested->linepos] <= 32)
+ nested->linepos++;
+ result->length = 0;
+ while (nested->line[nested->linepos] && nested->line[nested->linepos] > 32)
+ result->chars[result->length++] = nested->line[nested->linepos++];
+ if (!result->length)
+ {
+ /* Not enough tokens */
+ if (description)
+ compileError (nested, "%s not specified.", description);
+ return 0;
+ }
+ result->chars[result->length] = 0;
+ while (nested->line[nested->linepos] && nested->line[nested->linepos] <= 32)
+ nested->linepos++;
+ if (nested->line[nested->linepos] == 0)
+ {
+ lastToken = 1;
+ return 2;
+ }
+ else
+ {
+ lastToken = 0;
+ return 1;
+ }
+}
+
+static void
+compileError (FileInfo * nested, char *format, ...)
+{
+#ifndef __SYMBIAN32__
+ char buffer[MAXSTRING];
+ va_list arguments;
+ va_start (arguments, format);
+#ifdef _WIN32
+ (void) _vsnprintf (buffer, sizeof (buffer), format, arguments);
+#else
+ (void) vsnprintf (buffer, sizeof (buffer), format, arguments);
+#endif
+ va_end (arguments);
+ if (nested)
+ lou_logPrint ("%s:%d: error: %s", nested->fileName,
+ nested->lineNumber, buffer);
+ else
+ lou_logPrint ("error: %s", buffer);
+ errorCount++;
+#endif
+}
+
+static void
+compileWarning (FileInfo * nested, char *format, ...)
+{
+#ifndef __SYMBIAN32__
+ char buffer[MAXSTRING];
+ va_list arguments;
+ va_start (arguments, format);
+#ifdef _WIN32
+ (void) _vsnprintf (buffer, sizeof (buffer), format, arguments);
+#else
+ (void) vsnprintf (buffer, sizeof (buffer), format, arguments);
+#endif
+ va_end (arguments);
+ if (nested)
+ lou_logPrint ("%s:%d: warning: %s", nested->fileName,
+ nested->lineNumber, buffer);
+ else
+ lou_logPrint ("warning: %s", buffer);
+ warningCount++;
+#endif
+}
+
+static int
+allocateSpaceInTable (FileInfo * nested, TranslationTableOffset * offset,
+ int count)
+{
+/* allocate memory for translation table and expand previously allocated
+* memory if necessary */
+ int spaceNeeded = ((count + OFFSETSIZE - 1) / OFFSETSIZE) * OFFSETSIZE;
+ TranslationTableOffset size = tableUsed + spaceNeeded;
+ if (size > tableSize)
+ {
+ void *newTable;
+ size += (size / OFFSETSIZE);
+ newTable = realloc (table, size);
+ if (!newTable)
+ {
+ compileError (nested, "Not enough memory for translation table.");
+ return 0;
+ }
+ memset (((unsigned char *) newTable) + tableSize, 0, size - tableSize);
+ table = (TranslationTableHeader *) newTable;
+ tableSize = size;
+ }
+ if (offset != NULL)
+ {
+ *offset = (tableUsed - sizeof (*table)) / OFFSETSIZE;
+ tableUsed += spaceNeeded;
+ }
+ return 1;
+}
+
+static int
+reserveSpaceInTable (FileInfo * nested, int count)
+{
+ return (allocateSpaceInTable (nested, NULL, count));
+}
+
+static int
+allocateHeader (FileInfo * nested)
+{
+/*Allocate memory for the table header and a guess on the number of
+* rules */
+ const TranslationTableOffset startSize = 2 * sizeof (*table);
+ if (table)
+ return 1;
+ tableUsed = sizeof (*table) + OFFSETSIZE; /*So no offset is ever zero */
+ if (!(table = malloc (startSize)))
+ {
+ compileError (nested, "Not enough memory");
+ if (table != NULL)
+ free (table);
+ table = NULL;
+ return 0;
+ }
+ memset (table, 0, startSize);
+ tableSize = startSize;
+ return 1;
+}
+
+int
+stringHash (const widechar * c)
+{
+/*hash function for strings */
+ unsigned long int makeHash = (((unsigned long int) c[0] << 8) +
+ (unsigned long int) c[1]) % HASHNUM;
+ return (int) makeHash;
+}
+
+int
+charHash (widechar c)
+{
+ unsigned long int makeHash = (unsigned long int) c % HASHNUM;
+ return (int) makeHash;
+}
+
+static TranslationTableCharacter *
+compile_findCharOrDots (widechar c, int m)
+{
+/*Look up a character or dot pattern. If m is 0 look up a character,
+* otherwise look up a dot pattern. Although the algorithms are almost
+* identical, different tables are needed for characters and dots because
+* of the possibility of conflicts.*/
+ TranslationTableCharacter *character;
+ TranslationTableOffset bucket;
+ unsigned long int makeHash = (unsigned long int) c % HASHNUM;
+ if (m == 0)
+ bucket = table->characters[makeHash];
+ else
+ bucket = table->dots[makeHash];
+ while (bucket)
+ {
+ character = (TranslationTableCharacter *) & table->ruleArea[bucket];
+ if (character->realchar == c)
+ return character;
+ bucket = character->next;
+ }
+ return NULL;
+}
+
+static TranslationTableCharacter noChar = { 0, 0, 0, CTC_Space, 32, 32, 32 };
+static TranslationTableCharacter noDots =
+ { 0, 0, 0, CTC_Space, B16, B16, B16 };
+static char *unknownDots (widechar dots);
+
+static TranslationTableCharacter *
+definedCharOrDots (FileInfo * nested, widechar c, int m)
+{
+ TranslationTableCharacter *notFound;
+ TranslationTableCharacter *charOrDots = compile_findCharOrDots (c, m);
+ if (charOrDots)
+ return charOrDots;
+ if (m == 0)
+ {
+ notFound = &noChar;
+ compileError (nested,
+ "character %s should be defined at this point but is not",
+ showString (&c, 1));
+ }
+ else
+ {
+ notFound = &noDots;
+ compileError (nested,
+ "cell %s should be defined at this point but is not",
+ unknownDots (c));
+ }
+ return notFound;
+}
+
+static TranslationTableCharacter *
+addCharOrDots (FileInfo * nested, widechar c, int m)
+{
+/*See if a character or dot pattern is in the appropriate table. If not,
+* insert it. In either
+* case, return a pointer to it. */
+ TranslationTableOffset bucket;
+ TranslationTableCharacter *character;
+ TranslationTableCharacter *oldchar;
+ TranslationTableOffset offset;
+ unsigned long int makeHash;
+ if ((character = compile_findCharOrDots (c, m)))
+ return character;
+ if (!allocateSpaceInTable (nested, &offset, sizeof (*character)))
+ return NULL;
+ character = (TranslationTableCharacter *) & table->ruleArea[offset];
+ memset (character, 0, sizeof (*character));
+ character->realchar = c;
+ makeHash = (unsigned long int) c % HASHNUM;
+ if (m == 0)
+ bucket = table->characters[makeHash];
+ else
+ bucket = table->dots[makeHash];
+ if (!bucket)
+ {
+ if (m == 0)
+ table->characters[makeHash] = offset;
+ else
+ table->dots[makeHash] = offset;
+ }
+ else
+ {
+ oldchar = (TranslationTableCharacter *) & table->ruleArea[bucket];
+ while (oldchar->next)
+ oldchar =
+ (TranslationTableCharacter *) & table->ruleArea[oldchar->next];
+ oldchar->next = offset;
+ }
+ return character;
+}
+
+static CharOrDots *
+getCharOrDots (widechar c, int m)
+{
+ CharOrDots *cdPtr;
+ TranslationTableOffset bucket;
+ unsigned long int makeHash = (unsigned long int) c % HASHNUM;
+ if (m == 0)
+ bucket = table->charToDots[makeHash];
+ else
+ bucket = table->dotsToChar[makeHash];
+ while (bucket)
+ {
+ cdPtr = (CharOrDots *) & table->ruleArea[bucket];
+ if (cdPtr->lookFor == c)
+ return cdPtr;
+ bucket = cdPtr->next;
+ }
+ return NULL;
+}
+
+widechar
+getDotsForChar (widechar c)
+{
+ CharOrDots *cdPtr = getCharOrDots (c, 0);
+ if (cdPtr)
+ return cdPtr->found;
+ return B16;
+}
+
+widechar
+getCharFromDots (widechar d)
+{
+ CharOrDots *cdPtr = getCharOrDots (d, 1);
+ if (cdPtr)
+ return cdPtr->found;
+ return ' ';
+}
+
+static int
+putCharAndDots (FileInfo * nested, widechar c, widechar d)
+{
+ TranslationTableOffset bucket;
+ CharOrDots *cdPtr;
+ CharOrDots *oldcdPtr = NULL;
+ TranslationTableOffset offset;
+ unsigned long int makeHash;
+ if (!(cdPtr = getCharOrDots (c, 0)))
+ {
+ if (!allocateSpaceInTable (nested, &offset, sizeof (*cdPtr)))
+ return 0;
+ cdPtr = (CharOrDots *) & table->ruleArea[offset];
+ cdPtr->next = 0;
+ cdPtr->lookFor = c;
+ cdPtr->found = d;
+ makeHash = (unsigned long int) c % HASHNUM;
+ bucket = table->charToDots[makeHash];
+ if (!bucket)
+ table->charToDots[makeHash] = offset;
+ else
+ {
+ oldcdPtr = (CharOrDots *) & table->ruleArea[bucket];
+ while (oldcdPtr->next)
+ oldcdPtr = (CharOrDots *) & table->ruleArea[oldcdPtr->next];
+ oldcdPtr->next = offset;
+ }
+ }
+ if (!(cdPtr = getCharOrDots (d, 1)))
+ {
+ if (!allocateSpaceInTable (nested, &offset, sizeof (*cdPtr)))
+ return 0;
+ cdPtr = (CharOrDots *) & table->ruleArea[offset];
+ cdPtr->next = 0;
+ cdPtr->lookFor = d;
+ cdPtr->found = c;
+ makeHash = (unsigned long int) d % HASHNUM;
+ bucket = table->dotsToChar[makeHash];
+ if (!bucket)
+ table->dotsToChar[makeHash] = offset;
+ else
+ {
+ oldcdPtr = (CharOrDots *) & table->ruleArea[bucket];
+ while (oldcdPtr->next)
+ oldcdPtr = (CharOrDots *) & table->ruleArea[oldcdPtr->next];
+ oldcdPtr->next = offset;
+ }
+ }
+ return 1;
+}
+
+static char *
+unknownDots (widechar dots)
+{
+/*Print out dot numbers */
+ static char buffer[20];
+ int k = 1;
+ buffer[0] = '\\';
+ if ((dots & B1))
+ buffer[k++] = '1';
+ if ((dots & B2))
+ buffer[k++] = '2';
+ if ((dots & B3))
+ buffer[k++] = '3';
+ if ((dots & B4))
+ buffer[k++] = '4';
+ if ((dots & B5))
+ buffer[k++] = '5';
+ if ((dots & B6))
+ buffer[k++] = '6';
+ if ((dots & B7))
+ buffer[k++] = '7';
+ if ((dots & B8))
+ buffer[k++] = '8';
+ if ((dots & B9))
+ buffer[k++] = '9';
+ if ((dots & B10))
+ buffer[k++] = 'A';
+ if ((dots & B11))
+ buffer[k++] = 'B';
+ if ((dots & B12))
+ buffer[k++] = 'C';
+ if ((dots & B13))
+ buffer[k++] = 'D';
+ if ((dots & B14))
+ buffer[k++] = 'E';
+ if ((dots & B15))
+ buffer[k++] = 'F';
+ buffer[k++] = '/';
+ buffer[k] = 0;
+ return buffer;
+}
+
+static TranslationTableOffset newRuleOffset = 0;
+static TranslationTableRule *newRule = NULL;
+
+static int
+charactersDefined (FileInfo * nested)
+{
+/*Check that all characters are defined by character-definition
+* opcodes*/
+ int noErrors = 1;
+ int k;
+ if ((newRule->opcode >= CTO_Space && newRule->opcode <= CTO_LitDigit)
+ || newRule->opcode == CTO_SwapDd
+ ||
+ newRule->opcode == CTO_Replace || newRule->opcode == CTO_MultInd
+ || newRule->opcode == CTO_Repeated ||
+ ((newRule->opcode >= CTO_Context && newRule->opcode <=
+ CTO_Pass4) && newRule->opcode != CTO_Correct))
+ return 1;
+ for (k = 0; k < newRule->charslen; k++)
+ if (!compile_findCharOrDots (newRule->charsdots[k], 0))
+ {
+ compileError (nested, "Character %s is not defined", showString
+ (&newRule->charsdots[k], 1));
+ noErrors = 0;
+ }
+ if (!(newRule->opcode == CTO_Correct || newRule->opcode ==
+ CTO_NoBreak || newRule->opcode == CTO_SwapCc || newRule->opcode ==
+ CTO_SwapCd))
+ {
+ for (k = newRule->charslen; k < newRule->charslen + newRule->dotslen;
+ k++)
+ if (!compile_findCharOrDots (newRule->charsdots[k], 1))
+ {
+ compileError (nested, "Dot pattern %s is not defined.",
+ unknownDots (newRule->charsdots[k]));
+ noErrors = 0;
+ }
+ }
+ return noErrors;
+}
+
+static int noback = 0;
+static int nofor = 0;
+
+/*The following functions are
+called by addRule to handle various
+* cases.*/
+
+static void
+add_0_single (FileInfo * nested)
+{
+/*direction = 0, newRule->charslen = 1*/
+ TranslationTableRule *currentRule;
+ TranslationTableOffset *currentOffsetPtr;
+ TranslationTableCharacter *character;
+ int m = 0;
+ if (newRule->opcode == CTO_CompDots || newRule->opcode == CTO_Comp6)
+ return;
+ if (newRule->opcode >= CTO_Pass2 && newRule->opcode <= CTO_Pass4)
+ m = 1;
+ character = definedCharOrDots (nested, newRule->charsdots[0], m);
+ if (m != 1 && character->attributes & CTC_Letter && (newRule->opcode
+ ==
+ CTO_WholeWord
+ || newRule->opcode ==
+ CTO_LargeSign))
+ {
+ if (table->noLetsignCount < LETSIGNSIZE)
+ table->noLetsign[table->noLetsignCount++] = newRule->charsdots[0];
+ }
+ if (newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow)
+ character->definitionRule = newRuleOffset;
+ currentOffsetPtr = &character->otherRules;
+ while (*currentOffsetPtr)
+ {
+ currentRule = (TranslationTableRule *)
+ & table->ruleArea[*currentOffsetPtr];
+ if (currentRule->charslen == 0)
+ break;
+ if (currentRule->opcode >= CTO_Space && currentRule->opcode < CTO_UpLow)
+ if (!(newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow))
+ break;
+ currentOffsetPtr = &currentRule->charsnext;
+ }
+ newRule->charsnext = *currentOffsetPtr;
+ *currentOffsetPtr = newRuleOffset;
+}
+
+static void
+add_0_multiple (void)
+{
+/*direction = 0 newRule->charslen > 1*/
+ TranslationTableRule *currentRule = NULL;
+ TranslationTableOffset *currentOffsetPtr =
+ &table->forRules[stringHash (&newRule->charsdots[0])];
+ while (*currentOffsetPtr)
+ {
+ currentRule = (TranslationTableRule *)
+ & table->ruleArea[*currentOffsetPtr];
+ if (newRule->charslen > currentRule->charslen)
+ break;
+ if (newRule->charslen == currentRule->charslen)
+ if ((currentRule->opcode == CTO_Always)
+ && (newRule->opcode != CTO_Always))
+ break;
+ currentOffsetPtr = &currentRule->charsnext;
+ }
+ newRule->charsnext = *currentOffsetPtr;
+ *currentOffsetPtr = newRuleOffset;
+}
+
+static void
+add_1_single (FileInfo * nested)
+{
+/*direction = 1, newRule->dotslen = 1*/
+ TranslationTableRule *currentRule;
+ TranslationTableOffset *currentOffsetPtr;
+ TranslationTableCharacter *dots;
+ if (newRule->opcode == CTO_NoBreak || newRule->opcode == CTO_SwapCc ||
+ (newRule->opcode >= CTO_Context
+ &&
+ newRule->opcode <= CTO_Pass4)
+ || newRule->opcode == CTO_Repeated || (newRule->opcode == CTO_Always
+ && newRule->charslen == 1))
+ return; /*too ambiguous */
+ dots = definedCharOrDots (nested, newRule->charsdots[newRule->charslen], 1);
+ if (newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow)
+ dots->definitionRule = newRuleOffset;
+ currentOffsetPtr = &dots->otherRules;
+ while (*currentOffsetPtr)
+ {
+ currentRule = (TranslationTableRule *)
+ & table->ruleArea[*currentOffsetPtr];
+ if (newRule->charslen > currentRule->charslen ||
+ currentRule->dotslen == 0)
+ break;
+ if (currentRule->opcode >= CTO_Space && currentRule->opcode < CTO_UpLow)
+ if (!(newRule->opcode >= CTO_Space && newRule->opcode < CTO_UpLow))
+ break;
+ currentOffsetPtr = &currentRule->dotsnext;
+ }
+ newRule->dotsnext = *currentOffsetPtr;
+ *currentOffsetPtr = newRuleOffset;
+}
+
+static void
+add_1_multiple (void)
+{
+/*direction = 1, newRule->dotslen > 1*/
+ TranslationTableRule *currentRule = NULL;
+ TranslationTableOffset *currentOffsetPtr = &table->backRules[stringHash
+ (&newRule->
+ charsdots
+ [newRule->
+ charslen])];
+ if (newRule->opcode == CTO_NoBreak || newRule->opcode == CTO_SwapCc ||
+ (newRule->opcode >= CTO_Context && newRule->opcode <= CTO_Pass4))
+ return;
+ while (*currentOffsetPtr)
+ {
+ int currentLength;
+ int newLength;
+ currentRule = (TranslationTableRule *)
+ & table->ruleArea[*currentOffsetPtr];
+ currentLength = currentRule->dotslen + currentRule->charslen;
+ newLength = newRule->dotslen + newRule->charslen;
+ if (newLength > currentLength)
+ break;
+ if (currentLength == newLength)
+ if ((currentRule->opcode == CTO_Always)
+ && (newRule->opcode != CTO_Always))
+ break;
+ currentOffsetPtr = &currentRule->dotsnext;
+ }
+ newRule->dotsnext = *currentOffsetPtr;
+ *currentOffsetPtr = newRuleOffset;
+}
+
+static void
+makeRuleChain (TranslationTableOffset * offsetPtr)
+{
+ TranslationTableRule *currentRule;
+ while (*offsetPtr)
+ {
+ currentRule = (TranslationTableRule *) & table->ruleArea[*offsetPtr];
+ offsetPtr = &currentRule->charsnext;
+ }
+ newRule->charsnext = *offsetPtr;
+ *offsetPtr = newRuleOffset;
+}
+
+static int
+addPassRule (FileInfo * nested)
+{
+ TranslationTableOffset *offsetPtr;
+ switch (newRule->opcode)
+ {
+ case CTO_Correct:
+ offsetPtr = &table->attribOrSwapRules[0];
+ break;
+ case CTO_Context:
+ offsetPtr = &table->attribOrSwapRules[1];
+ break;
+ case CTO_Pass2:
+ offsetPtr = &table->attribOrSwapRules[2];
+ break;
+ case CTO_Pass3:
+ offsetPtr = &table->attribOrSwapRules[3];
+ break;
+ case CTO_Pass4:
+ offsetPtr = &table->attribOrSwapRules[4];
+ break;
+ default:
+ return 0;
+ }
+ makeRuleChain (offsetPtr);
+ return 1;
+}
+
+static int
+ addRule
+ (FileInfo * nested,
+ TranslationTableOpcode opcode,
+ CharsString * ruleChars,
+ CharsString * ruleDots,
+ TranslationTableCharacterAttributes after,
+ TranslationTableCharacterAttributes before)
+{
+/*Add a rule to the table, using the hash function to find the start of
+* chains and chaining both the chars and dots strings */
+ int ruleSize = sizeof (TranslationTableRule) - (DEFAULTRULESIZE * CHARSIZE);
+ int direction = 0; /*0 = forward translation; 1 = bacward */
+ if (ruleChars)
+ ruleSize += CHARSIZE * ruleChars->length;
+ if (ruleDots)
+ ruleSize += CHARSIZE * ruleDots->length;
+ if (!allocateSpaceInTable (nested, &newRuleOffset, ruleSize))
+ return 0;
+ newRule = (TranslationTableRule *) & table->ruleArea[newRuleOffset];
+ newRule->opcode = opcode;
+ newRule->after = after;
+ newRule->before = before;
+ if (ruleChars)
+ memcpy (&newRule->charsdots[0], &ruleChars->chars[0],
+ CHARSIZE * (newRule->charslen = ruleChars->length));
+ else
+ newRule->charslen = 0;
+ if (ruleDots)
+ memcpy (&newRule->charsdots[newRule->charslen],
+ &ruleDots->chars[0], CHARSIZE * (newRule->dotslen =
+ ruleDots->length));
+ else
+ newRule->dotslen = 0;
+ if (!charactersDefined (nested))
+ return 0;
+
+ /*link new rule into table. */
+ if (opcode == CTO_SwapCc || opcode == CTO_SwapCd || opcode == CTO_SwapDd)
+ return 1;
+ if (opcode >= CTO_Context && opcode <= CTO_Pass4 && newRule->charslen == 0)
+ return addPassRule (nested);
+ if (newRule->charslen == 0 || nofor)
+ direction = 1;
+ while (direction < 2)
+ {
+ if (direction == 0 && newRule->charslen == 1)
+ add_0_single (nested);
+ else if (direction == 0 && newRule->charslen > 1)
+ add_0_multiple ();
+ else if (direction == 1 && newRule->dotslen == 1 && !noback)
+ add_1_single (nested);
+ else if (direction == 1 && newRule->dotslen > 1 && !noback)
+ add_1_multiple ();
+ else
+ {
+ }
+ direction++;
+ if (newRule->dotslen == 0)
+ direction = 2;
+ }
+ return 1;
+}
+
+static const struct CharacterClass *
+findCharacterClass (const CharsString * name)
+{
+/*Find a character class, whether predefined or user-defined */
+ const struct CharacterClass *class = characterClasses;
+ while (class)
+ {
+ if ((name->length == class->length) &&
+ (memcmp (&name->chars[0], class->name, CHARSIZE *
+ name->length) == 0))
+ return class;
+ class = class->next;
+ }
+ return NULL;
+}
+
+static struct CharacterClass *
+addCharacterClass (FileInfo * nested, const widechar * name, int length)
+{
+/*Define a character class, Whether predefined or user-defined */
+ struct CharacterClass *class;
+ if (characterClassAttribute)
+ {
+ if ((class = malloc (sizeof (*class) + CHARSIZE * (length - 1))))
+ {
+ memset (class, 0, sizeof (*class));
+ memcpy (class->name, name, CHARSIZE * (class->length = length));
+ class->attribute = characterClassAttribute;
+ characterClassAttribute <<= 1;
+ class->next = characterClasses;
+ characterClasses = class;
+ return class;
+ }
+ }
+ compileError (nested, "character class table overflow.");
+ return NULL;
+}
+
+static void
+deallocateCharacterClasses (void)
+{
+ while (characterClasses)
+ {
+ struct CharacterClass *class = characterClasses;
+ characterClasses = characterClasses->next;
+ if (class)
+ free (class);
+ }
+}
+
+static int
+allocateCharacterClasses (void)
+{
+/*Allocate memory for predifined character classes */
+ int k = 0;
+ characterClasses = NULL;
+ characterClassAttribute = 1;
+ while (characterClassNames[k])
+ {
+ widechar wname[MAXSTRING];
+ int length = strlen (characterClassNames[k]);
+ int kk;
+ for (kk = 0; kk < length; kk++)
+ wname[kk] = (widechar) characterClassNames[k][kk];
+ if (!addCharacterClass (NULL, wname, length))
+ {
+ deallocateCharacterClasses ();
+ return 0;
+ }
+ k++;
+ }
+ return 1;
+}
+
+static TranslationTableOpcode
+getOpcode (FileInfo * nested, const CharsString * token)
+{
+ static TranslationTableOpcode lastOpcode = 0;
+ TranslationTableOpcode opcode = lastOpcode;
+
+ do
+ {
+ if (token->length == opcodeLengths[opcode])
+ if (eqasc2uni ((unsigned char *) opcodeNames[opcode],
+ &token->chars[0], token->length))
+ {
+ lastOpcode = opcode;
+ return opcode;
+ }
+ opcode++;
+ if (opcode >= CTO_None)
+ opcode = 0;
+ }
+ while (opcode != lastOpcode);
+ compileError (nested, "opcode %s not defined.", showString
+ (&token->chars[0], token->length));
+ return CTO_None;
+}
+
+TranslationTableOpcode
+findOpcodeNumber (const char *toFind)
+{
+/* Used by tools such as lou_debug */
+ static TranslationTableOpcode lastOpcode = 0;
+ TranslationTableOpcode opcode = lastOpcode;
+ int length = strlen (toFind);
+ do
+ {
+ if (length == opcodeLengths[opcode] && strcasecmp (toFind,
+ opcodeNames[opcode])
+ == 0)
+ {
+ lastOpcode = opcode;
+ return opcode;
+ }
+ opcode++;
+ if (opcode >= CTO_None)
+ opcode = 0;
+ }
+ while (opcode != lastOpcode);
+ return CTO_None;
+}
+
+const char *
+findOpcodeName (TranslationTableOpcode opcode)
+{
+/* Used by tools such as lou_debug */
+ if (opcode < 0 || opcode >= CTO_None)
+ {
+ sprintf (scratchBuf, "%d", opcode);
+ return scratchBuf;
+ }
+ return opcodeNames[opcode];
+}
+
+static widechar
+hexValue (FileInfo * nested, const widechar * digits, int length)
+{
+ int k;
+ unsigned int binaryValue = 0;
+ for (k = 0; k < length; k++)
+ {
+ unsigned int hexDigit = 0;
+ if (digits[k] >= '0' && digits[k] <= '9')
+ hexDigit = digits[k] - '0';
+ else if (digits[k] >= 'a' && digits[k] <= 'f')
+ hexDigit = digits[k] - 'a' + 10;
+ else if (digits[k] >= 'A' && digits[k] <= 'F')
+ hexDigit = digits[k] - 'A' + 10;
+ else
+ {
+ compileError (nested, "invalid %d-digit hexadecimal number",
+ length);
+ return (widechar) 0xffffffff;
+ }
+ binaryValue |= hexDigit << (4 * (length - 1 - k));
+ }
+ return (widechar) binaryValue;
+}
+
+#define MAXBYTES 7
+static int first0Bit[MAXBYTES] = { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0XFE };
+
+static int
+parseChars (FileInfo * nested, CharsString * result, CharsString * token)
+{
+ int in = 0;
+ int out = 0;
+ int lastOutSize = 0;
+ int lastIn;
+ unsigned int ch = 0;
+ int numBytes = 0;
+ unsigned int utf32 = 0;
+ int k;
+ while (in < token->length)
+ {
+ ch = token->chars[in++] & 0xff;
+ if (ch < 128)
+ {
+ if (ch == '\\')
+ { /* escape sequence */
+ switch (ch = token->chars[in])
+ {
+ case '\\':
+ break;
+ case 'e':
+ ch = 0x1b;
+ break;
+ case 'f':
+ ch = 12;
+ break;
+ case 'n':
+ ch = 10;
+ break;
+ case 'r':
+ ch = 13;
+ break;
+ case 's':
+ ch = ' ';
+ break;
+ case 't':
+ ch = 9;
+ break;
+ case 'v':
+ ch = 22;
+ break;
+ case 'w':
+ ch = ENDSEGMENT;
+ break;
+ case 34:
+ ch = QUOTESUB;
+ break;
+ case 'X':
+ case 'x':
+ if (token->length - in > 4)
+ {
+ ch = hexValue (nested, &token->chars[in + 1], 4);
+ in += 4;
+ }
+ break;
+ case 'y':
+ case 'Y':
+ if (CHARSIZE == 2)
+ {
+ not32:
+ compileError (nested,
+ "liblouis has not been compiled for 32-bit Unicode");
+ break;
+ }
+ if (token->length - in > 5)
+ {
+ ch = hexValue (nested, &token->chars[in + 1], 5);
+ in += 5;
+ }
+ break;
+ case 'z':
+ case 'Z':
+ if (CHARSIZE == 2)
+ goto not32;
+ if (token->length - in > 8)
+ {
+ ch = hexValue (nested, &token->chars[in + 1], 8);
+ in += 8;
+ }
+ break;
+ default:
+ compileError (nested, "invalid escape sequence '\\%c'", ch);
+ break;
+ }
+ in++;
+ }
+ result->chars[out++] = (widechar) ch;
+ if (out >= MAXSTRING)
+ {
+ result->length = out;
+ return 1;
+ }
+ continue;
+ }
+ lastOutSize = out;
+ lastIn = in;
+ for (numBytes = MAXBYTES - 1; numBytes >= 0; numBytes--)
+ if (ch >= first0Bit[numBytes])
+ break;
+ if (numBytes < 0)
+ continue;
+ utf32 = ch & (0XFF - first0Bit[numBytes]);
+ for (k = 0; k < numBytes; k++)
+ {
+ if (in >= MAXSTRING)
+ break;
+ if (token->chars[in] < 128 || (token->chars[in] & 0x0040))
+ {
+ compileWarning (nested, "invalid UTF-8. Assuming Latin-1.");
+ result->chars[out++] = token->chars[lastIn];
+ in = lastIn + 1;
+ continue;
+ }
+ utf32 = (utf32 << 6) + (token->chars[in++] & 0x3f);
+ }
+ if (CHARSIZE == 2 && utf32 > 0xffff)
+ utf32 = 0xffff;
+ result->chars[out++] = (widechar) utf32;
+ if (out >= MAXSTRING)
+ {
+ result->length = lastOutSize;
+ return 1;
+ }
+ }
+ result->length = out;
+ return 1;
+}
+
+int
+extParseChars (const char *inString, widechar * outString)
+{
+/* Parse external character strings */
+ CharsString wideIn;
+ CharsString result;
+ int k;
+ for (k = 0; inString[k] && k < MAXSTRING; k++)
+ wideIn.chars[k] = inString[k];
+ wideIn.chars[k] = 0;
+ wideIn.length = k;
+ parseChars (NULL, &result, &wideIn);
+ if (errorCount)
+ {
+ errorCount = 0;
+ return 0;
+ }
+ for (k = 0; k < result.length; k++)
+ outString[k] = result.chars[k];
+ outString[k] = 0;
+ return result.length;
+}
+
+static int
+parseDots (FileInfo * nested, CharsString * cells, const CharsString * token)
+{
+/*get dot patterns */
+ widechar cell = 0; /*assembly place for dots */
+ int cellCount = 0;
+ int index;
+ int start = 0;
+
+ for (index = 0; index < token->length; index++)
+ {
+ int started = index != start;
+ widechar character = token->chars[index];
+ switch (character)
+ { /*or dots to make up Braille cell */
+ {
+ int dot;
+ case '1':
+ dot = B1;
+ goto haveDot;
+ case '2':
+ dot = B2;
+ goto haveDot;
+ case '3':
+ dot = B3;
+ goto haveDot;
+ case '4':
+ dot = B4;
+ goto haveDot;
+ case '5':
+ dot = B5;
+ goto haveDot;
+ case '6':
+ dot = B6;
+ goto haveDot;
+ case '7':
+ dot = B7;
+ goto haveDot;
+ case '8':
+ dot = B8;
+ goto haveDot;
+ case '9':
+ dot = B9;
+ goto haveDot;
+ case 'a':
+ case 'A':
+ dot = B10;
+ goto haveDot;
+ case 'b':
+ case 'B':
+ dot = B11;
+ goto haveDot;
+ case 'c':
+ case 'C':
+ dot = B12;
+ goto haveDot;
+ case 'd':
+ case 'D':
+ dot = B13;
+ goto haveDot;
+ case 'e':
+ case 'E':
+ dot = B14;
+ goto haveDot;
+ case 'f':
+ case 'F':
+ dot = B15;
+ haveDot:
+ if (started && !cell)
+ goto invalid;
+ if (cell & dot)
+ {
+ compileError (nested, "dot specified more than once.");
+ return 0;
+ }
+ cell |= dot;
+ break;
+ }
+ case '0': /*blank */
+ if (started)
+ goto invalid;
+ break;
+ case '-': /*got all dots for this cell */
+ if (!started)
+ {
+ compileError (nested, "missing cell specification.");
+ return 0;
+ }
+ cells->chars[cellCount++] = cell | B16;
+ cell = 0;
+ start = index + 1;
+ break;
+ default:
+ invalid:
+ compileError (nested, "invalid dot number %s.", showString
+ (&character, 1));
+ return 0;
+ }
+ }
+ if (index == start)
+ {
+ compileError (nested, "missing cell specification.");
+ return 0;
+ }
+ cells->chars[cellCount++] = cell | B16; /*last cell */
+ cells->length = cellCount;
+ return 1;
+}
+
+int
+extParseDots (const char *inString, widechar * outString)
+{
+/* Parse external dot patterns */
+ CharsString wideIn;
+ CharsString result;
+ int k;
+ for (k = 0; inString[k] && k < MAXSTRING; k++)
+ wideIn.chars[k] = inString[k];
+ wideIn.chars[k] = 0;
+ wideIn.length = k;
+ parseDots (NULL, &result, &wideIn);
+ if (errorCount)
+ {
+ errorCount = 0;
+ return 0;
+ }
+ for (k = 0; k < result.length; k++)
+ outString[k] = result.chars[k];
+ outString[k] = 0;
+ return result.length;
+}
+
+static int
+getCharacters (FileInfo * nested, CharsString * characters)
+{
+/*Get ruleChars string */
+ CharsString token;
+ if (getToken (nested, &token, "characters"))
+ if (parseChars (nested, characters, &token))
+ return 1;
+ return 0;
+}
+
+static int
+getRuleCharsText (FileInfo * nested, CharsString * ruleChars)
+{
+ CharsString token;
+ if (getToken (nested, &token, "Characters operand"))
+ if (parseChars (nested, ruleChars, &token))
+ return 1;
+ return 0;
+}
+
+static int
+getRuleDotsText (FileInfo * nested, CharsString * ruleDots)
+{
+ CharsString token;
+ if (getToken (nested, &token, "characters"))
+ if (parseChars (nested, ruleDots, &token))
+ return 1;
+ return 0;
+}
+
+static int
+getRuleDotsPattern (FileInfo * nested, CharsString * ruleDots)
+{
+/*Interpret the dets operand */
+ CharsString token;
+ if (getToken (nested, &token, "Dots operand"))
+ {
+ if (token.length == 1 && token.chars[0] == '=')
+ {
+ ruleDots->length = 0;
+ return 1;
+ }
+ if (parseDots (nested, ruleDots, &token))
+ return 1;
+ }
+ return 0;
+}
+
+static int
+getCharacterClass (FileInfo * nested, const struct CharacterClass **class)
+{
+ CharsString token;
+ if (getToken (nested, &token, "character class name"))
+ {
+ if ((*class = findCharacterClass (&token)))
+ return 1;
+ compileError (nested, "character class not defined.");
+ }
+ return 0;
+}
+
+static int compileFile (const char *fileName);
+
+static int
+includeFile (FileInfo * nested, CharsString * includedFile)
+{
+/*Implement include opcode*/
+ int k;
+ char includeThis[MAXSTRING];
+ for (k = 0; k < includedFile->length; k++)
+ includeThis[k] = (char) includedFile->chars[k];
+ includeThis[k] = 0;
+ return compileFile (includeThis);
+}
+
+struct RuleName
+{
+ struct RuleName *next;
+ TranslationTableOffset ruleOffset;
+ widechar length;
+ widechar name[1];
+};
+static struct RuleName *ruleNames = NULL;
+static TranslationTableOffset
+findRuleName (const CharsString * name)
+{
+ const struct RuleName *nameRule = ruleNames;
+ while (nameRule)
+ {
+ if ((name->length == nameRule->length) &&
+ (memcmp (&name->chars[0], nameRule->name, CHARSIZE *
+ name->length) == 0))
+ return nameRule->ruleOffset;
+ nameRule = nameRule->next;
+ }
+ return 0;
+}
+
+static int
+addRuleName (FileInfo * nested, CharsString * name)
+{
+ int k;
+ struct RuleName *nameRule;
+ if (!(nameRule = malloc (sizeof (*nameRule) + CHARSIZE *
+ (name->length - 1))))
+ {
+ compileError (nested, "not enough memory");
+ return 0;
+ }
+ memset (nameRule, 0, sizeof (*nameRule));
+ for (k = 0; k < name->length; k++)
+ {
+ TranslationTableCharacter *ch = definedCharOrDots
+ (nested, name->chars[k],
+ 0);
+ if (!(ch->attributes & CTC_Letter))
+ {
+ compileError (nested, "a name may contain only letters");
+ return 0;
+ }
+ nameRule->name[k] = name->chars[k];
+ }
+ nameRule->length = name->length;
+ nameRule->ruleOffset = newRuleOffset;
+ nameRule->next = ruleNames;
+ ruleNames = nameRule;
+ return 1;
+}
+
+static void
+deallocateRuleNames (void)
+{
+ while (ruleNames)
+ {
+ struct RuleName *nameRule = ruleNames;
+ ruleNames = ruleNames->next;
+ if (nameRule)
+ free (nameRule);
+ }
+}
+
+static int
+compileSwapDots (FileInfo * nested, CharsString * source, CharsString * dest)
+{
+ int k = 0;
+ int kk = 0;
+ CharsString dotsSource;
+ CharsString dotsDest;
+ dest->length = 0;
+ dotsSource.length = 0;
+ while (k <= source->length)
+ {
+ if (source->chars[k] != ',' && k != source->length)
+ dotsSource.chars[dotsSource.length++] = source->chars[k];
+ else
+ {
+ if (!parseDots (nested, &dotsDest, &dotsSource))
+ return 0;
+ dest->chars[dest->length++] = dotsDest.length + 1;
+ for (kk = 0; kk < dotsDest.length; kk++)
+ dest->chars[dest->length++] = dotsDest.chars[kk];
+ dotsSource.length = 0;
+ }
+ k++;
+ }
+ return 1;
+}
+
+static int
+compileSwap (FileInfo * nested, TranslationTableOpcode opcode)
+{
+ CharsString ruleChars;
+ CharsString ruleDots;
+ CharsString name;
+ CharsString matches;
+ CharsString replacements;
+ if (!getToken (nested, &name, "name operand"))
+ return 0;
+ if (!getToken (nested, &matches, "matches operand"))
+ return 0;
+ if (!getToken (nested, &replacements, "replacements operand"))
+ return 0;
+ if (opcode == CTO_SwapCc || opcode == CTO_SwapCd)
+ {
+ if (!parseChars (nested, &ruleChars, &matches))
+ return 0;
+ }
+ else
+ {
+ if (!compileSwapDots (nested, &matches, &ruleChars))
+ return 0;
+ }
+ if (opcode == CTO_SwapCc)
+ {
+ if (!parseChars (nested, &ruleDots, &replacements))
+ return 0;
+ }
+ else
+ {
+ if (!compileSwapDots (nested, &replacements, &ruleDots))
+ return 0;
+ }
+ if (!addRule (nested, opcode, &ruleChars, &ruleDots, 0, 0))
+ return 0;
+ if (!addRuleName (nested, &name))
+ return 0;
+ return 1;
+}
+
+
+static int
+getNumber (widechar * source, widechar * dest)
+{
+/*Convert a string of wide character digits to an integer*/
+ int k = 0;
+ *dest = 0;
+ while (source[k] >= '0' && source[k] <= '9')
+ *dest = 10 * *dest + (source[k++] - '0');
+ return k;
+}
+
+/* Start of multipass compiler*/
+static CharsString passRuleChars;
+static CharsString passRuleDots;
+static CharsString passHoldString;
+static CharsString passLine;
+static int passLinepos;
+static int passPrevLinepos;
+static widechar passHoldNumber;
+static widechar passEmphasis;
+static TranslationTableCharacterAttributes passAttributes;
+static FileInfo *passNested;
+static TranslationTableOpcode passOpcode;
+static widechar *passInstructions;
+static int passIC;
+
+static int
+passGetAttributes ()
+{
+ int more = 1;
+ passAttributes = 0;
+ while (more)
+ {
+ switch (passLine.chars[passLinepos])
+ {
+ case pass_any:
+ passAttributes = 0xffffffff;
+ break;
+ case pass_digit:
+ passAttributes |= CTC_Digit;
+ break;
+ case pass_litDigit:
+ passAttributes |= CTC_LitDigit;
+ break;
+ case pass_letter:
+ passAttributes |= CTC_Letter;
+ break;
+ case pass_math:
+ passAttributes |= CTC_Math;
+ break;
+ case pass_punctuation:
+ passAttributes |= CTC_Punctuation;
+ break;
+ case pass_sign:
+ passAttributes |= CTC_Sign;
+ break;
+ case pass_space:
+ passAttributes |= CTC_Space;
+ break;
+ case pass_uppercase:
+ passAttributes |= CTC_UpperCase;
+ break;
+ case pass_lowercase:
+ passAttributes |= CTC_LowerCase;
+ break;
+ case pass_class1:
+ passAttributes |= CTC_Class1;
+ break;
+ case pass_class2:
+ passAttributes |= CTC_Class2;
+ break;
+ case pass_class3:
+ passAttributes |= CTC_Class3;
+ break;
+ case pass_class4:
+ passAttributes |= CTC_Class4;
+ break;
+ default:
+ more = 0;
+ break;
+ }
+ if (more)
+ passLinepos++;
+ }
+ if (!passAttributes)
+ {
+ compileError (passNested, "Missing attribute");
+ passLinepos--;
+ return 0;
+ }
+ return 1;
+}
+
+static int
+passGetEmphasis ()
+{
+ int more = 1;
+ passLinepos++;
+ passEmphasis = 0;
+ while (more)
+ {
+ switch (passLine.chars[passLinepos])
+ {
+ case 'i':
+ passEmphasis |= italic;
+ break;
+ case 'b':
+ passEmphasis |= bold;
+ break;
+ case 'u':
+ passEmphasis |= underline;
+ break;
+ case 'c':
+ passEmphasis |= computer_braille;
+ break;
+ default:
+ more = 0;
+ break;
+ }
+ if (more)
+ passLinepos++;
+ }
+ if (!passEmphasis)
+ {
+ compileError (passNested, "emphasis indicators expected");
+ passLinepos--;
+ return 0;
+ }
+ return 1;
+}
+
+static int
+passGetDots ()
+{
+ CharsString collectDots;
+ collectDots.length = 0;
+ while (passLinepos < passLine.length && (passLine.chars[passLinepos]
+ == '-'
+ || (passLine.chars[passLinepos] >=
+ '0'
+ && passLine.
+ chars[passLinepos] <= '9')
+ ||
+ ((passLine.
+ chars[passLinepos] | 32) >= 'a'
+ && (passLine.
+ chars[passLinepos] | 32) <=
+ 'f')))
+ collectDots.chars[collectDots.length++] = passLine.chars[passLinepos++];
+ if (!parseDots (passNested, &passHoldString, &collectDots))
+ return 0;
+ return 1;
+}
+
+static int
+passGetString ()
+{
+ passHoldString.length = 0;
+ while (1)
+ {
+ if (!passLine.chars[passLinepos])
+ {
+ compileError (passNested, "unterminated string");
+ return 0;
+ }
+ if (passLine.chars[passLinepos] == 34)
+ break;
+ if (passLine.chars[passLinepos] == QUOTESUB)
+ passHoldString.chars[passHoldString.length++] = 34;
+ else
+ passHoldString.chars[passHoldString.length++] =
+ passLine.chars[passLinepos];
+ passLinepos++;
+ }
+ passHoldString.chars[passHoldString.length] = 0;
+ passLinepos++;
+ return 1;
+}
+
+static int
+passGetNumber ()
+{
+ /*Convert a string of wide character digits to an integer */
+ passHoldNumber = 0;
+ while (passLine.chars[passLinepos] >= '0'
+ && passLine.chars[passLinepos] <= '9')
+ passHoldNumber =
+ 10 * passHoldNumber + (passLine.chars[passLinepos++] - '0');
+ return 1;
+}
+
+static int
+passGetName ()
+{
+ TranslationTableCharacterAttributes attr;
+ passHoldString.length = 0;
+ do
+ {
+ attr = definedCharOrDots (passNested, passLine.chars[passLinepos],
+ 0)->attributes;
+ if (passHoldString.length == 0)
+ {
+ if (!(attr & CTC_Letter))
+ {
+ passLinepos++;
+ continue;
+ }
+ }
+ if (!(attr & CTC_Letter))
+ break;
+ passHoldString.chars[passHoldString.length++] =
+ passLine.chars[passLinepos];
+ passLinepos++;
+ }
+ while (passLinepos < passLine.length);
+ return 1;
+}
+
+static int
+passIsKeyword (const char *token)
+{
+ int k;
+ int length = strlen (token);
+ int ch = passLine.chars[passLinepos + length + 1];
+ if (((ch | 32) >= 'a' && (ch | 32) <= 'z') || (ch >= '0' && ch <= '9'))
+ return 0;
+ for (k = 0; k < length && passLine.chars[passLinepos + k + 1]
+ == (widechar) token[k]; k++);
+ if (k == length)
+ {
+ passLinepos += length + 1;
+ return 1;
+ }
+ return 0;
+}
+
+struct PassName
+{
+ struct PassName *next;
+ int varnum;
+ widechar length;
+ widechar name[1];
+};
+static struct PassName *passNames = NULL;
+
+static int
+passFindName (const CharsString * name)
+{
+ const struct PassName *curname = passNames;
+ CharsString augmentedName;
+ for (augmentedName.length = 0; augmentedName.length < name->length;
+ augmentedName.length++)
+ augmentedName.chars[augmentedName.length] =
+ name->chars[augmentedName.length];
+ augmentedName.chars[augmentedName.length++] = passOpcode;
+ while (curname)
+ {
+ if ((augmentedName.length == curname->length) &&
+ (memcmp
+ (&augmentedName.chars[0], curname->name,
+ CHARSIZE * name->length) == 0))
+ return curname->varnum;
+ curname = curname->next;
+ }
+ compileError (passNested, "name not found");
+ return 0;
+}
+
+static int
+passAddName (CharsString * name, int var)
+{
+ int k;
+ struct PassName *curname;
+ CharsString augmentedName;
+ for (augmentedName.length = 0;
+ augmentedName.length < name->length; augmentedName.length++)
+ augmentedName.
+ chars[augmentedName.length] = name->chars[augmentedName.length];
+ augmentedName.chars[augmentedName.length++] = passOpcode;
+ if (!
+ (curname =
+ malloc (sizeof (*curname) + CHARSIZE * (augmentedName.length - 1))))
+ {
+ compileError (passNested, "not enough memory");
+ return 0;
+ }
+ memset (curname, 0, sizeof (*curname));
+ for (k = 0; k < augmentedName.length; k++)
+ {
+ curname->name[k] = augmentedName.chars[k];
+ }
+ curname->length = augmentedName.length;
+ curname->varnum = var;
+ curname->next = passNames;
+ passNames = curname;
+ return 1;
+}
+
+static pass_Codes
+passGetScriptToken ()
+{
+ while (passLinepos < passLine.length)
+ {
+ passPrevLinepos = passLinepos;
+ switch (passLine.chars[passLinepos])
+ {
+ case '\"':
+ passLinepos++;
+ if (passGetString ())
+ return pass_string;
+ return pass_invalidToken;
+ case '@':
+ passLinepos++;
+ if (passGetDots ())
+ return pass_dots;
+ return pass_invalidToken;
+ case '#': /*comment */
+ passLinepos = passLine.length + 1;
+ return pass_noMoreTokens;
+ case '!':
+ if (passLine.chars[passLinepos + 1] == '=')
+ {
+ passLinepos += 2;
+ return pass_noteq;
+ }
+ passLinepos++;
+ return pass_not;
+ case '-':
+ passLinepos++;
+ return pass_hyphen;
+ case '=':
+ passLinepos++;
+ return pass_eq;
+ case '<':
+ passLinepos++;
+ if (passLine.chars[passLinepos] == '=')
+ {
+ passLinepos++;
+ return pass_lteq;
+ }
+ return pass_lt;
+ case '>':
+ passLinepos++;
+ if (passLine.chars[passLinepos] == '=')
+ {
+ passLinepos++;
+ return pass_gteq;
+ }
+ return pass_gt;
+ case '+':
+ passLinepos++;
+ return pass_plus;
+ case '(':
+ passLinepos++;
+ return pass_leftParen;
+ case ')':
+ passLinepos++;
+ return pass_rightParen;
+ case ',':
+ passLinepos++;
+ return pass_comma;
+ case '&':
+ if (passLine.chars[passLinepos = 1] == '&')
+ {
+ passLinepos += 2;
+ return pass_and;
+ }
+ return pass_invalidToken;
+ case '|':
+ if (passLine.chars[passLinepos + 1] == '|')
+ {
+ passLinepos += 2;
+ return pass_or;
+ }
+ return pass_invalidToken;
+ case 'a':
+ if (passIsKeyword ("ttr"))
+ return pass_attributes;
+ passGetName ();
+ return pass_nameFound;
+ case 'b':
+ if (passIsKeyword ("ack"))
+ return pass_lookback;
+ if (passIsKeyword ("ool"))
+ return pass_boolean;
+ passGetName ();
+ return pass_nameFound;
+ case 'c':
+ if (passIsKeyword ("lass"))
+ return pass_class;
+ passGetName ();
+ return pass_nameFound;
+ case 'd':
+ if (passIsKeyword ("ef"))
+ return pass_define;
+ passGetName ();
+ return pass_nameFound;
+ case 'e':
+ if (passIsKeyword ("mph"))
+ return pass_emphasis;
+ passGetName ();
+ return pass_nameFound;
+ case 'f':
+ if (passIsKeyword ("ind"))
+ return pass_search;
+ if (passIsKeyword ("irst"))
+ return pass_first;
+ passGetName ();
+ return pass_nameFound;
+ case 'g':
+ if (passIsKeyword ("roup"))
+ return pass_group;
+ passGetName ();
+ return pass_nameFound;
+ case 'i':
+ if (passIsKeyword ("f"))
+ return pass_if;
+ passGetName ();
+ return pass_nameFound;
+ case 'l':
+ if (passIsKeyword ("ast"))
+ return pass_last;
+ passGetName ();
+ return pass_nameFound;
+ case 'm':
+ if (passIsKeyword ("ark"))
+ return pass_mark;
+ passGetName ();
+ return pass_nameFound;
+ case 'r':
+ if (passIsKeyword ("epgroup"))
+ return pass_repGroup;
+ if (passIsKeyword ("epcopy"))
+ return pass_copy;
+ if (passIsKeyword ("epomit"))
+ return pass_omit;
+ if (passIsKeyword ("ep"))
+ return pass_replace;
+ passGetName ();
+ return pass_nameFound;
+ case 's':
+ if (passIsKeyword ("cript"))
+ return pass_script;
+ if (passIsKeyword ("wap"))
+ return pass_swap;
+ passGetName ();
+ return pass_nameFound;
+ case 't':
+ if (passIsKeyword ("hen"))
+ return pass_then;
+ passGetName ();
+ return pass_nameFound;
+ default:
+ if (passLine.chars[passLinepos] <= 32)
+ {
+ passLinepos++;
+ break;
+ }
+ if (passLine.chars[passLinepos] >= '0'
+ && passLine.chars[passLinepos] <= '9')
+ {
+ passGetNumber ();
+ return pass_numberFound;
+ }
+ else
+ {
+ if (!passGetName ())
+ return pass_invalidToken;
+ else
+ return pass_nameFound;
+ }
+ }
+ }
+ return pass_noMoreTokens;
+}
+
+static int
+passIsLeftParen ()
+{
+ pass_Codes passCode = passGetScriptToken ();
+ if (passCode != pass_leftParen)
+ {
+ compileError (passNested, "'(' expected");
+ return 0;
+ }
+ return 1;
+}
+
+static int
+passIsName ()
+{
+ pass_Codes passCode = passGetScriptToken ();
+ if (passCode != pass_nameFound)
+ {
+ compileError (passNested, "a name expected");
+ return 0;
+ }
+ return 1;
+}
+
+static int
+passIsComma ()
+{
+ pass_Codes passCode = passGetScriptToken ();
+ if (passCode != pass_comma)
+ {
+ compileError (passNested, "',' expected");
+ return 0;
+ }
+ return 1;
+}
+
+static int
+passIsNumber ()
+{
+ pass_Codes passCode = passGetScriptToken ();
+ if (passCode != pass_numberFound)
+ {
+ compileError (passNested, "a number expected");
+ return 0;
+ }
+ return 1;
+}
+
+static int
+passIsRightParen ()
+{
+ pass_Codes passCode = passGetScriptToken ();
+ if (passCode != pass_rightParen)
+ {
+ compileError (passNested, "')' expected");
+ return 0;
+ }
+ return 1;
+}
+
+static int
+passGetRange ()
+{
+ pass_Codes passCode = passGetScriptToken ();
+ if (!(passCode == pass_comma || passCode == pass_rightParen))
+ {
+ compileError (passNested, "invalid range");
+ return 0;
+ }
+ if (passCode == pass_rightParen)
+ {
+ passInstructions[passIC++] = 1;
+ passInstructions[passIC++] = 1;
+ return 1;
+ }
+ if (!passIsNumber ())
+ return 0;
+ passInstructions[passIC++] = passHoldNumber;
+ passCode = passGetScriptToken ();
+ if (!(passCode == pass_comma || passCode == pass_rightParen))
+ {
+ compileError (passNested, "invalid range");
+ return 0;
+ }
+ if (passCode == pass_rightParen)
+ {
+ passInstructions[passIC++] = passHoldNumber;
+ return 1;
+ }
+ if (!passIsNumber ())
+ return 0;
+ passInstructions[passIC++] = passHoldNumber;
+ if (!passIsRightParen ())
+ return 0;
+ return 1;
+}
+
+static int
+passInsertAttributes ()
+{
+ passInstructions[passIC++] = pass_attributes;
+ passInstructions[passIC++] = passAttributes >> 16;
+ passInstructions[passIC++] = passAttributes & 0xffff;
+ if (!passGetRange ())
+ return 0;
+ return 1;
+}
+
+static int
+compilePassOpcode (FileInfo * nested, TranslationTableOpcode opcode)
+{
+/*Compile the operands of a pass opcode */
+ TranslationTableCharacterAttributes after = 0;
+ TranslationTableCharacterAttributes before = 0;
+ widechar passSubOp;
+ const struct CharacterClass *class;
+ TranslationTableOffset ruleOffset = 0;
+ TranslationTableRule *rule = NULL;
+ int k;
+ int kk = 0;
+ pass_Codes passCode;
+ int endTest = 0;
+ int isScript = 1;
+ passInstructions = passRuleDots.chars;
+ passIC = 0; /*Instruction counter */
+ passRuleChars.length = 0;
+ passNested = nested;
+ passOpcode = opcode;
+/* passHoldString and passLine are static variables declared
+ * previously.*/
+ passLinepos = 0;
+ passHoldString.length = 0;
+ for (k = nested->linepos; k < nested->linelen; k++)
+ passHoldString.chars[passHoldString.length++] = nested->line[k];
+ if (!eqasc2uni ((unsigned char *) "script", passHoldString.chars, 6))
+ {
+ isScript = 0;
+#define SEPCHAR 0x0001
+ for (k = 0; k < passHoldString.length && passHoldString.chars[k] > 32;
+ k++);
+ if (k < passHoldString.length)
+ passHoldString.chars[k] = SEPCHAR;
+ else
+ {
+ compileError (passNested, "Invalid multipass operands");
+ return 0;
+ }
+ }
+ parseChars (passNested, &passLine, &passHoldString);
+ if (isScript)
+ {
+ int more = 1;
+ passCode = passGetScriptToken ();
+ if (passCode != pass_script)
+ {
+ compileError (passNested, "Invalid multipass statement");
+ return 0;
+ }
+ /* Declaratives */
+ while (more)
+ {
+ passCode = passGetScriptToken ();
+ switch (passCode)
+ {
+ case pass_define:
+ if (!passIsLeftParen ())
+ return 0;
+ if (!passIsName ())
+ return 0;
+ if (!passIsComma ())
+ return 0;
+ if (!passIsNumber ())
+ return 0;
+ if (!passIsRightParen ())
+ return 0;
+ passAddName (&passHoldString, passHoldNumber);
+ break;
+ case pass_if:
+ more = 0;
+ break;
+ default:
+ compileError (passNested,
+ "invalid definition in declarative part");
+ return 0;
+ }
+ }
+ /* if part */
+ more = 1;
+ while (more)
+ {
+ passCode = passGetScriptToken ();
+ passSubOp = passCode;
+ switch (passCode)
+ {
+ case pass_not:
+ passInstructions[passIC++] = pass_not;
+ break;
+ case pass_first:
+ passInstructions[passIC++] = pass_first;
+ break;
+ case pass_last:
+ passInstructions[passIC++] = pass_last;
+ break;
+ case pass_search:
+ passInstructions[passIC++] = pass_search;
+ break;
+ case pass_string:
+ if (opcode != CTO_Context && opcode != CTO_Correct)
+ {
+ compileError (passNested,
+ "Character strings can only be used with the context and correct opcodes.");
+ return 0;
+ }
+ passInstructions[passIC++] = pass_string;
+ goto ifDoCharsDots;
+ case pass_dots:
+ if (passOpcode == CTO_Correct || passOpcode == CTO_Context)
+ {
+ compileError (passNested,
+ "dot patterns cannot be specified in the if part\
+ of the correct or context opcodes");
+ return 0;
+ }
+ passInstructions[passIC++] = pass_dots;
+ ifDoCharsDots:
+ passInstructions[passIC++] = passHoldString.length;
+ for (kk = 0; kk < passHoldString.length; kk++)
+ passInstructions[passIC++] = passHoldString.chars[kk];
+ break;
+ case pass_attributes:
+ if (!passIsLeftParen ())
+ return 0;
+ if (!passGetAttributes ())
+ return 0;
+ if (!passInsertAttributes ())
+ return 0;
+ break;
+ case pass_emphasis:
+ if (!passIsLeftParen ())
+ return 0;
+ if (!passGetEmphasis ())
+ return 0;
+ /*Right parenthis handled by subfunctiion */
+ break;
+ case pass_lookback:
+ passInstructions[passIC++] = pass_lookback;
+ passCode = passGetScriptToken ();
+ if (passCode != pass_leftParen)
+ {
+ passInstructions[passIC++] = 1;
+ passLinepos = passPrevLinepos;
+ break;
+ }
+ if (!passIsNumber ())
+ return 0;
+ if (!passIsRightParen ())
+ return 0;
+ passInstructions[passIC] = passHoldNumber;
+ break;
+ case pass_group:
+ if (!passIsLeftParen ())
+ return 0;
+ break;
+ case pass_mark:
+ passInstructions[passIC++] = pass_startReplace;
+ passInstructions[passIC++] = pass_endReplace;
+ break;
+ case pass_replace:
+ passInstructions[passIC++] = pass_startReplace;
+ if (!passIsLeftParen ())
+ return 0;
+ break;
+ case pass_rightParen:
+ passInstructions[passIC++] = pass_endReplace;
+ break;
+ case pass_groupstart:
+ case pass_groupend:
+ if (!passIsLeftParen ())
+ return 0;
+ if (!passGetName ())
+ return 0;
+ if (!passIsRightParen ())
+ return 0;
+ ruleOffset = findRuleName (&passHoldString);
+ if (ruleOffset)
+ rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
+ if (rule && rule->opcode == CTO_Grouping)
+ {
+ passInstructions[passIC++] = passSubOp;
+ passInstructions[passIC++] = ruleOffset >> 16;
+ passInstructions[passIC++] = ruleOffset & 0xffff;
+ break;
+ }
+ else
+ {
+ compileError (passNested, "%s is not a grouping name",
+ showString (&passHoldString.chars[0],
+ passHoldString.length));
+ return 0;
+ }
+ break;
+ case pass_class:
+ if (!passIsLeftParen ())
+ return 0;
+ if (!passGetName ())
+ return 0;
+ if (!passIsRightParen ())
+ return 0;
+ if (!(class = findCharacterClass (&passHoldString)))
+ return 0;
+ passAttributes = class->attribute;
+ passInsertAttributes ();
+ break;
+ case pass_swap:
+ ruleOffset = findRuleName (&passHoldString);
+ if (!passIsLeftParen ())
+ return 0;
+ if (!passGetName ())
+ return 0;
+ if (!passIsRightParen ())
+ return 0;
+ ruleOffset = findRuleName (&passHoldString);
+ if (ruleOffset)
+ rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
+ if (rule
+ && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd
+ || rule->opcode == CTO_SwapDd))
+ {
+ passInstructions[passIC++] = pass_swap;
+ passInstructions[passIC++] = ruleOffset >> 16;
+ passInstructions[passIC++] = ruleOffset & 0xffff;
+ if (!passGetRange ())
+ return 0;
+ break;
+ }
+ compileError (passNested,
+ "%s is not a swap name.",
+ showString (&passHoldString.chars[0],
+ passHoldString.length));
+ return 0;
+ case pass_nameFound:
+ passHoldNumber = passFindName (&passHoldString);
+ passCode = passGetScriptToken ();
+ if (!(passCode == pass_eq || passCode == pass_lt || passCode
+ == pass_gt || passCode == pass_noteq || passCode ==
+ pass_lteq || passCode == pass_gteq))
+ {
+ compileError (nested,
+ "invalid comparison operator in if part");
+ return 0;
+ }
+ passInstructions[passIC++] = passCode;
+ passInstructions[passIC++] = passHoldNumber;
+ if (!passIsNumber ())
+ return 0;
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ case pass_then:
+ passInstructions[passIC++] = pass_endTest;
+ more = 0;
+ break;
+ default:
+ compileError (passNested, "invalid choice in if part");
+ return 0;
+ }
+ }
+
+ /* then part */
+ more = 1;
+ while (more)
+ {
+ passCode = passGetScriptToken ();
+ passSubOp = passCode;
+ switch (passCode)
+ {
+ case pass_string:
+ if (opcode != CTO_Correct)
+ {
+ compileError (passNested,
+ "Character strings can only be used in the then part with the correct opcode.");
+ return 0;
+ }
+ passInstructions[passIC++] = pass_string;
+ goto thenDoCharsDots;
+ case pass_dots:
+ if (opcode == CTO_Correct)
+ {
+ compileError (passNested,
+ "Dot patterns cannot be used with the correct opcode.");
+ return 0;
+ }
+ passInstructions[passIC++] = pass_dots;
+ thenDoCharsDots:
+ passInstructions[passIC++] = passHoldString.length;
+ for (kk = 0; kk < passHoldString.length; kk++)
+ passInstructions[passIC++] = passHoldString.chars[kk];
+ break;
+ case pass_nameFound:
+ passHoldNumber = passFindName (&passHoldString);
+ passCode = passGetScriptToken ();
+ if (!(passCode == pass_plus || passCode == pass_hyphen
+ || passCode == pass_eq))
+ {
+ compileError (nested,
+ "Invalid variable operator in then part");
+ return 0;
+ }
+ passInstructions[passIC++] = passCode;
+ passInstructions[passIC++] = passHoldNumber;
+ if (!passIsNumber ())
+ return 0;
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ case pass_copy:
+ passInstructions[passIC++] = pass_copy;
+ break;
+ case pass_omit:
+ passInstructions[passIC++] = pass_omit;
+ break;
+ case pass_swap:
+ ruleOffset = findRuleName (&passHoldString);
+ if (!passIsLeftParen ())
+ return 0;
+ if (!passGetName ())
+ return 0;
+ if (!passIsRightParen ())
+ return 0;
+ ruleOffset = findRuleName (&passHoldString);
+ if (ruleOffset)
+ rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
+ if (rule
+ && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd
+ || rule->opcode == CTO_SwapDd))
+ {
+ passInstructions[passIC++] = pass_swap;
+ passInstructions[passIC++] = ruleOffset >> 16;
+ passInstructions[passIC++] = ruleOffset & 0xffff;
+ if (!passGetRange ())
+ return 0;
+ break;
+ }
+ compileError (passNested,
+ "%s is not a swap name.",
+ showString (&passHoldString.chars[0],
+ passHoldString.length));
+ return 0;
+ case pass_noMoreTokens:
+ more = 0;
+ break;
+ default:
+ compileError (passNested, "invalid action in then part");
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ /* Older machine-language-like "assembler". */
+
+ /*Compile test part */
+ for (k = 0; k < passLine.length && passLine.chars[k] != SEPCHAR; k++);
+ endTest = k;
+ passLine.chars[endTest] = pass_endTest;
+ passLinepos = 0;
+ while (passLinepos <= endTest)
+ {
+ switch ((passSubOp = passLine.chars[passLinepos]))
+ {
+ case pass_lookback:
+ passInstructions[passIC++] = pass_lookback;
+ passLinepos++;
+ passGetNumber ();
+ if (passHoldNumber == 0)
+ passHoldNumber = 1;
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ case pass_not:
+ passInstructions[passIC++] = pass_not;
+ passLinepos++;
+ break;
+ case pass_first:
+ passInstructions[passIC++] = pass_first;
+ passLinepos++;
+ break;
+ case pass_last:
+ passInstructions[passIC++] = pass_last;
+ passLinepos++;
+ break;
+ case pass_search:
+ passInstructions[passIC++] = pass_search;
+ passLinepos++;
+ break;
+ case pass_string:
+ if (opcode != CTO_Context && opcode != CTO_Correct)
+ {
+ compileError (passNested,
+ "Character strings can only be used with the context and correct opcodes.");
+ return 0;
+ }
+ passLinepos++;
+ passInstructions[passIC++] = pass_string;
+ passGetString ();
+ goto testDoCharsDots;
+ case pass_dots:
+ passLinepos++;
+ passInstructions[passIC++] = pass_dots;
+ passGetDots ();
+ testDoCharsDots:
+ if (passHoldString.length == 0)
+ return 0;
+ passInstructions[passIC++] = passHoldString.length;
+ for (kk = 0; kk < passHoldString.length; kk++)
+ passInstructions[passIC++] = passHoldString.chars[kk];
+ break;
+ case pass_startReplace:
+ passInstructions[passIC++] = pass_startReplace;
+ passLinepos++;
+ break;
+ case pass_endReplace:
+ passInstructions[passIC++] = pass_endReplace;
+ passLinepos++;
+ break;
+ case pass_variable:
+ passLinepos++;
+ passGetNumber ();
+ switch (passLine.chars[passLinepos])
+ {
+ case pass_eq:
+ passInstructions[passIC++] = pass_eq;
+ goto doComp;
+ case pass_lt:
+ if (passLine.chars[passLinepos + 1] == pass_eq)
+ {
+ passLinepos++;
+ passInstructions[passIC++] = pass_lteq;
+ }
+ else
+ passInstructions[passIC++] = pass_lt;
+ goto doComp;
+ case pass_gt:
+ if (passLine.chars[passLinepos + 1] == pass_eq)
+ {
+ passLinepos++;
+ passInstructions[passIC++] = pass_gteq;
+ }
+ else
+ passInstructions[passIC++] = pass_gt;
+ doComp:
+ passInstructions[passIC++] = passHoldNumber;
+ passLinepos++;
+ passGetNumber ();
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ default:
+ compileError (passNested, "incorrect comparison operator");
+ return 0;
+ }
+ break;
+ case pass_attributes:
+ passLinepos++;
+ passGetAttributes ();
+ insertAttributes:
+ passInstructions[passIC++] = pass_attributes;
+ passInstructions[passIC++] = passAttributes >> 16;
+ passInstructions[passIC++] = passAttributes & 0xffff;
+ getRange:
+ if (passLine.chars[passLinepos] == pass_until)
+ {
+ passLinepos++;
+ passInstructions[passIC++] = 1;
+ passInstructions[passIC++] = 0xffff;
+ break;
+ }
+ passGetNumber ();
+ if (passHoldNumber == 0)
+ {
+ passHoldNumber = passInstructions[passIC++] = 1;
+ passInstructions[passIC++] = 1; /*This is not an error */
+ break;
+ }
+ passInstructions[passIC++] = passHoldNumber;
+ if (passLine.chars[passLinepos] != pass_hyphen)
+ {
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ }
+ passLinepos++;
+ passGetNumber ();
+ if (passHoldNumber == 0)
+ {
+ compileError (passNested, "invalid range");
+ return 0;
+ }
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ case pass_groupstart:
+ case pass_groupend:
+ passLinepos++;
+ passGetName ();
+ ruleOffset = findRuleName (&passHoldString);
+ if (ruleOffset)
+ rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
+ if (rule && rule->opcode == CTO_Grouping)
+ {
+ passInstructions[passIC++] = passSubOp;
+ passInstructions[passIC++] = ruleOffset >> 16;
+ passInstructions[passIC++] = ruleOffset & 0xffff;
+ break;
+ }
+ else
+ {
+ compileError (passNested, "%s is not a grouping name",
+ showString (&passHoldString.chars[0],
+ passHoldString.length));
+ return 0;
+ }
+ break;
+ case pass_swap:
+ passGetName ();
+ if ((class = findCharacterClass (&passHoldString)))
+ {
+ passAttributes = class->attribute;
+ goto insertAttributes;
+ }
+ ruleOffset = findRuleName (&passHoldString);
+ if (ruleOffset)
+ rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
+ if (rule
+ && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd
+ || rule->opcode == CTO_SwapDd))
+ {
+ passInstructions[passIC++] = pass_swap;
+ passInstructions[passIC++] = ruleOffset >> 16;
+ passInstructions[passIC++] = ruleOffset & 0xffff;
+ goto getRange;
+ }
+ compileError (passNested,
+ "%s is neither a class name nor a swap name.",
+ showString (&passHoldString.chars[0],
+ passHoldString.length));
+ return 0;
+ case pass_endTest:
+ passInstructions[passIC++] = pass_endTest;
+ passLinepos++;
+ break;
+ default:
+ compileError (passNested,
+ "incorrect operator '%c ' in test part",
+ passLine.chars[passLinepos]);
+ return 0;
+ }
+
+ } /*Compile action part */
+
+ /* Compile action part */
+ while (passLinepos < passLine.length &&
+ passLine.chars[passLinepos] <= 32)
+ passLinepos++;
+ while (passLinepos < passLine.length &&
+ passLine.chars[passLinepos] > 32)
+ {
+ switch ((passSubOp = passLine.chars[passLinepos]))
+ {
+ case pass_string:
+ if (opcode != CTO_Correct)
+ {
+ compileError (passNested,
+ "Character strings can only be used with the ccorrect opcode.");
+ return 0;
+ }
+ passLinepos++;
+ passInstructions[passIC++] = pass_string;
+ passGetString ();
+ goto actionDoCharsDots;
+ case pass_dots:
+ if (opcode == CTO_Correct)
+ {
+ compileError (passNested,
+ "Dot patterns cannot be used with the correct opcode.");
+ return 0;
+ }
+ passLinepos++;
+ passGetDots ();
+ passInstructions[passIC++] = pass_dots;
+ actionDoCharsDots:
+ if (passHoldString.length == 0)
+ return 0;
+ passInstructions[passIC++] = passHoldString.length;
+ for (kk = 0; kk < passHoldString.length; kk++)
+ passInstructions[passIC++] = passHoldString.chars[kk];
+ break;
+ case pass_variable:
+ passLinepos++;
+ passGetNumber ();
+ switch (passLine.chars[passLinepos])
+ {
+ case pass_eq:
+ passInstructions[passIC++] = pass_eq;
+ passInstructions[passIC++] = passHoldNumber;
+ passLinepos++;
+ passGetNumber ();
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ case pass_plus:
+ case pass_hyphen:
+ passInstructions[passIC++] = passLine.chars[passLinepos];
+ passInstructions[passIC++] = passHoldNumber;
+ break;
+ default:
+ compileError (passNested,
+ "incorrect variable operator in action part");
+ return 0;
+ }
+ break;
+ case pass_copy:
+ passInstructions[passIC++] = pass_copy;
+ passLinepos++;
+ break;
+ case pass_omit:
+ passInstructions[passIC++] = pass_omit;
+ passLinepos++;
+ break;
+ case pass_groupreplace:
+ case pass_groupstart:
+ case pass_groupend:
+ passLinepos++;
+ passGetName ();
+ ruleOffset = findRuleName (&passHoldString);
+ if (ruleOffset)
+ rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
+ if (rule && rule->opcode == CTO_Grouping)
+ {
+ passInstructions[passIC++] = passSubOp;
+ passInstructions[passIC++] = ruleOffset >> 16;
+ passInstructions[passIC++] = ruleOffset & 0xffff;
+ break;
+ }
+ compileError (passNested, "%s is not a grouping name",
+ showString (&passHoldString.chars[0],
+ passHoldString.length));
+ return 0;
+ case pass_swap:
+ passLinepos++;
+ passGetName ();
+ ruleOffset = findRuleName (&passHoldString);
+ if (ruleOffset)
+ rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
+ if (rule
+ && (rule->opcode == CTO_SwapCc || rule->opcode == CTO_SwapCd
+ || rule->opcode == CTO_SwapDd))
+ {
+ passInstructions[passIC++] = pass_swap;
+ passInstructions[passIC++] = ruleOffset >> 16;
+ passInstructions[passIC++] = ruleOffset & 0xffff;
+ break;
+ }
+ compileError (passNested, "%s is not a swap name.",
+ showString (&passHoldString.chars[0],
+ passHoldString.length));
+ return 0;
+ break;
+ default:
+ compileError (passNested, "incorrect operator in action part");
+ return 0;
+ }
+ }
+ }
+
+ /*Analyze and add rule */
+ passRuleDots.length = passIC;
+ passIC = 0;
+ while (passIC < passRuleDots.length)
+ {
+ int start = 0;
+ switch (passInstructions[passIC])
+ {
+ case pass_string:
+ case pass_dots:
+ case pass_attributes:
+ case pass_swap:
+ start = 1;
+ break;
+ case pass_groupstart:
+ case pass_groupend:
+ start = 1;
+ break;
+ case pass_eq:
+ case pass_lt:
+ case pass_gt:
+ case pass_lteq:
+ case pass_gteq:
+ passIC += 3;
+ break;
+ case pass_lookback:
+ passIC += 2;
+ break;
+ case pass_not:
+ case pass_startReplace:
+ case pass_endReplace:
+ case pass_first:
+ passIC++;
+ break;
+ default:
+ compileError (passNested,
+ "Test/if part must contain characters, dots, attributes or class \
+swap.");
+ return 0;
+ }
+ if (start)
+ break;
+ }
+
+ switch (passInstructions[passIC])
+ {
+ case pass_string:
+ case pass_dots:
+ for (k = 0; k < passInstructions[passIC + 1]; k++)
+ passRuleChars.chars[k] = passInstructions[passIC + 2 + k];
+ passRuleChars.length = k;
+ after = before = 0;
+ break;
+ case pass_attributes:
+ case pass_groupstart:
+ case pass_groupend:
+ case pass_swap:
+ after = passRuleDots.length;
+ before = 0;
+ break;
+ default:
+ break;
+ }
+ if (!addRule (passNested, opcode, &passRuleChars, &passRuleDots,
+ after, before))
+ return 0;
+ return 1;
+}
+
+/* End of multipass compiler */
+
+static int
+compileBrailleIndicator (FileInfo * nested, char *ermsg,
+ TranslationTableOpcode opcode,
+ TranslationTableOffset * rule)
+{
+ CharsString token;
+ CharsString cells;
+ if (getToken (nested, &token, ermsg))
+ if (parseDots (nested, &cells, &token))
+ if (!addRule (nested, opcode, NULL, &cells, 0, 0))
+ return 0;
+ *rule = newRuleOffset;
+ return 1;
+}
+
+static int
+compileNumber (FileInfo * nested)
+{
+ CharsString token;
+ widechar dest;
+ if (!getToken (nested, &token, "number"))
+ return 0;
+ getNumber (&token.chars[0], &dest);
+ if (!(dest > 0))
+ {
+ compileError (nested, "a nonzero positive number is required");
+ return 0;
+ }
+ return dest;
+}
+
+static int
+compileGrouping (FileInfo * nested)
+{
+ int k;
+ CharsString name;
+ CharsString groupChars;
+ CharsString groupDots;
+ CharsString dotsParsed;
+ TranslationTableCharacter *charsDotsPtr;
+ widechar endChar;
+ widechar endDots;
+ if (!getToken (nested, &name, "name operand"))
+ return 0;
+ if (!getRuleCharsText (nested, &groupChars))
+ return 0;
+ if (!getToken (nested, &groupDots, "dots operand"))
+ return 0;
+ for (k = 0; k < groupDots.length && groupDots.chars[k] != ','; k++);
+ if (k == groupDots.length)
+ {
+ compileError (nested,
+ "Dots operand must consist of two cells separated by a comma");
+ return 0;
+ }
+ groupDots.chars[k] = '-';
+ if (!parseDots (nested, &dotsParsed, &groupDots))
+ return 0;
+ if (groupChars.length != 2 || dotsParsed.length != 2)
+ {
+ compileError (nested,
+ "two Unicode characters and two cells separated by a comma are needed.");
+ return 0;
+ }
+ charsDotsPtr = addCharOrDots (nested, groupChars.chars[0], 0);
+ charsDotsPtr->attributes |= CTC_Math;
+ charsDotsPtr->uppercase = charsDotsPtr->realchar;
+ charsDotsPtr->lowercase = charsDotsPtr->realchar;
+ charsDotsPtr = addCharOrDots (nested, groupChars.chars[1], 0);
+ charsDotsPtr->attributes |= CTC_Math;
+ charsDotsPtr->uppercase = charsDotsPtr->realchar;
+ charsDotsPtr->lowercase = charsDotsPtr->realchar;
+ charsDotsPtr = addCharOrDots (nested, dotsParsed.chars[0], 1);
+ charsDotsPtr->attributes |= CTC_Math;
+ charsDotsPtr->uppercase = charsDotsPtr->realchar;
+ charsDotsPtr->lowercase = charsDotsPtr->realchar;
+ charsDotsPtr = addCharOrDots (nested, dotsParsed.chars[1], 1);
+ charsDotsPtr->attributes |= CTC_Math;
+ charsDotsPtr->uppercase = charsDotsPtr->realchar;
+ charsDotsPtr->lowercase = charsDotsPtr->realchar;
+ if (!addRule (nested, CTO_Grouping, &groupChars, &dotsParsed, 0, 0))
+ return 0;
+ if (!addRuleName (nested, &name))
+ return 0;
+ putCharAndDots (nested, groupChars.chars[0], dotsParsed.chars[0]);
+ putCharAndDots (nested, groupChars.chars[1], dotsParsed.chars[1]);
+ endChar = groupChars.chars[1];
+ endDots = dotsParsed.chars[1];
+ groupChars.length = dotsParsed.length = 1;
+ if (!addRule (nested, CTO_Math, &groupChars, &dotsParsed, 0, 0))
+ return 0;
+ groupChars.chars[0] = endChar;
+ dotsParsed.chars[0] = endDots;
+ if (!addRule (nested, CTO_Math, &groupChars, &dotsParsed, 0, 0))
+ return 0;
+ return 1;
+}
+
+static int
+compileUplow (FileInfo * nested)
+{
+ int k;
+ TranslationTableCharacter *upperChar;
+ TranslationTableCharacter *lowerChar;
+ TranslationTableCharacter *upperCell = NULL;
+ TranslationTableCharacter *lowerCell = NULL;
+ CharsString ruleChars;
+ CharsString ruleDots;
+ CharsString upperDots;
+ CharsString lowerDots;
+ int haveLowerDots = 0;
+ TranslationTableCharacterAttributes attr;
+ if (!getRuleCharsText (nested, &ruleChars))
+ return 0;
+ if (!getToken (nested, &ruleDots, "dots operand"))
+ return 0;
+ for (k = 0; k < ruleDots.length && ruleDots.chars[k] != ','; k++);
+ if (k == ruleDots.length)
+ {
+ if (!parseDots (nested, &upperDots, &ruleDots))
+ return 0;
+ lowerDots.length = upperDots.length;
+ for (k = 0; k < upperDots.length; k++)
+ lowerDots.chars[k] = upperDots.chars[k];
+ lowerDots.chars[k] = 0;
+ }
+ else
+ {
+ haveLowerDots = ruleDots.length;
+ ruleDots.length = k;
+ if (!parseDots (nested, &upperDots, &ruleDots))
+ return 0;
+ ruleDots.length = 0;
+ k++;
+ for (; k < haveLowerDots; k++)
+ ruleDots.chars[ruleDots.length++] = ruleDots.chars[k];
+ if (!parseDots (nested, &lowerDots, &ruleDots))
+ return 0;
+ }
+ if (ruleChars.length != 2 || upperDots.length < 1)
+ {
+ compileError (nested,
+ "Exactly two Unicode characters and at least one cell are required.");
+ return 0;
+ }
+ if (haveLowerDots && lowerDots.length < 1)
+ {
+ compileError (nested, "at least one cell is required after the comma.");
+ return 0;
+ }
+ upperChar = addCharOrDots (nested, ruleChars.chars[0], 0);
+ upperChar->attributes |= CTC_Letter | CTC_UpperCase;
+ upperChar->uppercase = ruleChars.chars[0];
+ upperChar->lowercase = ruleChars.chars[1];
+ lowerChar = addCharOrDots (nested, ruleChars.chars[1], 0);
+ lowerChar->attributes |= CTC_Letter | CTC_LowerCase;
+ lowerChar->uppercase = ruleChars.chars[0];
+ lowerChar->lowercase = ruleChars.chars[1];
+ for (k = 0; k < upperDots.length; k++)
+ if (!compile_findCharOrDots (upperDots.chars[k], 1))
+ {
+ attr = CTC_Letter | CTC_UpperCase;
+ upperCell = addCharOrDots (nested, upperDots.chars[k], 1);
+ if (upperDots.length != 1)
+ attr = CTC_Space;
+ upperCell->attributes |= attr;
+ upperCell->uppercase = upperCell->realchar;
+ }
+ if (haveLowerDots)
+ {
+ for (k = 0; k < lowerDots.length; k++)
+ if (!compile_findCharOrDots (lowerDots.chars[k], 1))
+ {
+ attr = CTC_Letter | CTC_LowerCase;
+ lowerCell = addCharOrDots (nested, lowerDots.chars[k], 1);
+ if (lowerDots.length != 1)
+ attr = CTC_Space;
+ lowerCell->attributes |= attr;
+ lowerCell->lowercase = lowerCell->realchar;
+ }
+ }
+ else if (upperCell != NULL && upperDots.length == 1)
+ upperCell->attributes |= CTC_LowerCase;
+ if (lowerDots.length == 1)
+ putCharAndDots (nested, ruleChars.chars[1], lowerDots.chars[0]);
+ if (upperCell != NULL)
+ upperCell->lowercase = lowerDots.chars[0];
+ if (lowerCell != NULL)
+ lowerCell->uppercase = upperDots.chars[0];
+ if (upperDots.length == 1)
+ putCharAndDots (nested, ruleChars.chars[0], upperDots.chars[0]);
+ ruleChars.length = 1;
+ ruleChars.chars[2] = ruleChars.chars[0];
+ ruleChars.chars[0] = ruleChars.chars[1];
+ if (!addRule (nested, CTO_LowerCase, &ruleChars, &lowerDots, 0, 0))
+ return 0;
+ ruleChars.chars[0] = ruleChars.chars[2];
+ if (!addRule (nested, CTO_UpperCase, &ruleChars, &upperDots, 0, 0))
+ return 0;
+ return 1;
+}
+
+/*Functions for compiling hyphenation tables*/
+
+typedef struct /*hyphenation dictionary: finite state machine */
+{
+ int numStates;
+ HyphenationState *states;
+} HyphenDict;
+
+#define DEFAULTSTATE 0xffff
+#define HYPHENHASHSIZE 8191
+
+typedef struct
+{
+ void *next;
+ CharsString *key;
+ int val;
+} HyphenHashEntry;
+
+typedef struct
+{
+ HyphenHashEntry *entries[HYPHENHASHSIZE];
+} HyphenHashTab;
+
+/* a hash function from ASU - adapted from Gtk+ */
+static unsigned int
+hyphenStringHash (const CharsString * s)
+{
+ int k;
+ unsigned int h = 0, g;
+ for (k = 0; k < s->length; k++)
+ {
+ h = (h << 4) + s->chars[k];
+ if ((g = h & 0xf0000000))
+ {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return h;
+}
+
+static HyphenHashTab *
+hyphenHashNew (void)
+{
+ HyphenHashTab *hashTab;
+ hashTab = malloc (sizeof (HyphenHashTab));
+ memset (hashTab, 0, sizeof (HyphenHashTab));
+ return hashTab;
+}
+
+static void
+hyphenHashFree (HyphenHashTab * hashTab)
+{
+ int i;
+ HyphenHashEntry *e, *next;
+ for (i = 0; i < HYPHENHASHSIZE; i++)
+ for (e = hashTab->entries[i]; e; e = next)
+ {
+ next = e->next;
+ free (e->key);
+ free (e);
+ }
+ free (hashTab);
+}
+
+/* assumes that key is not already present! */
+static void
+hyphenHashInsert (HyphenHashTab * hashTab, const CharsString * key, int val)
+{
+ int i, j;
+ HyphenHashEntry *e;
+ i = hyphenStringHash (key) % HYPHENHASHSIZE;
+ e = malloc (sizeof (HyphenHashEntry));
+ e->next = hashTab->entries[i];
+ e->key = malloc ((key->length + 1) * CHARSIZE);
+ e->key->length = key->length;
+ for (j = 0; j < key->length; j++)
+ e->key->chars[j] = key->chars[j];
+ e->val = val;
+ hashTab->entries[i] = e;
+}
+
+/* return val if found, otherwise DEFAULTSTATE */
+static int
+hyphenHashLookup (HyphenHashTab * hashTab, const CharsString * key)
+{
+ int i, j;
+ HyphenHashEntry *e;
+ if (key->length == 0)
+ return 0;
+ i = hyphenStringHash (key) % HYPHENHASHSIZE;
+ for (e = hashTab->entries[i]; e; e = e->next)
+ {
+ if (key->length != e->key->length)
+ continue;
+ for (j = 0; j < key->length; j++)
+ if (key->chars[j] != e->key->chars[j])
+ break;
+ if (j == key->length)
+ return e->val;
+ }
+ return DEFAULTSTATE;
+}
+
+static int
+hyphenGetNewState (HyphenDict * dict, HyphenHashTab * hashTab, const
+ CharsString * string)
+{
+ hyphenHashInsert (hashTab, string, dict->numStates);
+ /* predicate is true if dict->numStates is a power of two */
+ if (!(dict->numStates & (dict->numStates - 1)))
+ dict->states = realloc (dict->states,
+ (dict->numStates << 1) *
+ sizeof (HyphenationState));
+ dict->states[dict->numStates].hyphenPattern = 0;
+ dict->states[dict->numStates].fallbackState = DEFAULTSTATE;
+ dict->states[dict->numStates].numTrans = 0;
+ dict->states[dict->numStates].trans.pointer = NULL;
+ return dict->numStates++;
+}
+
+/* add a transition from state1 to state2 through ch - assumes that the
+ transition does not already exist */
+static void
+hyphenAddTrans (HyphenDict * dict, int state1, int state2, widechar ch)
+{
+ int numTrans;
+ numTrans = dict->states[state1].numTrans;
+ if (numTrans == 0)
+ dict->states[state1].trans.pointer = malloc (sizeof (HyphenationTrans));
+ else if (!(numTrans & (numTrans - 1)))
+ dict->states[state1].trans.pointer = realloc
+ (dict->states[state1].trans.pointer,
+ (numTrans << 1) * sizeof (HyphenationTrans));
+ dict->states[state1].trans.pointer[numTrans].ch = ch;
+ dict->states[state1].trans.pointer[numTrans].newState = state2;
+ dict->states[state1].numTrans++;
+}
+
+static int
+compileHyphenation (FileInfo * nested, CharsString * encoding)
+{
+ CharsString hyph;
+ HyphenationTrans *holdPointer;
+ HyphenHashTab *hashTab;
+ CharsString word;
+ char pattern[MAXSTRING];
+ unsigned int stateNum = 0, lastState = 0;
+ int i, j, k = encoding->length;
+ widechar ch;
+ int found;
+ HyphenHashEntry *e;
+ HyphenDict dict;
+ TranslationTableOffset holdOffset;
+ /*Set aside enough space for hyphenation states and transitions in
+ * translation table. Must be done before anything else*/
+ reserveSpaceInTable (nested, 250000);
+ hashTab = hyphenHashNew ();
+ dict.numStates = 1;
+ dict.states = malloc (sizeof (HyphenationState));
+ dict.states[0].hyphenPattern = 0;
+ dict.states[0].fallbackState = DEFAULTSTATE;
+ dict.states[0].numTrans = 0;
+ dict.states[0].trans.pointer = NULL;
+ do
+ {
+ if (encoding->chars[0] == 'I')
+ {
+ if (!getToken (nested, &hyph, NULL))
+ continue;
+ }
+ else
+ {
+ /*UTF-8 */
+ if (!getToken (nested, &word, NULL))
+ continue;
+ parseChars (nested, &hyph, &word);
+ }
+ if (hyph.length == 0 || hyph.chars[0] == '#' || hyph.chars[0] ==
+ '%' || hyph.chars[0] == '<')
+ continue; /*comment */
+ for (i = 0; i < hyph.length; i++)
+ definedCharOrDots (nested, hyph.chars[i], 0);
+ j = 0;
+ pattern[j] = '0';
+ for (i = 0; i < hyph.length; i++)
+ {
+ if (hyph.chars[i] >= '0' && hyph.chars[i] <= '9')
+ pattern[j] = (char) hyph.chars[i];
+ else
+ {
+ word.chars[j] = hyph.chars[i];
+ pattern[++j] = '0';
+ }
+ }
+ word.chars[j] = 0;
+ word.length = j;
+ pattern[j + 1] = 0;
+ for (i = 0; pattern[i] == '0'; i++);
+ found = hyphenHashLookup (hashTab, &word);
+ if (found != DEFAULTSTATE)
+ stateNum = found;
+ else
+ stateNum = hyphenGetNewState (&dict, hashTab, &word);
+ k = j + 2 - i;
+ if (k > 0)
+ {
+ allocateSpaceInTable (nested,
+ &dict.states[stateNum].hyphenPattern, k);
+ memcpy (&table->ruleArea[dict.states[stateNum].hyphenPattern],
+ &pattern[i], k);
+ }
+ /* now, put in the prefix transitions */
+ while (found == DEFAULTSTATE)
+ {
+ lastState = stateNum;
+ ch = word.chars[word.length-- - 1];
+ found = hyphenHashLookup (hashTab, &word);
+ if (found != DEFAULTSTATE)
+ stateNum = found;
+ else
+ stateNum = hyphenGetNewState (&dict, hashTab, &word);
+ hyphenAddTrans (&dict, stateNum, lastState, ch);
+ }
+ }
+ while (getALine (nested));
+ /* put in the fallback states */
+ for (i = 0; i < HYPHENHASHSIZE; i++)
+ {
+ for (e = hashTab->entries[i]; e; e = e->next)
+ {
+ for (j = 1; j <= e->key->length; j++)
+ {
+ word.length = 0;
+ for (k = j; k < e->key->length; k++)
+ word.chars[word.length++] = e->key->chars[k];
+ stateNum = hyphenHashLookup (hashTab, &word);
+ if (stateNum != DEFAULTSTATE)
+ break;
+ }
+ if (e->val)
+ dict.states[e->val].fallbackState = stateNum;
+ }
+ }
+ hyphenHashFree (hashTab);
+/*Transfer hyphenation information to table*/
+ for (i = 0; i < dict.numStates; i++)
+ {
+ if (dict.states[i].numTrans == 0)
+ dict.states[i].trans.offset = 0;
+ else
+ {
+ holdPointer = dict.states[i].trans.pointer;
+ allocateSpaceInTable (nested,
+ &dict.states[i].trans.offset,
+ dict.states[i].numTrans *
+ sizeof (HyphenationTrans));
+ memcpy (&table->ruleArea[dict.states[i].trans.offset],
+ holdPointer,
+ dict.states[i].numTrans * sizeof (HyphenationTrans));
+ free (holdPointer);
+ }
+ }
+ allocateSpaceInTable (nested,
+ &holdOffset, dict.numStates *
+ sizeof (HyphenationState));
+ table->hyphenStatesArray = holdOffset;
+ /* Prevents segmentajion fault if table is reallocated */
+ memcpy (&table->ruleArea[table->hyphenStatesArray], &dict.states[0],
+ dict.numStates * sizeof (HyphenationState));
+ free (dict.states);
+ return 1;
+}
+
+static int
+compileNoBreak (FileInfo * nested)
+{
+ int k;
+ CharsString ruleDots;
+ CharsString otherDots;
+ CharsString dotsBefore;
+ CharsString dotsAfter;
+ int haveDotsAfter = 0;
+ if (!getToken (nested, &ruleDots, "dots operand"))
+ return 0;
+ for (k = 0; k < ruleDots.length && ruleDots.chars[k] != ','; k++);
+ if (k == ruleDots.length)
+ {
+ if (!parseDots (nested, &dotsBefore, &ruleDots))
+ return 0;
+ dotsAfter.length = dotsBefore.length;
+ for (k = 0; k < dotsBefore.length; k++)
+ dotsAfter.chars[k] = dotsBefore.chars[k];
+ dotsAfter.chars[k] = 0;
+ }
+ else
+ {
+ haveDotsAfter = ruleDots.length;
+ ruleDots.length = k;
+ if (!parseDots (nested, &dotsBefore, &ruleDots))
+ return 0;
+ otherDots.length = 0;
+ k++;
+ for (; k < haveDotsAfter; k++)
+ otherDots.chars[otherDots.length++] = ruleDots.chars[k];
+ if (!parseDots (nested, &dotsAfter, &otherDots))
+ return 0;
+ }
+ for (k = 0; k < dotsBefore.length; k++)
+ dotsBefore.chars[k] = getCharFromDots (dotsBefore.chars[k]);
+ for (k = 0; k < dotsAfter.length; k++)
+ dotsAfter.chars[k] = getCharFromDots (dotsAfter.chars[k]);
+ if (!addRule (nested, CTO_NoBreak, &dotsBefore, &dotsAfter, 0, 0))
+ return 0;
+ table->noBreak = newRuleOffset;
+ return 1;
+}
+
+static int
+compileCharDef (FileInfo * nested,
+ TranslationTableOpcode opcode,
+ TranslationTableCharacterAttributes attributes)
+{
+ CharsString ruleChars;
+ CharsString ruleDots;
+ TranslationTableCharacter *character;
+ TranslationTableCharacter *cell;
+ TranslationTableCharacter *otherCell;
+ TranslationTableCharacterAttributes attr;
+ int k;
+ if (!getRuleCharsText (nested, &ruleChars))
+ return 0;
+ if (attributes & (CTC_UpperCase | CTC_LowerCase))
+ attributes |= CTC_Letter;
+ if (!getRuleDotsPattern (nested, &ruleDots))
+ return 0;
+ if (ruleChars.length != 1 || ruleDots.length < 1)
+ {
+ compileError (nested,
+ "Exactly one Unicode character and at least one cell are required.");
+ return 0;
+ }
+ character = addCharOrDots (nested, ruleChars.chars[0], 0);
+ character->attributes |= attributes;
+ character->uppercase = character->lowercase = character->realchar;
+ cell = compile_findCharOrDots (ruleDots.chars[0], 1);
+ if (ruleDots.length == 1 && cell)
+ cell->attributes |= attributes;
+ else
+ {
+ for (k = 0; k < ruleDots.length; k++)
+ {
+ if (!compile_findCharOrDots (ruleDots.chars[k], 1))
+ {
+ attr = attributes;
+ otherCell = addCharOrDots (nested, ruleDots.chars[k], 1);
+ if (ruleDots.length != 1)
+ attr = CTC_Space;
+ otherCell->attributes |= attr;
+ otherCell->uppercase = otherCell->lowercase =
+ otherCell->realchar;
+ }
+ }
+ }
+ if (!addRule (nested, opcode, &ruleChars, &ruleDots, 0, 0))
+ return 0;
+ if (ruleDots.length == 1)
+ putCharAndDots (nested, ruleChars.chars[0], ruleDots.chars[0]);
+ return 1;
+}
+
+static int
+compileRule (FileInfo * nested)
+{
+ int ok = 1;
+ CharsString token;
+ TranslationTableOpcode opcode;
+ CharsString ruleChars;
+ CharsString ruleDots;
+ CharsString cells;
+ CharsString scratchPad;
+ TranslationTableCharacterAttributes after = 0;
+ TranslationTableCharacterAttributes before = 0;
+ int k;
+
+ noback = nofor = 0;
+doOpcode:
+ if (!getToken (nested, &token, NULL))
+ return 1; /*blank line */
+ if (token.chars[0] == '#' || token.chars[0] == '<')
+ return 1; /*comment */
+ if (nested->lineNumber == 1 && (eqasc2uni ((unsigned char *) "ISO",
+ token.chars, 3) ||
+ eqasc2uni ((unsigned char *) "UTF-8",
+ token.chars, 5)))
+ {
+ compileHyphenation (nested, &token);
+ return 1;
+ }
+ opcode = getOpcode (nested, &token);
+ switch (opcode)
+ { /*Carry out operations */
+ case CTO_None:
+ break;
+ case CTO_IncludeFile:
+ {
+ CharsString includedFile;
+ if (getToken (nested, &token, "include file name"))
+ if (parseChars (nested, &includedFile, &token))
+ if (!includeFile (nested, &includedFile))
+ ok = 0;
+ break;
+ }
+ case CTO_Locale:
+ break;
+ case CTO_Undefined:
+ ok =
+ compileBrailleIndicator (nested, "undefined character opcode",
+ CTO_Undefined, &table->undefined);
+ break;
+ case CTO_CapitalSign:
+ ok =
+ compileBrailleIndicator (nested, "capital sign", CTO_CapitalRule,
+ &table->capitalSign);
+ break;
+ case CTO_BeginCapitalSign:
+ ok =
+ compileBrailleIndicator (nested, "begin capital sign",
+ CTO_BeginCapitalRule,
+ &table->beginCapitalSign);
+ break;
+ case CTO_LenBegcaps:
+ ok = table->lenBeginCaps = compileNumber (nested);
+ break;
+ case CTO_EndCapitalSign:
+ ok =
+ compileBrailleIndicator (nested, "end capitals sign",
+ CTO_EndCapitalRule, &table->endCapitalSign);
+ break;
+ case CTO_FirstWordCaps:
+ ok =
+ compileBrailleIndicator (nested, "first word capital sign",
+ CTO_FirstWordCapsRule,
+ &table->firstWordCaps);
+ break;
+ case CTO_LastWordCapsBefore:
+ ok =
+ compileBrailleIndicator (nested, "capital sign before last word",
+ CTO_LastWordCapsBeforeRule,
+ &table->lastWordCapsBefore);
+ break;
+ case CTO_LastWordCapsAfter:
+ ok =
+ compileBrailleIndicator (nested, "capital sign after last word",
+ CTO_LastWordCapsAfterRule,
+ &table->lastWordCapsAfter);
+ break;
+ case CTO_LenCapsPhrase:
+ ok = table->lenCapsPhrase = compileNumber (nested);
+ break;
+ case CTO_LetterSign:
+ ok =
+ compileBrailleIndicator (nested, "letter sign", CTO_LetterRule,
+ &table->letterSign);
+ break;
+ case CTO_NoLetsignBefore:
+ if (getRuleCharsText (nested, &ruleChars))
+ {
+ if ((table->noLetsignBeforeCount + ruleChars.length) > LETSIGNSIZE)
+ {
+ compileError (nested, "More than %d characters", LETSIGNSIZE);
+ ok = 0;
+ break;
+ }
+ for (k = 0; k < ruleChars.length; k++)
+ table->noLetsignBefore[table->noLetsignBeforeCount++] =
+ ruleChars.chars[k];
+ }
+ break;
+ case CTO_NoLetsign:
+ if (getRuleCharsText (nested, &ruleChars))
+ {
+ if ((table->noLetsignCount + ruleChars.length) > LETSIGNSIZE)
+ {
+ compileError (nested, "More than %d characters", LETSIGNSIZE);
+ ok = 0;
+ break;
+ }
+ for (k = 0; k < ruleChars.length; k++)
+ table->noLetsign[table->noLetsignCount++] = ruleChars.chars[k];
+ }
+ break;
+ case CTO_NoLetsignAfter:
+ if (getRuleCharsText (nested, &ruleChars))
+ {
+ if ((table->noLetsignAfterCount + ruleChars.length) > LETSIGNSIZE)
+ {
+ compileError (nested, "More than %d characters", LETSIGNSIZE);
+ ok = 0;
+ break;
+ }
+ for (k = 0; k < ruleChars.length; k++)
+ table->noLetsignAfter[table->noLetsignAfterCount++] =
+ ruleChars.chars[k];
+ }
+ break;
+ case CTO_NumberSign:
+ ok =
+ compileBrailleIndicator (nested, "number sign", CTO_NumberRule,
+ &table->numberSign);
+ break;
+ case CTO_FirstWordItal:
+ ok =
+ compileBrailleIndicator (nested, "first word italic",
+ CTO_FirstWordItalRule,
+ &table->firstWordItal);
+ break;
+ case CTO_ItalSign:
+ case CTO_LastWordItalBefore:
+ ok =
+ compileBrailleIndicator (nested, "first word italic before",
+ CTO_LastWordItalBeforeRule,
+ &table->lastWordItalBefore);
+ break;
+ case CTO_LastWordItalAfter:
+ ok =
+ compileBrailleIndicator (nested, "last word italic after",
+ CTO_LastWordItalAfterRule,
+ &table->lastWordItalAfter);
+ break;
+ case CTO_BegItal:
+ case CTO_FirstLetterItal:
+ ok =
+ compileBrailleIndicator (nested, "first letter italic",
+ CTO_FirstLetterItalRule,
+ &table->firstLetterItal);
+ break;
+ case CTO_EndItal:
+ case CTO_LastLetterItal:
+ ok =
+ compileBrailleIndicator (nested, "last letter italic",
+ CTO_LastLetterItalRule,
+ &table->lastLetterItal);
+ break;
+ case CTO_SingleLetterItal:
+ ok =
+ compileBrailleIndicator (nested, "single letter italic",
+ CTO_SingleLetterItalRule,
+ &table->singleLetterItal);
+ break;
+ case CTO_ItalWord:
+ ok =
+ compileBrailleIndicator (nested, "italic word", CTO_ItalWordRule,
+ &table->italWord);
+ break;
+ case CTO_LenItalPhrase:
+ ok = table->lenItalPhrase = compileNumber (nested);
+ break;
+ case CTO_FirstWordBold:
+ ok =
+ compileBrailleIndicator (nested, "first word bold",
+ CTO_FirstWordBoldRule,
+ &table->firstWordBold);
+ break;
+ case CTO_BoldSign:
+ case CTO_LastWordBoldBefore:
+ ok =
+ compileBrailleIndicator (nested, "last word bold before",
+ CTO_LastWordBoldBeforeRule,
+ &table->lastWordBoldBefore);
+ break;
+ case CTO_LastWordBoldAfter:
+ ok =
+ compileBrailleIndicator (nested, "last word bold after",
+ CTO_LastWordBoldAfterRule,
+ &table->lastWordBoldAfter);
+ break;
+ case CTO_BegBold:
+ case CTO_FirstLetterBold:
+ ok =
+ compileBrailleIndicator (nested, "first letter bold",
+ CTO_FirstLetterBoldRule,
+ &table->firstLetterBold);
+ break;
+ case CTO_EndBold:
+ case CTO_LastLetterBold:
+ ok =
+ compileBrailleIndicator (nested, "last letter bold",
+ CTO_LastLetterBoldRule,
+ &table->lastLetterBold);
+ break;
+ case CTO_SingleLetterBold:
+ ok =
+ compileBrailleIndicator (nested, "single letter bold",
+ CTO_SingleLetterBoldRule,
+ &table->singleLetterBold);
+ break;
+ case CTO_BoldWord:
+ ok =
+ compileBrailleIndicator (nested, "bold word", CTO_BoldWordRule,
+ &table->boldWord);
+ break;
+ case CTO_LenBoldPhrase:
+ ok = table->lenBoldPhrase = compileNumber (nested);
+ break;
+ case CTO_FirstWordUnder:
+ ok =
+ compileBrailleIndicator (nested, "first word underline",
+ CTO_FirstWordUnderRule,
+ &table->firstWordUnder);
+ break;
+ case CTO_UnderSign:
+ case CTO_LastWordUnderBefore:
+ ok =
+ compileBrailleIndicator (nested, "last word underline before",
+ CTO_LastWordUnderBeforeRule,
+ &table->lastWordUnderBefore);
+ break;
+ case CTO_LastWordUnderAfter:
+ ok =
+ compileBrailleIndicator (nested, "last word underline after",
+ CTO_LastWordUnderAfterRule,
+ &table->lastWordUnderAfter);
+ break;
+ case CTO_BegUnder:
+ case CTO_FirstLetterUnder:
+ ok =
+ compileBrailleIndicator (nested, "first letter underline",
+ CTO_FirstLetterUnderRule,
+ &table->firstLetterUnder);
+ break;
+ case CTO_EndUnder:
+ case CTO_LastLetterUnder:
+ ok =
+ compileBrailleIndicator (nested, "last letter underline",
+ CTO_LastLetterUnderRule,
+ &table->lastLetterUnder);
+ break;
+ case CTO_SingleLetterUnder:
+ ok =
+ compileBrailleIndicator (nested, "single letter underline",
+ CTO_SingleLetterUnderRule,
+ &table->singleLetterUnder);
+ break;
+ case CTO_UnderWord:
+ ok =
+ compileBrailleIndicator (nested, "underlined word", CTO_UnderWordRule,
+ &table->underWord);
+ break;
+ case CTO_LenUnderPhrase:
+ ok = table->lenUnderPhrase = compileNumber (nested);
+ break;
+ case CTO_BegComp:
+ ok =
+ compileBrailleIndicator (nested, "begin computer braille",
+ CTO_BegCompRule, &table->begComp);
+ break;
+ case CTO_EndComp:
+ ok =
+ compileBrailleIndicator (nested, "end computer braslle",
+ CTO_EndCompRule, &table->endComp);
+ break;
+ case CTO_Syllable:
+ table->syllables = 1;
+ case CTO_Always:
+ case CTO_NoCross:
+ case CTO_LargeSign:
+ case CTO_WholeWord:
+ case CTO_PartWord:
+ case CTO_JoinNum:
+ case CTO_JoinableWord:
+ case CTO_LowWord:
+ case CTO_SuffixableWord:
+ case CTO_PrefixableWord:
+ case CTO_BegWord:
+ case CTO_BegMidWord:
+ case CTO_MidWord:
+ case CTO_MidEndWord:
+ case CTO_EndWord:
+ case CTO_PrePunc:
+ case CTO_PostPunc:
+ case CTO_BegNum:
+ case CTO_MidNum:
+ case CTO_EndNum:
+ case CTO_Repeated:
+ case CTO_RepWord:
+ if (getRuleCharsText (nested, &ruleChars))
+ if (getRuleDotsPattern (nested, &ruleDots))
+ if (!addRule (nested, opcode, &ruleChars, &ruleDots, after, before))
+ ok = 0;
+ break;
+ case CTO_CompDots:
+ case CTO_Comp6:
+ if (!getRuleCharsText (nested, &ruleChars))
+ return 0;
+ if (ruleChars.length != 1 || ruleChars.chars[0] > 255)
+ {
+ compileError (nested,
+ "first operand must be 1 character and < 256");
+ return 0;
+ }
+ if (!getRuleDotsPattern (nested, &ruleDots))
+ return 0;
+ if (!addRule (nested, opcode, &ruleChars, &ruleDots, after, before))
+ ok = 0;
+ table->compdotsPattern[ruleChars.chars[0]] = newRuleOffset;
+ break;
+ case CTO_ExactDots:
+ if (!getRuleCharsText (nested, &ruleChars))
+ return 0;
+ if (ruleChars.chars[0] != '@')
+ {
+ compileError (nested, "The operand must begin with an at sign (@)");
+ return 0;
+ }
+ for (k = 1; k < ruleChars.length; k++)
+ scratchPad.chars[k - 1] = ruleChars.chars[k];
+ scratchPad.length = ruleChars.length - 1;
+ if (!parseDots (nested, &ruleDots, &scratchPad))
+ return 0;
+ if (!addRule (nested, opcode, &ruleChars, &ruleDots, before, after))
+ ok = 0;
+ break;
+ case CTO_CapsNoCont:
+ ruleChars.length = 1;
+ ruleChars.chars[0] = 'a';
+ if (!addRule
+ (nested, CTO_CapsNoContRule, &ruleChars, NULL, after, before))
+ ok = 0;
+ table->capsNoCont = newRuleOffset;
+ break;
+ case CTO_Replace:
+ if (getRuleCharsText (nested, &ruleChars))
+ {
+ if (lastToken)
+ ruleDots.length = ruleDots.chars[0] = 0;
+ else
+ {
+ getRuleDotsText (nested, &ruleDots);
+ if (ruleDots.chars[0] == '#')
+ ruleDots.length = ruleDots.chars[0] = 0;
+ else if (ruleDots.chars[0] == '\\' && ruleDots.chars[1] == '#')
+ memcpy (&ruleDots.chars[0], &ruleDots.chars[1],
+ ruleDots.length-- * CHARSIZE);
+ }
+ }
+ for (k = 0; k < ruleChars.length; k++)
+ addCharOrDots (nested, ruleChars.chars[k], 0);
+ for (k = 0; k < ruleDots.length; k++)
+ addCharOrDots (nested, ruleDots.chars[k], 0);
+ if (!addRule (nested, opcode, &ruleChars, &ruleDots, after, before))
+ ok = 0;
+ break;
+ case CTO_Pass2:
+ if (table->numPasses < 2)
+ table->numPasses = 2;
+ goto doPass;
+ case CTO_Pass3:
+ if (table->numPasses < 3)
+ table->numPasses = 3;
+ goto doPass;
+ case CTO_Pass4:
+ if (table->numPasses < 4)
+ table->numPasses = 4;
+ doPass:
+ case CTO_Context:
+ if (!compilePassOpcode (nested, opcode))
+ ok = 0;
+ break;
+ case CTO_Correct:
+ if (!compilePassOpcode (nested, opcode))
+ ok = 0;
+ table->corrections = 1;
+ break;
+ case CTO_Contraction:
+ case CTO_NoCont:
+ case CTO_CompBrl:
+ case CTO_Literal:
+ if (getRuleCharsText (nested, &ruleChars))
+ if (!addRule (nested, opcode, &ruleChars, NULL, after, before))
+ ok = 0;
+ break;
+ case CTO_MultInd:
+ {
+ int lastToken;
+ ruleChars.length = 0;
+ if (getToken (nested, &token, "multiple braille indicators") &&
+ parseDots (nested, &cells, &token))
+ {
+ while ((lastToken = getToken (nested, &token, "multind opcodes")))
+ {
+ opcode = getOpcode (nested, &token);
+ if (opcode >= CTO_CapitalSign && opcode < CTO_MultInd)
+ ruleChars.chars[ruleChars.length++] = (widechar) opcode;
+ else
+ {
+ compileError (nested, "Not a braille indicator opcode.");
+ ok = 0;
+ }
+ if (lastToken == 2)
+ break;
+ }
+ }
+ else
+ ok = 0;
+ if (!addRule (nested, CTO_MultInd, &ruleChars, &cells, after, before))
+ ok = 0;
+ break;
+ }
+
+ case CTO_Class:
+ {
+ CharsString characters;
+ const struct CharacterClass *class;
+ if (!characterClasses)
+ {
+ if (!allocateCharacterClasses ())
+ ok = 0;
+ }
+ if (getToken (nested, &token, "character class name"))
+ {
+ if ((class = findCharacterClass (&token)))
+ {
+ compileError (nested, "character class already defined.");
+ }
+ else
+ if ((class =
+ addCharacterClass (nested, &token.chars[0], token.length)))
+ {
+ if (getCharacters (nested, &characters))
+ {
+ int index;
+ for (index = 0; index < characters.length; ++index)
+ {
+ TranslationTableRule *defRule;
+ TranslationTableCharacter *character =
+ definedCharOrDots
+ (nested, characters.chars[index], 0);
+ character->attributes |= class->attribute;
+ defRule = (TranslationTableRule *)
+ & table->ruleArea[character->definitionRule];
+ if (defRule->dotslen == 1)
+ {
+ character = definedCharOrDots
+ (nested,
+ defRule->charsdots[defRule->charslen], 1);
+ character->attributes |= class->attribute;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ {
+ TranslationTableCharacterAttributes *attributes;
+ const struct CharacterClass *class;
+ case CTO_After:
+ attributes = &after;
+ goto doClass;
+ case CTO_Before:
+ attributes = &before;
+ doClass:
+
+ if (!characterClasses)
+ {
+ if (!allocateCharacterClasses ())
+ ok = 0;
+ }
+ if (getCharacterClass (nested, &class))
+ {
+ *attributes |= class->attribute;
+ goto doOpcode;
+ }
+ break;
+ }
+ case CTO_NoBack:
+ noback = 1;
+ goto doOpcode;
+ case CTO_NoFor:
+ nofor = 1;
+ goto doOpcode;
+ case CTO_SwapCc:
+ case CTO_SwapCd:
+ case CTO_SwapDd:
+ if (!compileSwap (nested, opcode))
+ ok = 0;
+ break;
+ case CTO_Hyphen:
+ case CTO_DecPoint:
+ if (getRuleCharsText (nested, &ruleChars))
+ if (getRuleDotsPattern (nested, &ruleDots))
+ {
+ if (ruleChars.length != 1 || ruleDots.length < 1)
+ {
+ compileError (nested,
+ "One Unicode character and at least one cell are required.");
+ ok = 0;
+ }
+ if (!addRule
+ (nested, opcode, &ruleChars, &ruleDots, after, before))
+ ok = 0;
+ }
+ break;
+ case CTO_Space:
+ compileCharDef (nested, opcode, CTC_Space);
+ break;
+ case CTO_Digit:
+ compileCharDef (nested, opcode, CTC_Digit);
+ break;
+ case CTO_LitDigit:
+ compileCharDef (nested, opcode, CTC_LitDigit);
+ break;
+ case CTO_Punctuation:
+ compileCharDef (nested, opcode, CTC_Punctuation);
+ break;
+ case CTO_Math:
+ compileCharDef (nested, opcode, CTC_Math);
+ break;
+ case CTO_Sign:
+ compileCharDef (nested, opcode, CTC_Sign);
+ break;
+ case CTO_Letter:
+ compileCharDef (nested, opcode, CTC_Letter);
+ break;
+ case CTO_UpperCase:
+ compileCharDef (nested, opcode, CTC_UpperCase);
+ break;
+ case CTO_LowerCase:
+ compileCharDef (nested, opcode, CTC_LowerCase);
+ break;
+ case CTO_NoBreak:
+ ok = compileNoBreak (nested);
+ break;
+ case CTO_Grouping:
+ ok = compileGrouping (nested);
+ break;
+ case CTO_UpLow:
+ ok = compileUplow (nested);
+ break;
+ case CTO_Display:
+ if (getRuleCharsText (nested, &ruleChars))
+ if (getRuleDotsPattern (nested, &ruleDots))
+ {
+ if (ruleChars.length != 1 || ruleDots.length != 1)
+ {
+ compileError (nested,
+ "Exactly one character and one cell are required.");
+ ok = 0;
+ }
+ putCharAndDots (nested, ruleChars.chars[0], ruleDots.chars[0]);
+ }
+ break;
+ default:
+ compileError (nested, "unimplemented opcode.");
+ break;
+ }
+ return ok;
+}
+
+int EXPORT_CALL
+lou_readCharFromFile (const char *fileName, int *mode)
+{
+/*Read a character from a file, whether big-endian, little-endian or
+* ASCII8*/
+ int ch;
+ static FileInfo nested;
+ if (fileName == NULL)
+ return 0;
+ if (*mode == 1)
+ {
+ *mode = 0;
+ nested.fileName = fileName;
+ nested.encoding = noEncoding;
+ nested.status = 0;
+ nested.lineNumber = 0;
+ if (!(nested.in = fopen (nested.fileName, "r")))
+ {
+ lou_logPrint ("Cannot open file '%s'", nested.fileName);
+ *mode = 1;
+ return EOF;
+ }
+ }
+ if (nested.in == NULL)
+ {
+ *mode = 1;
+ return EOF;
+ }
+ ch = getAChar (&nested);
+ if (ch == EOF)
+ {
+ fclose (nested.in);
+ nested.in = NULL;
+ *mode = 1;
+ }
+ return ch;
+}
+
+static int fileCount = 0;
+static FILE *
+findTable (const char *tableName)
+{
+/* Search paths for tables */
+ FILE *tableFile;
+ char *pathList;
+ char pathEnd[2];
+ char trialPath[MAXSTRING];
+ if (tableName == NULL || tableName[0] == 0)
+ return NULL;
+ strcpy (trialPath, tablePath);
+ strcat (trialPath, tableName);
+ if ((tableFile = fopen (trialPath, "rb")))
+ return tableFile;
+ pathEnd[0] = DIR_SEP;
+ pathEnd[1] = 0;
+ /* See if table is on environment path LOUIS_TABLEPATH */
+ pathList = getenv ("LOUIS_TABLEPATH");
+ if (pathList)
+ while (1)
+ {
+ int k;
+ int listLength;
+ int currentListPos = 0;
+ listLength = strlen (pathList);
+ for (k = 0; k < listLength; k++)
+ if (pathList[k] == ',')
+ break;
+ if (k == listLength || k == 0)
+ { /* Only one file */
+ strcpy (trialPath, pathList);
+ strcat (trialPath, pathEnd);
+ strcat (trialPath, tableName);
+ if ((tableFile = fopen (trialPath, "rb")))
+ break;
+ }
+ else
+ { /* Compile a list of files */
+ strncpy (trialPath, pathList, k);
+ trialPath[k] = 0;
+ strcat (trialPath, pathEnd);
+ strcat (trialPath, tableName);
+ currentListPos = k + 1;
+ if ((tableFile = fopen (trialPath, "rb")))
+ break;
+ while (currentListPos < listLength)
+ {
+ for (k = currentListPos; k < listLength; k++)
+ if (pathList[k] == ',')
+ break;
+ strncpy (trialPath,
+ &pathList[currentListPos], k - currentListPos);
+ trialPath[k - currentListPos] = 0;
+ strcat (trialPath, pathEnd);
+ strcat (trialPath, tableName);
+ if ((tableFile = fopen (trialPath, "rb")))
+ currentListPos = k + 1;
+ break;
+ }
+ }
+ break;
+ }
+ if (tableFile)
+ return tableFile;
+ /* See if table in current directory or on a path in
+ * the table name*/
+ if ((tableFile = fopen (tableName, "rb")))
+ return tableFile;
+/* See if table on dataPath. */
+ pathList = lou_getDataPath ();
+ if (pathList)
+ {
+ strcpy (trialPath, pathList);
+ strcat (trialPath, pathEnd);
+#ifdef _WIN32
+ strcat (trialPath, "liblouis\\tables\\");
+#else
+ strcat (trialPath, "liblouis/tables/");
+#endif
+ strcat (trialPath, tableName);
+ if ((tableFile = fopen (trialPath, "rb")))
+ return tableFile;
+ }
+ /* See if table on installed or program path. */
+#ifdef _WIN32
+ strcpy (trialPath, lou_getProgramPath ());
+ strcat (trialPath, "\\share\\liblouss\\tables\\");
+#else
+ strcpy (trialPath, TABLESDIR);
+ strcat (trialPath, pathEnd);
+#endif
+ strcat (trialPath, tableName);
+ if ((tableFile = fopen (trialPath, "rb")))
+ return tableFile;
+ return NULL;
+}
+
+static int
+compileFile (const char *fileName)
+{
+/*Compile a table file */
+ FileInfo nested;
+ fileCount++;
+ nested.fileName = fileName;
+ nested.encoding = noEncoding;
+ nested.status = 0;
+ nested.lineNumber = 0;
+ if ((nested.in = findTable (fileName)))
+ {
+ while (getALine (&nested))
+ compileRule (&nested);
+ fclose (nested.in);
+ }
+ else
+ {
+ if (fileCount > 1)
+ lou_logPrint ("Cannot open table '%s'", nested.fileName);
+ errorCount++;
+ return 0;
+ }
+ return 1;
+}
+
+static int
+compileString (const char *inString)
+{
+/* This function can be used to make changes to tables on the fly. */
+ int k;
+ FileInfo nested;
+ if (inString == NULL)
+ return 0;
+ nested.fileName = inString;
+ nested.encoding = noEncoding;
+ nested.lineNumber = 1;
+ nested.status = 0;
+ nested.linepos = 0;
+ for (k = 0; inString[k]; k++)
+ nested.line[k] = inString[k];
+ nested.line[k] = 0;
+ return compileRule (&nested);
+}
+
+static int
+makeDoubleRule (TranslationTableOpcode opcode, TranslationTableOffset
+ * singleRule, TranslationTableOffset * doubleRule)
+{
+ CharsString dots;
+ TranslationTableRule *rule;
+ if (!*singleRule || *doubleRule)
+ return 1;
+ rule = (TranslationTableRule *) & table->ruleArea[*singleRule];
+ memcpy (dots.chars, &rule->charsdots[0], rule->dotslen * CHARSIZE);
+ memcpy (&dots.chars[rule->dotslen], &rule->charsdots[0],
+ rule->dotslen * CHARSIZE);
+ dots.length = 2 * rule->dotslen;
+ if (!addRule (NULL, opcode, NULL, &dots, 0, 0))
+ return 0;
+ *doubleRule = newRuleOffset;
+ return 1;
+}
+
+static int
+setDefaults (void)
+{
+ if (!table->lenBeginCaps)
+ table->lenBeginCaps = 2;
+ makeDoubleRule (CTO_FirstWordItal, &table->lastWordItalBefore,
+ &table->firstWordItal);
+ if (!table->lenItalPhrase)
+ table->lenItalPhrase = 4;
+ makeDoubleRule (CTO_FirstWordBold, &table->lastWordBoldBefore,
+ &table->firstWordBold);
+ if (!table->lenBoldPhrase)
+ table->lenBoldPhrase = 4;
+ makeDoubleRule (CTO_FirstWordUnder, &table->lastWordUnderBefore,
+ &table->firstWordUnder);
+ if (!table->lenUnderPhrase)
+ table->lenUnderPhrase = 4;
+ if (table->numPasses == 0)
+ table->numPasses = 1;
+ return 1;
+}
+
+static char *
+doLang2table (const char *tableList)
+{
+ static char newList[MAXSTRING];
+ int k;
+ char buffer[MAXSTRING];
+ FILE *l2t;
+ char *langCode;
+ int langCodeLen;
+ if (tableList == NULL || *tableList == 0)
+ return NULL;
+ strcpy (newList, tableList);
+ for (k = strlen (newList) - 1; k >= 0 && newList[k] != '='; k--);
+ if (k < 0)
+ return newList;
+ fileCount = 1;
+ errorCount = 1;
+ newList[k] = 0;
+ strcpy (buffer, newList);
+ langCode = &newList[k + 1];
+ langCodeLen = strlen (langCode);
+ strcat (buffer, "lang2table");
+ l2t = fopen (buffer, "r");
+ if (l2t == NULL)
+ return NULL;
+ while ((fgets (buffer, sizeof (buffer) - 2, l2t)))
+ {
+ char *codeInFile;
+ int codeInFileLen;
+ char *tableInFile;
+ for (k = 0; buffer[k] < 32; k++);
+ if (buffer[k] == '#' || buffer[k] < 32)
+ continue;
+ codeInFile = &buffer[k];
+ codeInFileLen = k;
+ while (buffer[k] > 32)
+ k++;
+ codeInFileLen = k - codeInFileLen;
+ codeInFile[codeInFileLen] = 0;
+ if (!
+ (codeInFileLen == langCodeLen
+ && strcasecmp (langCode, codeInFile) == 0))
+ continue;
+ while (buffer[k] < 32)
+ k++;
+ tableInFile = &buffer[k];
+ while (buffer[k] > 32)
+ k++;
+ buffer[k] = 0;
+ strcat (newList, tableInFile);
+ fclose (l2t);
+ fileCount = 0;
+ errorCount = 0;
+ return newList;
+ }
+ fclose (l2t);
+ return NULL;
+}
+
+static void *
+compileTranslationTable (const char *tl)
+{
+/*compile source tables into a table in memory */
+ const char *tableList;
+ int k;
+ char mainTable[MAXSTRING];
+ char subTable[MAXSTRING];
+ int listLength;
+ int currentListPos = 0;
+ errorCount = 0;
+ warningCount = 0;
+ fileCount = 0;
+ table = NULL;
+ characterClasses = NULL;
+ ruleNames = NULL;
+ tableList = doLang2table (tl);
+ if (tableList == NULL)
+ return NULL;
+ if (!opcodeLengths[0])
+ {
+ TranslationTableOpcode opcode;
+ for (opcode = 0; opcode < CTO_None; opcode++)
+ opcodeLengths[opcode] = strlen (opcodeNames[opcode]);
+ }
+ allocateHeader (NULL);
+ /*Compile things that are necesary for the proper operation of
+ liblouis or liblouisxml or liblouisutdml */
+ compileString ("space \\s 0");
+ compileString ("noback sign \\x0000 0");
+ compileString ("space \\x00a0 a unbreakable space");
+ compileString ("space \\x001b 1b escape");
+ compileString ("space \\xffff 123456789abcdef ENDSEGMENT");
+ listLength = strlen (tableList);
+ for (k = currentListPos; k < listLength; k++)
+ if (tableList[k] == ',')
+ break;
+ if (k == listLength)
+ { /* Only one file */
+ strcpy (tablePath, tableList);
+ for (k = strlen (tablePath); k >= 0; k--)
+ if (tablePath[k] == '\\' || tablePath[k] == '/')
+ break;
+ strcpy (mainTable, &tablePath[k + 1]);
+ tablePath[++k] = 0;
+ if (!compileFile (mainTable))
+ goto cleanup;
+ }
+ else
+ { /* Compile a list of files */
+ currentListPos = k + 1;
+ strncpy (tablePath, tableList, k);
+ tablePath[k] = 0;
+ for (k = strlen (tablePath); k >= 0; k--)
+ if (tablePath[k] == '\\' || tablePath[k] == '/')
+ break;
+ strcpy (mainTable, &tablePath[k + 1]);
+ tablePath[++k] = 0;
+ if (!compileFile (mainTable))
+ goto cleanup;
+ while (currentListPos < listLength)
+ {
+ for (k = currentListPos; k < listLength; k++)
+ if (tableList[k] == ',')
+ break;
+ strncpy (subTable, &tableList[currentListPos], k - currentListPos);
+ subTable[k - currentListPos] = 0;
+ if (!compileFile (subTable))
+ goto cleanup;
+ currentListPos = k + 1;
+ }
+ }
+/*Clean up after compiling files*/
+cleanup:
+ if (characterClasses)
+ deallocateCharacterClasses ();
+ if (ruleNames)
+ deallocateRuleNames ();
+ if (warningCount)
+ lou_logPrint ("%d warnings issued", warningCount);
+ if (!errorCount)
+ {
+ setDefaults ();
+ table->tableSize = tableSize;
+ table->bytesUsed = tableUsed;
+ }
+ else
+ {
+ if (!(errorCount == 1 && fileCount == 1))
+ lou_logPrint ("%d errors found.", errorCount);
+ if (table)
+ free (table);
+ table = NULL;
+ }
+ return (void *) table;
+}
+
+typedef struct
+{
+ void *next;
+ void *table;
+ int tableListLength;
+ char tableList[1];
+} ChainEntry;
+static ChainEntry *tableChain = NULL;
+static ChainEntry *lastTrans = NULL;
+static void *
+getTable (const char *tableList)
+{
+/*Keep track of which tables have already been compiled */
+ int tableListLen;
+ ChainEntry *currentEntry = NULL;
+ ChainEntry *lastEntry = NULL;
+ void *newTable;
+ if (tableList == NULL || *tableList == 0)
+ return NULL;
+ errorCount = fileCount = 0;
+ tableListLen = strlen (tableList);
+ /*See if this is the last table used. */
+ if (lastTrans != NULL)
+ if (tableListLen == lastTrans->tableListLength && (memcmp
+ (&lastTrans->
+ tableList
+ [0],
+ tableList,
+ tableListLen)) == 0)
+ return (table = lastTrans->table);
+/*See if Table has already been compiled*/
+ currentEntry = tableChain;
+ while (currentEntry != NULL)
+ {
+ if (tableListLen == currentEntry->tableListLength && (memcmp
+ (&currentEntry->
+ tableList
+ [0],
+ tableList,
+ tableListLen))
+ == 0)
+ {
+ lastTrans = currentEntry;
+ return (table = currentEntry->table);
+ }
+ lastEntry = currentEntry;
+ currentEntry = currentEntry->next;
+ }
+ if ((newTable = compileTranslationTable (tableList)))
+ {
+ /*Add a new entry to the table chain. */
+ int entrySize = sizeof (ChainEntry) + tableListLen;
+ ChainEntry *newEntry = malloc (entrySize);
+ if (tableChain == NULL)
+ tableChain = newEntry;
+ else
+ lastEntry->next = newEntry;
+ newEntry->next = NULL;
+ newEntry->table = newTable;
+ newEntry->tableListLength = tableListLen;
+ memcpy (&newEntry->tableList[0], tableList, tableListLen);
+ lastTrans = newEntry;
+ return newEntry->table;
+ }
+ return NULL;
+}
+
+char *
+getLastTableList ()
+{
+ if (lastTrans == NULL)
+ return NULL;
+ strncpy (scratchBuf, lastTrans->tableList, lastTrans->tableListLength);
+ scratchBuf[lastTrans->tableListLength] = 0;
+ return scratchBuf;
+}
+
+void *EXPORT_CALL
+lou_getTable (const char *tableList)
+{
+/* Search paths for tables and keep track of compiled tables. */
+ void *table = NULL;
+ char *pathList;
+ char pathEnd[2];
+ char trialPath[MAXSTRING];
+ if (tableList == NULL || tableList[0] == 0)
+ return NULL;
+ errorCount = fileCount = 0;
+ pathEnd[0] = DIR_SEP;
+ pathEnd[1] = 0;
+ /* See if table is on environment path LOUIS_TABLEPATH */
+ pathList = getenv ("LOUIS_TABLEPATH");
+ if (pathList)
+ while (1)
+ {
+ int k;
+ int listLength;
+ int currentListPos = 0;
+ listLength = strlen (pathList);
+ for (k = 0; k < listLength; k++)
+ if (pathList[k] == ',')
+ break;
+ if (k == listLength || k == 0)
+ { /* Only one file */
+ strcpy (trialPath, pathList);
+ strcat (trialPath, pathEnd);
+ strcat (trialPath, tableList);
+ table = getTable (trialPath);
+ if (table)
+ break;
+ }
+ else
+ { /* Compile a list of files */
+ strncpy (trialPath, pathList, k);
+ trialPath[k] = 0;
+ strcat (trialPath, pathEnd);
+ strcat (trialPath, tableList);
+ currentListPos = k + 1;
+ table = getTable (trialPath);
+ if (table)
+ break;
+ while (currentListPos < listLength)
+ {
+ for (k = currentListPos; k < listLength; k++)
+ if (pathList[k] == ',')
+ break;
+ strncpy (trialPath,
+ &pathList[currentListPos], k - currentListPos);
+ trialPath[k - currentListPos] = 0;
+ strcat (trialPath, pathEnd);
+ strcat (trialPath, tableList);
+ table = getTable (trialPath);
+ currentListPos = k + 1;
+ if (table)
+ break;
+ }
+ }
+ break;
+ }
+ if (!table)
+ {
+ /* See if table in current directory or on a path in
+ * the table name*/
+ if (errorCount > 0 && (!(errorCount == 1 && fileCount == 1)))
+ return NULL;
+ table = getTable (tableList);
+ }
+ if (!table)
+ {
+/* See if table on dataPath. */
+ if (errorCount > 0 && (!(errorCount == 1 && fileCount == 1)))
+ return NULL;
+ pathList = lou_getDataPath ();
+ if (pathList)
+ {
+ strcpy (trialPath, pathList);
+ strcat (trialPath, pathEnd);
+#ifdef _WIN32
+ strcat (trialPath, "liblouis\\tables\\");
+#else
+ strcat (trialPath, "liblouis/tables/");
+#endif
+ strcat (trialPath, tableList);
+ table = getTable (trialPath);
+ }
+ }
+ if (!table)
+ {
+ /* See if table on installed or program path. */
+ if (errorCount > 0 && (!(errorCount == 1 && fileCount == 1)))
+ return NULL;
+#ifdef _WIN32
+ strcpy (trialPath, lou_getProgramPath ());
+ strcat (trialPath, "\\share\\liblouss\\tables\\");
+#else
+ strcpy (trialPath, TABLESDIR);
+ strcat (trialPath, pathEnd);
+#endif
+ strcat (trialPath, tableList);
+ table = getTable (trialPath);
+ }
+ if (!table)
+ lou_logPrint ("%s could not be found", tableList);
+ return table;
+}
+
+static unsigned char *destSpacing = NULL;
+static int sizeDestSpacing = 0;
+static unsigned short *typebuf = NULL;
+static int sizeTypebuf = 0;
+static widechar *passbuf1 = NULL;
+static int sizePassbuf1 = 0;
+static widechar *passbuf2 = NULL;
+static int sizePassbuf2 = 0;
+static int *srcMapping = NULL;
+static int *prevSrcMapping = NULL;
+static int sizeSrcMapping = 0;
+static int sizePrevSrcMapping = 0;
+void *
+liblouis_allocMem (AllocBuf buffer, int srcmax, int destmax)
+{
+ if (srcmax < 1024)
+ srcmax = 1024;
+ if (destmax < 1024)
+ destmax = 1024;
+ switch (buffer)
+ {
+ case alloc_typebuf:
+ if (destmax > sizeTypebuf)
+ {
+ if (typebuf != NULL)
+ free (typebuf);
+ typebuf = malloc ((destmax + 4) * sizeof (unsigned short));
+ sizeTypebuf = destmax;
+ }
+ return typebuf;
+ case alloc_destSpacing:
+ if (destmax > sizeDestSpacing)
+ {
+ if (destSpacing != NULL)
+ free (destSpacing);
+ destSpacing = malloc (destmax + 4);
+ sizeDestSpacing = destmax;
+ }
+ return destSpacing;
+ case alloc_passbuf1:
+ if (destmax > sizePassbuf1)
+ {
+ if (passbuf1 != NULL)
+ free (passbuf1);
+ passbuf1 = malloc ((destmax + 4) * CHARSIZE);
+ sizePassbuf1 = destmax;
+ }
+ return passbuf1;
+ case alloc_passbuf2:
+ if (destmax > sizePassbuf2)
+ {
+ if (passbuf2 != NULL)
+ free (passbuf2);
+ passbuf2 = malloc ((destmax + 4) * CHARSIZE);
+ sizePassbuf2 = destmax;
+ }
+ return passbuf2;
+ case alloc_srcMapping:
+ {
+ int mapSize;
+ if (srcmax >= destmax)
+ mapSize = srcmax;
+ else
+ mapSize = destmax;
+ if (mapSize > sizeSrcMapping)
+ {
+ if (srcMapping != NULL)
+ free (srcMapping);
+ srcMapping = malloc ((mapSize + 4) * sizeof (int));
+ sizeSrcMapping = mapSize;
+ }
+ }
+ return srcMapping;
+ case alloc_prevSrcMapping:
+ {
+ int mapSize;
+ if (srcmax >= destmax)
+ mapSize = srcmax;
+ else
+ mapSize = destmax;
+ if (mapSize > sizePrevSrcMapping)
+ {
+ if (prevSrcMapping != NULL)
+ free (prevSrcMapping);
+ prevSrcMapping = malloc ((mapSize + 4) * sizeof (int));
+ sizePrevSrcMapping = mapSize;
+ }
+ }
+ return prevSrcMapping;
+ default:
+ return NULL;
+ }
+}
+
+void EXPORT_CALL
+lou_free (void)
+{
+ ChainEntry *currentEntry;
+ ChainEntry *previousEntry;
+ if (logFile != NULL)
+ fclose (logFile);
+ if (tableChain != NULL)
+ {
+ currentEntry = tableChain;
+ while (currentEntry)
+ {
+ free (currentEntry->table);
+ previousEntry = currentEntry;
+ currentEntry = currentEntry->next;
+ free (previousEntry);
+ }
+ tableChain = NULL;
+ lastTrans = NULL;
+ }
+ if (typebuf != NULL)
+ free (typebuf);
+ typebuf = NULL;
+ sizeTypebuf = 0;
+ if (destSpacing != NULL)
+ free (destSpacing);
+ destSpacing = NULL;
+ sizeDestSpacing = 0;
+ if (passbuf1 != NULL)
+ free (passbuf1);
+ passbuf1 = NULL;
+ sizePassbuf1 = 0;
+ if (passbuf2 != NULL)
+ free (passbuf2);
+ passbuf2 = NULL;
+ sizePassbuf2 = 0;
+ if (srcMapping != NULL)
+ free (srcMapping);
+ srcMapping = NULL;
+ sizeSrcMapping = 0;
+ if (prevSrcMapping != NULL)
+ free (prevSrcMapping);
+ prevSrcMapping = NULL;
+ sizePrevSrcMapping = 0;
+ opcodeLengths[0] = 0;
+}
+
+char *EXPORT_CALL
+lou_version ()
+{
+ static char *version = PACKAGE_VERSION;
+ return version;
+}
+
+int EXPORT_CALL
+lou_charSize (void)
+{
+ return CHARSIZE;
+}
+
+int EXPORT_CALL
+lou_compileString (const char *tableList, const char *inString)
+{
+ if (!lou_getTable (tableList))
+ return 0;
+ return compileString (inString);
+}
+
+/**
+ * This procedure provides a target for cals that serve as breakpoints
+ * for gdb.
+ */
+/*
+char *EXPORT_CALL
+lou_getTablePaths ()
+{
+ static char paths[MAXSTRING];
+ char *pathList;
+ strcpy (paths, tablePath);
+ strcat (paths, ",");
+ pathList = getenv ("LOUIS_TABLEPATH");
+ if (pathList)
+ {
+ strcat (paths, pathList);
+ strcat (paths, ",");
+ }
+ pathList = getcwd (scratchBuf, MAXSTRING);
+ if (pathList)
+ {
+ strcat (paths, pathList);
+ strcat (paths, ",");
+ }
+ pathList = lou_getDataPath ();
+ if (pathList)
+ {
+ strcat (paths, pathList);
+ strcat (paths, ",");
+ }
+#ifdef _WIN32
+ strcpy (paths, lou_getProgramPath ());
+ strcat (paths, "\\share\\liblouss\\tables\\");
+#else
+ strcpy (paths, TABLESDIR);
+#endif
+ return paths;
+}
+*/
+
+void debugHook ()
+{
+ char *hook = "debug hook";
+ printf ("%s\n", hook);
+}

Powered by Google App Engine
This is Rietveld 408576698