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 = ¤tRule->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 = ¤tRule->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 = ¤tRule->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 = ¤tRule->dotsnext; |
+ } |
+ newRule->dotsnext = *currentOffsetPtr; |
+ *currentOffsetPtr = newRuleOffset; |
+} |
+ |
+static void |
+makeRuleChain (TranslationTableOffset * offsetPtr) |
+{ |
+ TranslationTableRule *currentRule; |
+ while (*offsetPtr) |
+ { |
+ currentRule = (TranslationTableRule *) & table->ruleArea[*offsetPtr]; |
+ offsetPtr = ¤tRule->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 |
+ (¤tEntry-> |
+ 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); |
+} |