| Index: trunk/src/third_party/liblouis/overrides/liblouis/compileTranslationTable.c
|
| ===================================================================
|
| --- trunk/src/third_party/liblouis/overrides/liblouis/compileTranslationTable.c (revision 237669)
|
| +++ trunk/src/third_party/liblouis/overrides/liblouis/compileTranslationTable.c (working copy)
|
| @@ -1,5219 +0,0 @@
|
| -/* 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;
|
| - 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);
|
| -}
|
|
|