| 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);
|
| +}
|
|
|