blob: 7cbf3bdb72477e80061eb4b0ded7182a4924e535 [file] [log] [blame]
/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "louis.h"
#include "transcommon.ci"
static int translateString (void);
static int compbrlStart = 0;
static int compbrlEnd = 0;
int EXPORT_CALL
lou_translateString (const char *tableList, const widechar
* inbufx,
int *inlen, widechar * outbuf, int *outlen, char
*typeform, char *spacing, int mode)
{
return
lou_translate (tableList, inbufx, inlen, outbuf, outlen, typeform,
spacing, NULL, NULL, NULL, mode);
}
int EXPORT_CALL
lou_translate (const char *tableList, const widechar
* inbufx,
int *inlen, widechar * outbuf, int *outlen,
char *typeform, char *spacing, int *outputPos,
int *inputPos, int *cursorPos, int modex)
{
return trace_translate (tableList, inbufx, inlen, outbuf, outlen,
typeform, spacing, outputPos, inputPos, cursorPos,
NULL, NULL, modex);
}
int
trace_translate (const char *tableList, const widechar * inbufx,
int *inlen, widechar * outbuf, int *outlen,
char *typeform, char *spacing, int *outputPos,
int *inputPos, int *cursorPos,
const TranslationTableRule ** rules, int *rulesLen, int modex)
{
int k;
int goodTrans = 1;
if (tableList == NULL || inbufx == NULL || inlen == NULL || outbuf ==
NULL || outlen == NULL)
return 0;
if ((modex & otherTrans))
return other_translate (tableList, inbufx,
inlen, outbuf, outlen,
typeform, spacing, outputPos, inputPos, cursorPos,
modex);
table = lou_getTable (tableList);
if (table == NULL || *inlen < 0 || *outlen < 0)
return 0;
currentInput = (widechar *) inbufx;
srcmax = 0;
while (srcmax < *inlen && currentInput[srcmax])
srcmax++;
destmax = *outlen;
haveEmphasis = 0;
if (!(typebuf = liblouis_allocMem (alloc_typebuf, srcmax, destmax)))
return 0;
if (typeform != NULL)
{
for (k = 0; k < srcmax; k++)
if ((typebuf[k] = typeform[k] & EMPHASIS))
haveEmphasis = 1;
}
else
memset (typebuf, 0, srcmax * sizeof (unsigned short));
if (!(spacing == NULL || *spacing == 'X'))
srcSpacing = (unsigned char *) spacing;
outputPositions = outputPos;
if (outputPos != NULL)
for (k = 0; k < srcmax; k++)
outputPos[k] = -1;
inputPositions = inputPos;
mode = modex;
if (cursorPos != NULL && *cursorPos >= 0)
{
cursorStatus = 0;
cursorPosition = *cursorPos;
if ((mode & (compbrlAtCursor | compbrlLeftCursor)))
{
compbrlStart = cursorPosition;
if (checkAttr (currentInput[compbrlStart], CTC_Space, 0))
compbrlEnd = compbrlStart + 1;
else
{
while (compbrlStart >= 0 && !checkAttr
(currentInput[compbrlStart], CTC_Space, 0))
compbrlStart--;
compbrlStart++;
compbrlEnd = cursorPosition;
if (!(mode & compbrlLeftCursor))
while (compbrlEnd < srcmax && !checkAttr
(currentInput[compbrlEnd], CTC_Space, 0))
compbrlEnd++;
}
}
}
else
{
cursorPosition = -1;
cursorStatus = 1; /*so it won't check cursor position */
}
if (!(passbuf1 = liblouis_allocMem (alloc_passbuf1, srcmax, destmax)))
return 0;
if (!(srcMapping = liblouis_allocMem (alloc_srcMapping, srcmax, destmax)))
return 0;
if (!
(prevSrcMapping =
liblouis_allocMem (alloc_prevSrcMapping, srcmax, destmax)))
return 0;
for (k = 0; k <= srcmax; k++)
srcMapping[k] = k;
srcMapping[srcmax] = srcmax;
if ((!(mode & pass1Only)) && (table->numPasses > 1 || table->corrections))
{
if (!(passbuf2 = liblouis_allocMem (alloc_passbuf2, srcmax, destmax)))
return 0;
}
if (srcSpacing != NULL)
{
if (!(destSpacing = liblouis_allocMem (alloc_destSpacing, srcmax,
destmax)))
goodTrans = 0;
else
memset (destSpacing, '*', destmax);
}
appliedRulesCount = 0;
if (rules != NULL && rulesLen != NULL)
{
appliedRules = rules;
maxAppliedRules = *rulesLen;
}
else
{
appliedRules = NULL;
maxAppliedRules = 0;
}
currentPass = 0;
if ((mode & pass1Only))
{
currentOutput = passbuf1;
memcpy (prevSrcMapping, srcMapping, destmax * sizeof (int));
goodTrans = translateString ();
currentPass = 5; /*Certainly > table->numPasses */
}
while (currentPass <= table->numPasses && goodTrans)
{
memcpy (prevSrcMapping, srcMapping, destmax * sizeof (int));
switch (currentPass)
{
case 0:
if (table->corrections)
{
currentOutput = passbuf2;
goodTrans = makeCorrections ();
currentInput = passbuf2;
srcmax = dest;
}
break;
case 1:
currentOutput = passbuf1;
goodTrans = translateString ();
break;
case 2:
srcmax = dest;
currentInput = passbuf1;
currentOutput = passbuf2;
goodTrans = translatePass ();
break;
case 3:
srcmax = dest;
currentInput = passbuf2;
currentOutput = passbuf1;
goodTrans = translatePass ();
break;
case 4:
srcmax = dest;
currentInput = passbuf1;
currentOutput = passbuf2;
goodTrans = translatePass ();
break;
default:
break;
}
currentPass++;
}
if (goodTrans)
{
for (k = 0; k < dest; k++)
{
if (typeform != NULL)
{
if ((currentOutput[k] & (B7 | B8)))
typeform[k] = '8';
else
typeform[k] = '0';
}
if ((mode & dotsIO))
{
if ((mode & ucBrl))
outbuf[k] = ((currentOutput[k] & 0xff) | 0x2800);
else
outbuf[k] = currentOutput[k];
}
else
outbuf[k] = getCharFromDots (currentOutput[k]);
}
*inlen = realInlen;
*outlen = dest;
if (inputPositions != NULL)
memcpy (inputPositions, srcMapping, destmax * sizeof (int));
if (outputPos != NULL)
{
int lastpos = 0;
for (k = 0; k < *inlen; k++)
if (outputPos[k] == -1)
outputPos[k] = lastpos;
else
lastpos = outputPos[k];
}
}
if (destSpacing != NULL)
{
memcpy (srcSpacing, destSpacing, srcmax);
srcSpacing[srcmax] = 0;
}
if (cursorPos != NULL)
*cursorPos = cursorPosition;
if (rulesLen != NULL)
*rulesLen = appliedRulesCount;
return goodTrans;
}
int EXPORT_CALL
lou_translatePrehyphenated (const char *tableList,
const widechar * inbufx, int *inlen,
widechar * outbuf, int *outlen,
char *typeform, char *spacing,
int *outputPos, int *inputPos, int *cursorPos,
char *inputHyphens, char *outputHyphens,
int modex)
{
int rv = 1;
int *alloc_inputPos = NULL;
if (inputHyphens != NULL)
{
if (outputHyphens == NULL)
return 0;
if (inputPos == NULL)
{
alloc_inputPos = malloc (*outlen * sizeof (int));
inputPos = alloc_inputPos;
}
}
if (lou_translate (tableList, inbufx, inlen, outbuf, outlen, typeform,
spacing, outputPos, inputPos, cursorPos, modex))
{
if (inputHyphens != NULL)
{
int inpos = 0;
int outpos;
for (outpos = 0; outpos < *outlen; outpos++)
{
int new_inpos = inputPos[outpos];
if (new_inpos < inpos)
{
rv = 0;
break;
}
if (new_inpos > inpos)
outputHyphens[outpos] = inputHyphens[new_inpos];
else
outputHyphens[outpos] = '0';
inpos = new_inpos;
}
}
}
if (alloc_inputPos != NULL)
free (alloc_inputPos);
return rv;
}
static TranslationTableOpcode indicOpcode;
static const TranslationTableRule *indicRule;
static int dontContract = 0;
static int doCompbrl (void);
static int
hyphenate (const widechar * word, int wordSize, char *hyphens)
{
widechar prepWord[MAXSTRING];
int i, j, k;
int stateNum;
widechar ch;
HyphenationState *statesArray = (HyphenationState *)
& table->ruleArea[table->hyphenStatesArray];
HyphenationState *currentState;
HyphenationTrans *transitionsArray;
char *hyphenPattern;
int patternOffset;
if (!table->hyphenStatesArray || (wordSize + 3) > MAXSTRING)
return 0;
j = 0;
prepWord[j++] = '.';
for (i = 0; i < wordSize; i++)
prepWord[j++] = (findCharOrDots (word[i], 0))->lowercase;
prepWord[j++] = '.';
prepWord[j] = 0;
for (i = 0; i < wordSize; i++)
hyphens[i] = '0';
/* now, run the finite state machine */
stateNum = 0;
for (i = 0; i < j; i++)
{
ch = prepWord[i];
while (1)
{
if (stateNum == 0xffff)
{
stateNum = 0;
goto nextLetter;
}
currentState = &statesArray[stateNum];
if (currentState->trans.offset)
{
transitionsArray = (HyphenationTrans *) &
table->ruleArea[currentState->trans.offset];
for (k = 0; k < currentState->numTrans; k++)
if (transitionsArray[k].ch == ch)
{
stateNum = transitionsArray[k].newState;
goto stateFound;
}
}
stateNum = currentState->fallbackState;
}
stateFound:
currentState = &statesArray[stateNum];
if (currentState->hyphenPattern)
{
hyphenPattern =
(char *) &table->ruleArea[currentState->hyphenPattern];
patternOffset = i + 1 - strlen (hyphenPattern);
for (k = 0; hyphenPattern[k]; k++)
if (hyphens[patternOffset + k] < hyphenPattern[k])
hyphens[patternOffset + k] = hyphenPattern[k];
}
nextLetter:;
}
hyphens[wordSize] = 0;
return 1;
}
static int destword;
static int srcword;
static int doCompTrans (int start, int end);
static int
for_updatePositions (const widechar * outChars, int inLength, int outLength)
{
int k;
if ((dest + outLength) > destmax || (src + inLength) > srcmax)
return 0;
memcpy (&currentOutput[dest], outChars, outLength * CHARSIZE);
if (!cursorStatus)
{
if ((mode & (compbrlAtCursor | compbrlLeftCursor)))
{
if (src >= compbrlStart)
{
cursorStatus = 2;
return (doCompTrans (compbrlStart, compbrlEnd));
}
}
else if (cursorPosition >= src && cursorPosition < (src + inLength))
{
cursorPosition = dest;
cursorStatus = 1;
}
else if (currentInput[cursorPosition] == 0 &&
cursorPosition == (src + inLength))
{
cursorPosition = dest + outLength / 2 + 1;
cursorStatus = 1;
}
}
else if (cursorStatus == 2 && cursorPosition == src)
cursorPosition = dest;
if (inputPositions != NULL || outputPositions != NULL)
{
if (outLength <= inLength)
{
for (k = 0; k < outLength; k++)
{
if (inputPositions != NULL)
srcMapping[dest + k] = prevSrcMapping[src];
if (outputPositions != NULL)
outputPositions[prevSrcMapping[src + k]] = dest;
}
for (k = outLength; k < inLength; k++)
if (outputPositions != NULL)
outputPositions[prevSrcMapping[src + k]] = dest;
}
else
{
for (k = 0; k < inLength; k++)
{
if (inputPositions != NULL)
srcMapping[dest + k] = prevSrcMapping[src];
if (outputPositions != NULL)
outputPositions[prevSrcMapping[src + k]] = dest;
}
for (k = inLength; k < outLength; k++)
if (inputPositions != NULL)
srcMapping[dest + k] = prevSrcMapping[src];
}
}
dest += outLength;
return 1;
}
static int
syllableBreak (void)
{
int wordStart;
int wordEnd;
int k;
char hyphens[MAXSTRING];
for (wordStart = src; wordStart >= 0; wordStart--)
if (!((findCharOrDots (currentInput[wordStart], 0))->attributes &
CTC_Letter))
{
wordStart++;
break;
}
if (wordStart < 0)
wordStart = 0;
for (wordEnd = src; wordEnd < srcmax; wordEnd++)
if (!((findCharOrDots (currentInput[wordEnd], 0))->attributes &
CTC_Letter))
{
wordEnd--;
break;
}
if (!hyphenate (&currentInput[wordStart], wordEnd - wordStart, hyphens))
return 0;
/* If the number at the beginning of the syllable is odd or all
* numbers are even there is no syllable break. Otherwise there is.*/
k = src - wordStart;
if (hyphens[k] & 1)
return 0;
k++;
for (; k < (src - wordStart + transCharslen); k++)
if (hyphens[k] & 1)
return 1;
return 0;
}
static TranslationTableCharacter *curCharDef;
static widechar before, after;
static TranslationTableCharacterAttributes beforeAttributes;
static TranslationTableCharacterAttributes afterAttributes;
static void
setBefore (void)
{
if (src >= 2 && currentInput[src - 1] == ENDSEGMENT)
before = currentInput[src - 2];
else
before = (src == 0) ? ' ' : currentInput[src - 1];
beforeAttributes = (findCharOrDots (before, 0))->attributes;
}
static void
setAfter (int length)
{
if ((src + length + 2) < srcmax && currentInput[src + 1] == ENDSEGMENT)
after = currentInput[src + 2];
else
after = (src + length < srcmax) ? currentInput[src + length] : ' ';
afterAttributes = (findCharOrDots (after, 0))->attributes;
}
static int prevTypeform = plain_text;
static int prevSrc = 0;
static TranslationTableRule pseudoRule = {
0
};
static int
brailleIndicatorDefined (TranslationTableOffset offset)
{
if (!offset)
return 0;
indicRule = (TranslationTableRule *) & table->ruleArea[offset];
indicOpcode = indicRule->opcode;
return 1;
}
static typeforms prevType = plain_text;
static typeforms curType = plain_text;
typedef enum
{
firstWord,
lastWordBefore,
lastWordAfter,
firstLetter,
lastLetter,
singleLetter,
word,
lenPhrase
} emphCodes;
static int wordsMarked = 0;
static int finishEmphasis = 0;
static int wordCount = 0;
static int lastWord = 0;
static int startType = -1;
static int endType = 0;
static void
markWords (const TranslationTableOffset * offset)
{
/*Mark the beginnings of words*/
int numWords = 0;
int k;
wordsMarked = 1;
numWords = offset[lenPhrase];
if (!numWords)
numWords = 4;
if (wordCount < numWords)
{
for (k = src; k < endType; k++)
if (!checkAttr (currentInput[k - 1], CTC_Letter | CTC_Digit, 0) &&
checkAttr (currentInput[k], CTC_Digit | CTC_Letter, 0))
typebuf[k] |= STARTWORD;
}
else
{
int firstWord = 1;
int lastWord = src;
for (k = src; k < endType; k++)
{
if (!checkAttr (currentInput[k - 1], CTC_Letter | CTC_Digit, 0)
&& checkAttr (currentInput[k], CTC_Digit | CTC_Letter, 0))
{
if (firstWord)
{
typebuf[k] |= FIRSTWORD;
firstWord = 0;
}
else
lastWord = k;
}
}
typebuf[lastWord] |= STARTWORD;
}
}
static int
insertIndicators (void)
{
/*Insert italic, bold, etc. indicators before words*/
int typeMark;
int ruleFound = 0;
if (!wordsMarked || !haveEmphasis)
return 1;
typeMark = typebuf[src] & (STARTWORD | FIRSTWORD);
if (!typeMark)
return 1;
switch (typebuf[src] & EMPHASIS)
{
case italic:
if ((typeMark & FIRSTWORD))
ruleFound = brailleIndicatorDefined (table->firstWordItal);
else
ruleFound = brailleIndicatorDefined (table->lastWordItalBefore);
break;
case bold:
if ((typeMark & FIRSTWORD))
ruleFound = brailleIndicatorDefined (table->firstWordBold);
else
ruleFound = brailleIndicatorDefined (table->lastWordBoldBefore);
break;
case underline:
if ((typeMark & FIRSTWORD))
ruleFound = brailleIndicatorDefined (table->firstWordUnder);
else
ruleFound = brailleIndicatorDefined (table->lastWordUnderBefore);
break;
default:
ruleFound = 0;
break;
}
if (ruleFound)
{
if (!for_updatePositions
(&indicRule->charsdots[0], 0, indicRule->dotslen))
return 0;
}
return 1;
}
static int
validMatch ()
{
/*Analyze the typeform parameter and also check for capitalization*/
TranslationTableCharacter *currentInputChar;
TranslationTableCharacter *ruleChar;
TranslationTableCharacterAttributes prevAttr = 0;
int k;
int kk = 0;
unsigned short mask = 0;
if (!transCharslen)
return 0;
switch (transOpcode)
{
case CTO_WholeWord:
case CTO_PrefixableWord:
case CTO_SuffixableWord:
case CTO_JoinableWord:
case CTO_LowWord:
mask = EMPHASIS | capsemph;
break;
default:
mask = EMPHASIS | SYLLABLEMARKS | INTERNALMARKS | capsemph;
break;
}
for (k = src; k < src + transCharslen; k++)
{
if (currentInput[k] == ENDSEGMENT)
{
if (k == src && transCharslen == 1)
return 1;
else
return 0;
}
currentInputChar = findCharOrDots (currentInput[k], 0);
if (k == src)
prevAttr = currentInputChar->attributes;
ruleChar = findCharOrDots (transRule->charsdots[kk++], 0);
if ((currentInputChar->lowercase != ruleChar->lowercase))
return 0;
if (typebuf != NULL && (typebuf[src] & capsemph) == 0 &&
(typebuf[k] & mask) != (typebuf[src] & mask))
return 0;
if (currentInputChar->attributes != CTC_Letter)
{
if (k != (src + 1) && (prevAttr &
CTC_Letter)
&& (currentInputChar->attributes & CTC_Letter)
&&
((currentInputChar->
attributes & (CTC_LowerCase | CTC_UpperCase |
CTC_Letter)) !=
(prevAttr & (CTC_LowerCase | CTC_UpperCase | CTC_Letter))))
return 0;
}
prevAttr = currentInputChar->attributes;
}
return 1;
}
static int
checkMultCaps (void)
{
int k;
for (k = 0; k < table->lenBeginCaps; k++)
if (k >= srcmax - src ||
!checkAttr (currentInput[src + k], CTC_UpperCase, 0))
return 0;
return 1;
}
static int prevPrevType = 0;
static int nextType = 0;
static TranslationTableCharacterAttributes prevPrevAttr = 0;
static int
beginEmphasis (const TranslationTableOffset * offset)
{
if (src != startType)
{
wordCount = finishEmphasis = wordsMarked = 0;
startType = lastWord = src;
for (endType = src; endType < srcmax; endType++)
{
if ((typebuf[endType] & EMPHASIS) != curType)
break;
if (checkAttr (currentInput[endType - 1], CTC_Space, 0)
&& !checkAttr (currentInput[endType], CTC_Space, 0))
{
lastWord = endType;
wordCount++;
}
}
}
if ((beforeAttributes & CTC_Letter) && (endType - startType) ==
1 && brailleIndicatorDefined (offset[singleLetter]))
return 1;
else
if ((beforeAttributes & CTC_Letter) && brailleIndicatorDefined
(offset[firstLetter]))
return 1;
else if (brailleIndicatorDefined (offset[lastWordBefore]))
{
markWords (offset);
return 0;
}
else
return (brailleIndicatorDefined (offset[firstWord]));
return 0;
}
static int
endEmphasis (const TranslationTableOffset * offset)
{
if (wordsMarked)
return 0;
if (prevPrevType != prevType && nextType != prevType &&
brailleIndicatorDefined (offset[singleLetter]))
return 0;
else
if ((finishEmphasis || (src < srcmax && ((findCharOrDots
(currentInput[src + 1],
0))->attributes &
CTC_Letter)))
&& brailleIndicatorDefined (offset[lastLetter]))
return 1;
else
return (brailleIndicatorDefined (offset[lastWordAfter]));
return 0;
}
static int
doCompEmph (void)
{
int endEmph;
for (endEmph = src; (typebuf[endEmph] & computer_braille) && endEmph
<= srcmax; endEmph++);
return doCompTrans (src, endEmph);
}
static int
insertBrailleIndicators (int finish)
{
/*Insert braille indicators such as italic, bold, capital,
* letter, number, etc.*/
typedef enum
{
checkNothing,
checkBeginTypeform,
checkEndTypeform,
checkNumber,
checkLetter,
checkBeginMultCaps,
checkEndMultCaps,
checkSingleCap,
checkAll
} checkThis;
checkThis checkWhat = checkNothing;
int ok = 0;
int k;
if (finish == 2)
{
while (dest > 0 && (currentOutput[dest - 1] == 0 ||
currentOutput[dest - 1] == B16))
dest--;
finishEmphasis = 1;
prevType = prevPrevType;
curType = plain_text;
checkWhat = checkEndTypeform;
}
else
{
if (src == prevSrc && !finish)
return 1;
if (src != prevSrc)
{
if (haveEmphasis && src < srcmax)
nextType = typebuf[src + 1] & EMPHASIS;
else
nextType = plain_text;
if (src > 2)
{
if (haveEmphasis)
prevPrevType = typebuf[src - 2] & EMPHASIS;
else
prevPrevType = plain_text;
prevPrevAttr =
(findCharOrDots (currentInput[src - 2], 0))->attributes;
}
else
{
prevPrevType = plain_text;
prevPrevAttr = CTC_Space;
}
if (haveEmphasis && (typebuf[src] & EMPHASIS) != prevTypeform)
{
prevType = prevTypeform & EMPHASIS;
curType = typebuf[src] & EMPHASIS;
checkWhat = checkEndTypeform;
}
else if (!finish)
checkWhat = checkNothing;
else
checkWhat = checkNumber;
}
if (finish == 1)
checkWhat = checkNumber;
}
do
{
ok = 0;
switch (checkWhat)
{
case checkNothing:
ok = 0;
break;
case checkBeginTypeform:
if (haveEmphasis)
switch (curType)
{
case plain_text:
ok = 0;
break;
case italic:
ok = beginEmphasis (&table->firstWordItal);
curType = 0;
break;
case bold:
ok = beginEmphasis (&table->firstWordBold);
curType = 0;
break;
case underline:
ok = beginEmphasis (&table->firstWordUnder);
curType = 0;
break;
case computer_braille:
ok = 0;
doCompEmph ();
curType = 0;
break;
case italic + underline:
ok = beginEmphasis (&table->firstWordUnder);
curType -= underline;
break;
case italic + bold:
ok = beginEmphasis (&table->firstWordBold);
curType -= bold;
break;
case italic + computer_braille:
ok = 0;
doCompEmph ();
curType -= computer_braille;
break;
case underline + bold:
beginEmphasis (&table->firstWordBold);
curType -= bold;
break;
case underline + computer_braille:
ok = 0;
doCompEmph ();
curType -= computer_braille;
break;
case bold + computer_braille:
ok = 0;
doCompEmph ();
curType -= computer_braille;
break;
default:
ok = 0;
curType = 0;
break;
}
if (!curType)
{
if (!finish)
checkWhat = checkNothing;
else
checkWhat = checkNumber;
}
break;
case checkEndTypeform:
if (haveEmphasis)
switch (prevType)
{
case plain_text:
ok = 0;
break;
case italic:
ok = endEmphasis (&table->firstWordItal);
prevType = 0;
break;
case bold:
ok = endEmphasis (&table->firstWordBold);
prevType = 0;
break;
case underline:
ok = endEmphasis (&table->firstWordUnder);
prevType = 0;
break;
case computer_braille:
ok = 0;
prevType = 0;
break;
case italic + underline:
ok = endEmphasis (&table->firstWordUnder);
prevType -= underline;
break;
case italic + bold:
ok = endEmphasis (&table->firstWordBold);
prevType -= bold;
break;
case italic + computer_braille:
ok = 1;
prevType -= computer_braille;
break;
case underline + bold:
ok = endEmphasis (&table->firstWordBold);
prevType -= bold;
break;
case underline + computer_braille:
ok = 0;
prevType -= computer_braille;
break;
case bold + computer_braille:
ok = endEmphasis (&table->firstWordBold);
prevType -= bold;
break;
default:
ok = 0;
prevType = 0;
break;
}
if (!prevType)
{
checkWhat = checkBeginTypeform;
prevTypeform = typebuf[src] & EMPHASIS;
}
break;
case checkNumber:
if (brailleIndicatorDefined
(table->numberSign) &&
checkAttr (currentInput[src], CTC_Digit, 0) &&
(prevTransOpcode == CTO_ExactDots
|| !(beforeAttributes & CTC_Digit))
&& prevTransOpcode != CTO_MidNum)
{
ok = 1;
checkWhat = checkNothing;
}
else
checkWhat = checkLetter;
break;
case checkLetter:
if (!brailleIndicatorDefined (table->letterSign))
{
ok = 0;
checkWhat = checkBeginMultCaps;
break;
}
if (transOpcode == CTO_Contraction)
{
ok = 1;
checkWhat = checkBeginMultCaps;
break;
}
if ((checkAttr (currentInput[src], CTC_Letter, 0)
&& !(beforeAttributes & CTC_Letter))
&& (!checkAttr (currentInput[src + 1], CTC_Letter, 0)
|| (beforeAttributes & CTC_Digit)))
{
ok = 1;
if (src > 0)
for (k = 0; k < table->noLetsignBeforeCount; k++)
if (currentInput[src - 1] == table->noLetsignBefore[k])
{
ok = 0;
break;
}
for (k = 0; k < table->noLetsignCount; k++)
if (currentInput[src] == table->noLetsign[k])
{
ok = 0;
break;
}
if ((src + 1) < srcmax)
for (k = 0; k < table->noLetsignAfterCount; k++)
if (currentInput[src + 1] == table->noLetsignAfter[k])
{
ok = 0;
break;
}
}
checkWhat = checkBeginMultCaps;
break;
case checkBeginMultCaps:
if (brailleIndicatorDefined (table->beginCapitalSign) &&
!(beforeAttributes & CTC_UpperCase) && checkMultCaps ())
{
ok = 1;
if (table->capsNoCont)
dontContract = 1;
checkWhat = checkNothing;
}
else
checkWhat = checkSingleCap;
break;
case checkEndMultCaps:
if (brailleIndicatorDefined (table->endCapitalSign) &&
(prevPrevAttr & CTC_UpperCase)
&& (beforeAttributes & CTC_UpperCase)
&& checkAttr (currentInput[src], CTC_LowerCase, 0))
{
ok = 1;
if (table->capsNoCont)
dontContract = 0;
}
checkWhat = checkNothing;
break;
case checkSingleCap:
if (brailleIndicatorDefined (table->capitalSign) && src < srcmax
&& checkAttr (currentInput[src], CTC_UpperCase, 0) &&
(!(beforeAttributes & CTC_UpperCase) ||
table->beginCapitalSign == 0))
{
ok = 1;
checkWhat = checkNothing;
}
checkWhat = checkEndMultCaps;
break;
default:
ok = 0;
checkWhat = checkNothing;
break;
}
if (ok && indicRule != NULL)
{
if (!for_updatePositions
(&indicRule->charsdots[0], 0, indicRule->dotslen))
return 0;
if (cursorStatus == 2)
checkWhat = checkNothing;
}
}
while (checkWhat != checkNothing);
finishEmphasis = 0;
return 1;
}
static int
onlyLettersBehind (void)
{
/* Actually, spaces, then letters */
int k;
if (!(beforeAttributes & CTC_Space))
return 0;
for (k = src - 2; k >= 0; k--)
{
TranslationTableCharacterAttributes attr = (findCharOrDots
(currentInput[k],
0))->attributes;
if ((attr & CTC_Space))
continue;
if ((attr & CTC_Letter))
return 1;
else
return 0;
}
return 1;
}
static int
onlyLettersAhead (void)
{
/* Actullly, spaces, then letters */
int k;
if (!(afterAttributes & CTC_Space))
return 0;
for (k = src + transCharslen + 1; k < srcmax; k++)
{
TranslationTableCharacterAttributes attr = (findCharOrDots
(currentInput[k],
0))->attributes;
if ((attr & CTC_Space))
continue;
if ((attr & (CTC_Letter | CTC_LitDigit)))
return 1;
else
return 0;
}
return 0;
}
static int
noCompbrlAhead (void)
{
int start = src + transCharslen;
int end;
int curSrc;
if (start >= srcmax)
return 1;
while (start < srcmax && checkAttr (currentInput[start], CTC_Space, 0))
start++;
if (start == srcmax || (transOpcode == CTO_JoinableWord && (!checkAttr
(currentInput
[start],
CTC_Letter |
CTC_Digit, 0)
||
!checkAttr
(currentInput
[start - 1],
CTC_Space,
0))))
return 1;
end = start;
while (end < srcmax && !checkAttr (currentInput[end], CTC_Space, 0))
end++;
if ((mode & (compbrlAtCursor | compbrlLeftCursor)) && cursorPosition
>= start && cursorPosition < end)
return 0;
/* Look ahead for rules with CTO_CompBrl */
for (curSrc = start; curSrc < end; curSrc++)
{
int length = srcmax - curSrc;
int tryThis;
const TranslationTableCharacter *character1;
const TranslationTableCharacter *character2;
int k;
character1 = findCharOrDots (currentInput[curSrc], 0);
for (tryThis = 0; tryThis < 2; tryThis++)
{
TranslationTableOffset ruleOffset = 0;
TranslationTableRule *testRule;
unsigned long int makeHash = 0;
switch (tryThis)
{
case 0:
if (!(length >= 2))
break;
/*Hash function optimized for forward translation */
makeHash = (unsigned long int) character1->lowercase << 8;
character2 = findCharOrDots (currentInput[curSrc + 1], 0);
makeHash += (unsigned long int) character2->lowercase;
makeHash %= HASHNUM;
ruleOffset = table->forRules[makeHash];
break;
case 1:
if (!(length >= 1))
break;
length = 1;
ruleOffset = character1->otherRules;
break;
}
while (ruleOffset)
{
testRule =
(TranslationTableRule *) & table->ruleArea[ruleOffset];
for (k = 0; k < testRule->charslen; k++)
{
character1 = findCharOrDots (testRule->charsdots[k], 0);
character2 = findCharOrDots (currentInput[curSrc + k], 0);
if (character1->lowercase != character2->lowercase)
break;
}
if (tryThis == 1 || k == testRule->charslen)
{
if (testRule->opcode == CTO_CompBrl
|| testRule->opcode == CTO_Literal)
return 0;
}
ruleOffset = testRule->charsnext;
}
}
}
return 1;
}
static widechar const *repwordStart;
static int repwordLength;
static int
isRepeatedWord (void)
{
int start;
if (src == 0 || !checkAttr (currentInput[src - 1], CTC_Letter, 0))
return 0;
if ((src + transCharslen) >= srcmax || !checkAttr (currentInput[src +
transCharslen],
CTC_Letter, 0))
return 0;
for (start = src - 2;
start >= 0 && checkAttr (currentInput[start], CTC_Letter, 0); start--);
start++;
repwordStart = &currentInput[start];
repwordLength = src - start;
if (compareChars (repwordStart, &currentInput[src
+ transCharslen],
repwordLength, 0))
return 1;
return 0;
}
static void
for_selectRule (void)
{
/*check for valid Translations. Return value is in transRule. */
int length = srcmax - src;
int tryThis;
const TranslationTableCharacter *character2;
int k;
curCharDef = findCharOrDots (currentInput[src], 0);
for (tryThis = 0; tryThis < 3; tryThis++)
{
TranslationTableOffset ruleOffset = 0;
unsigned long int makeHash = 0;
switch (tryThis)
{
case 0:
if (!(length >= 2))
break;
/*Hash function optimized for forward translation */
makeHash = (unsigned long int) curCharDef->lowercase << 8;
character2 = findCharOrDots (currentInput[src + 1], 0);
makeHash += (unsigned long int) character2->lowercase;
makeHash %= HASHNUM;
ruleOffset = table->forRules[makeHash];
break;
case 1:
if (!(length >= 1))
break;
length = 1;
ruleOffset = curCharDef->otherRules;
break;
case 2: /*No rule found */
transRule = &pseudoRule;
transOpcode = pseudoRule.opcode = CTO_None;
transCharslen = pseudoRule.charslen = 1;
pseudoRule.charsdots[0] = currentInput[src];
pseudoRule.dotslen = 0;
return;
break;
}
while (ruleOffset)
{
transRule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
transOpcode = transRule->opcode;
transCharslen = transRule->charslen;
if (tryThis == 1 || ((transCharslen <= length) && validMatch ()))
{
/* check this rule */
setAfter (transCharslen);
if ((!transRule->after || (beforeAttributes
& transRule->after)) &&
(!transRule->before || (afterAttributes
& transRule->before)))
switch (transOpcode)
{ /*check validity of this Translation */
case CTO_Space:
case CTO_Letter:
case CTO_UpperCase:
case CTO_LowerCase:
case CTO_Digit:
case CTO_LitDigit:
case CTO_Punctuation:
case CTO_Math:
case CTO_Sign:
case CTO_Hyphen:
case CTO_Replace:
case CTO_CompBrl:
case CTO_Literal:
return;
case CTO_Repeated:
if ((mode & (compbrlAtCursor | compbrlLeftCursor))
&& src >= compbrlStart && src <= compbrlEnd)
break;
return;
case CTO_RepWord:
if (dontContract || (mode & noContractions))
break;
if (isRepeatedWord ())
return;
break;
case CTO_NoCont:
if (dontContract || (mode & noContractions))
break;
return;
case CTO_Syllable:
transOpcode = CTO_Always;
case CTO_Always:
if (dontContract || (mode & noContractions))
break;
return;
case CTO_ExactDots:
return;
case CTO_NoCross:
if (syllableBreak ())
break;
return;
case CTO_Context:
if (!srcIncremented || !passDoTest ())
break;
return;
case CTO_LargeSign:
if (dontContract || (mode & noContractions))
break;
if (!((beforeAttributes & (CTC_Space
| CTC_Punctuation))
|| onlyLettersBehind ())
|| !((afterAttributes & CTC_Space)
|| prevTransOpcode == CTO_LargeSign)
|| (afterAttributes & CTC_Letter)
|| !noCompbrlAhead ())
transOpcode = CTO_Always;
return;
case CTO_WholeWord:
if (dontContract || (mode & noContractions))
break;
case CTO_Contraction:
if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
&& (afterAttributes & (CTC_Space | CTC_Punctuation)))
return;
break;
case CTO_PartWord:
if (dontContract || (mode & noContractions))
break;
if ((beforeAttributes & CTC_Letter)
|| (afterAttributes & CTC_Letter))
return;
break;
case CTO_JoinNum:
if (dontContract || (mode & noContractions))
break;
if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
&&
(afterAttributes & CTC_Space) &&
(dest + transRule->dotslen < destmax))
{
int cursrc = src + transCharslen + 1;
while (cursrc < srcmax)
{
if (!checkAttr
(currentInput[cursrc], CTC_Space, 0))
{
if (checkAttr
(currentInput[cursrc], CTC_Digit, 0))
return;
break;
}
cursrc++;
}
}
break;
case CTO_LowWord:
if (dontContract || (mode & noContractions))
break;
if ((beforeAttributes & CTC_Space)
&& (afterAttributes & CTC_Space)
&& (prevTransOpcode != CTO_JoinableWord))
return;
break;
case CTO_JoinableWord:
if (dontContract || (mode & noContractions))
break;
if (beforeAttributes & (CTC_Space | CTC_Punctuation)
&& onlyLettersAhead () && noCompbrlAhead ())
return;
break;
case CTO_SuffixableWord:
if (dontContract || (mode & noContractions))
break;
if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
&& (afterAttributes &
(CTC_Space | CTC_Letter | CTC_Punctuation)))
return;
break;
case CTO_PrefixableWord:
if (dontContract || (mode & noContractions))
break;
if ((beforeAttributes &
(CTC_Space | CTC_Letter | CTC_Punctuation))
&& (afterAttributes & (CTC_Space | CTC_Punctuation)))
return;
break;
case CTO_BegWord:
if (dontContract || (mode & noContractions))
break;
if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
&& (afterAttributes & CTC_Letter))
return;
break;
case CTO_BegMidWord:
if (dontContract || (mode & noContractions))
break;
if ((beforeAttributes &
(CTC_Letter | CTC_Space | CTC_Punctuation))
&& (afterAttributes & CTC_Letter))
return;
break;
case CTO_MidWord:
if (dontContract || (mode & noContractions))
break;
if (beforeAttributes & CTC_Letter
&& afterAttributes & CTC_Letter)
return;
break;
case CTO_MidEndWord:
if (dontContract || (mode & noContractions))
break;
if (beforeAttributes & CTC_Letter
&& afterAttributes & (CTC_Letter | CTC_Space |
CTC_Punctuation))
return;
break;
case CTO_EndWord:
if (dontContract || (mode & noContractions))
break;
if (beforeAttributes & CTC_Letter
&& afterAttributes & (CTC_Space | CTC_Punctuation))
return;
break;
case CTO_BegNum:
if (beforeAttributes & (CTC_Space | CTC_Punctuation)
&& afterAttributes & CTC_Digit)
return;
break;
case CTO_MidNum:
if (prevTransOpcode != CTO_ExactDots
&& beforeAttributes & CTC_Digit
&& afterAttributes & CTC_Digit)
return;
break;
case CTO_EndNum:
if (beforeAttributes & CTC_Digit &&
prevTransOpcode != CTO_ExactDots)
return;
break;
case CTO_DecPoint:
if (!(afterAttributes & CTC_Digit))
break;
if (beforeAttributes & CTC_Digit)
transOpcode = CTO_MidNum;
return;
case CTO_PrePunc:
if (!checkAttr (currentInput[src], CTC_Punctuation, 0)
|| (src > 0
&& checkAttr (currentInput[src - 1], CTC_Letter,
0)))
break;
for (k = src + transCharslen; k < srcmax; k++)
{
if (checkAttr
(currentInput[k], (CTC_Letter | CTC_Digit), 0))
return;
if (checkAttr (currentInput[k], CTC_Space, 0))
break;
}
break;
case CTO_PostPunc:
if (!checkAttr (currentInput[src], CTC_Punctuation, 0)
|| (src < (srcmax - 1)
&& checkAttr (currentInput[src + 1], CTC_Letter,
0)))
break;
for (k = src; k >= 0; k--)
{
if (checkAttr
(currentInput[k], (CTC_Letter | CTC_Digit), 0))
return;
if (checkAttr (currentInput[k], CTC_Space, 0))
break;
}
break;
default:
break;
}
}
/*Done with checking this rule */
ruleOffset = transRule->charsnext;
}
}
}
static int
undefinedCharacter (widechar c)
{
/*Display an undefined character in the output buffer*/
int k;
char *display;
if (table->undefined)
{
TranslationTableRule *transRule = (TranslationTableRule *)
& table->ruleArea[table->undefined];
if (!for_updatePositions
(&transRule->charsdots[transRule->charslen],
transRule->charslen, transRule->dotslen))
return 0;
return 1;
}
display = showString (&c, 1);
if ((dest + strlen (display)) > destmax)
return 0;
if (outputPositions != NULL)
outputPositions[prevSrcMapping[src]] = dest;
for (k = 0; k < strlen (display); k++)
{
if (inputPositions != NULL)
srcMapping[dest] = prevSrcMapping[src];
currentOutput[dest++] = getDotsForChar (display[k]);
}
return 1;
}
static int
putCharacter (widechar character)
{
/*Insert the dots equivalent of a character into the output buffer */
TranslationTableCharacter *chardef;
TranslationTableOffset offset;
if (cursorStatus == 2)
return 1;
chardef = (findCharOrDots (character, 0));
if ((chardef->attributes & CTC_Letter) && (chardef->attributes &
CTC_UpperCase))
chardef = findCharOrDots (chardef->lowercase, 0);
offset = chardef->definitionRule;
if (offset)
{
const TranslationTableRule *rule = (TranslationTableRule *)
& table->ruleArea[offset];
if (rule->dotslen)
return for_updatePositions (&rule->charsdots[1], 1, rule->dotslen);
{
widechar d = getDotsForChar (character);
return for_updatePositions (&d, 1, 1);
}
}
return undefinedCharacter (character);
}
static int
putCharacters (const widechar * characters, int count)
{
/*Insert the dot equivalents of a series of characters in the output
* buffer */
int k;
for (k = 0; k < count; k++)
if (!putCharacter (characters[k]))
return 0;
return 1;
}
static int
doCompbrl (void)
{
/*Handle strings containing substrings defined by the compbrl opcode*/
int stringEnd;
if (checkAttr (currentInput[src], CTC_Space, 0))
return 1;
if (destword)
{
src = srcword;
dest = destword;
}
else
{
src = 0;
dest = 0;
}
for (stringEnd = src; stringEnd < srcmax; stringEnd++)
if (checkAttr (currentInput[stringEnd], CTC_Space, 0))
break;
return (doCompTrans (src, stringEnd));
}
static int
putCompChar (widechar character)
{
/*Insert the dots equivalent of a character into the output buffer */
TranslationTableOffset offset = (findCharOrDots
(character, 0))->definitionRule;
if (offset)
{
const TranslationTableRule *rule = (TranslationTableRule *)
& table->ruleArea[offset];
if (rule->dotslen)
return for_updatePositions (&rule->charsdots[1], 1, rule->dotslen);
{
widechar d = getDotsForChar (character);
return for_updatePositions (&d, 1, 1);
}
}
return undefinedCharacter (character);
}
static int
doCompTrans (int start, int end)
{
int k;
if (cursorStatus != 2 && brailleIndicatorDefined (table->begComp))
if (!for_updatePositions
(&indicRule->charsdots[0], 0, indicRule->dotslen))
return 0;
for (k = start; k < end; k++)
{
TranslationTableOffset compdots = 0;
src = k;
if (currentInput[k] < 256)
compdots = table->compdotsPattern[currentInput[k]];
if (compdots != 0)
{
transRule = (TranslationTableRule *) & table->ruleArea[compdots];
if (!for_updatePositions
(&transRule->charsdots[transRule->charslen],
transRule->charslen, transRule->dotslen))
return 0;
}
else if (!putCompChar (currentInput[k]))
return 0;
}
if (cursorStatus != 2 && brailleIndicatorDefined (table->endComp))
if (!for_updatePositions
(&indicRule->charsdots[0], 0, indicRule->dotslen))
return 0;
src = end;
return 1;
}
static int
doNocont (void)
{
/*Handle strings containing substrings defined by the nocont opcode*/
if (checkAttr (currentInput[src], CTC_Space, 0) || dontContract
|| (mode & noContractions))
return 1;
if (destword)
{
src = srcword;
dest = destword;
}
else
{
src = 0;
dest = 0;
}
dontContract = 1;
return 1;
}
static int
markSyllables (void)
{
int k;
int syllableMarker = 0;
int currentMark = 0;
if (typebuf == NULL || !table->syllables)
return 1;
src = 0;
while (src < srcmax)
{ /*the main multipass translation loop */
int length = srcmax - src;
const TranslationTableCharacter *character = findCharOrDots
(currentInput[src], 0);
const TranslationTableCharacter *character2;
int tryThis = 0;
while (tryThis < 3)
{
TranslationTableOffset ruleOffset = 0;
unsigned long int makeHash = 0;
switch (tryThis)
{
case 0:
if (!(length >= 2))
break;
makeHash = (unsigned long int) character->lowercase << 8;
character2 = findCharOrDots (currentInput[src + 1], 0);
makeHash += (unsigned long int) character2->lowercase;
makeHash %= HASHNUM;
ruleOffset = table->forRules[makeHash];
break;
case 1:
if (!(length >= 1))
break;
length = 1;
ruleOffset = character->otherRules;
break;
case 2: /*No rule found */
transOpcode = CTO_Always;
ruleOffset = 0;
break;
}
while (ruleOffset)
{
transRule =
(TranslationTableRule *) & table->ruleArea[ruleOffset];
transOpcode = transRule->opcode;
transCharslen = transRule->charslen;
if (tryThis == 1 || (transCharslen <= length &&
compareChars (&transRule->
charsdots[0],
&currentInput[src],
transCharslen, 0)))
{
if (transOpcode == CTO_Syllable)
{
tryThis = 4;
break;
}
}
ruleOffset = transRule->charsnext;
}
tryThis++;
}
switch (transOpcode)
{
case CTO_Always:
if (src >= srcmax)
return 0;
if (typebuf != NULL)
typebuf[src++] |= currentMark;
break;
case CTO_Syllable:
syllableMarker++;
if (syllableMarker > 3)
syllableMarker = 1;
currentMark = syllableMarker << 6;
/*The syllable marker is bita 6 and 7 of typebuf. */
if ((src + transCharslen) > srcmax)
return 0;
for (k = 0; k < transCharslen; k++)
typebuf[src++] |= currentMark;
break;
default:
break;
}
}
return 1;
}
static int
translateString (void)
{
/*Main translation routine */
int k;
markSyllables ();
srcword = 0;
destword = 0; /* last word translated */
dontContract = 0;
prevTransOpcode = CTO_None;
wordsMarked = 0;
prevType = prevPrevType = curType = nextType = prevTypeform = plain_text;
startType = prevSrc = -1;
src = dest = 0;
srcIncremented = 1;
for (k = 0; k < NUMVAR; k++)
passVariables[k] = 0;
if (typebuf && table->capitalSign)
for (k = 0; k < srcmax; k++)
if (checkAttr (currentInput[k], CTC_UpperCase, 0))
typebuf[k] |= capsemph;
while (src < srcmax)
{ /*the main translation loop */
setBefore ();
if (!insertBrailleIndicators (0))
goto failure;
if (src >= srcmax)
break;
if (!insertIndicators ())
goto failure;
for_selectRule ();
if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
appliedRules[appliedRulesCount++] = transRule;
srcIncremented = 1;
prevSrc = src;
switch (transOpcode) /*Rules that pre-empt context and swap */
{
case CTO_CompBrl:
case CTO_Literal:
if (!doCompbrl ())
goto failure;
continue;
default:
break;
}
if (!insertBrailleIndicators (1))
goto failure;
if (transOpcode == CTO_Context || findAttribOrSwapRules ())
switch (transOpcode)
{
case CTO_Context:
if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
appliedRules[appliedRulesCount++] = transRule;
if (!passDoAction ())
goto failure;
if (endReplace == src)
srcIncremented = 0;
src = endReplace;
continue;
default:
break;
}
/*Processing before replacement*/
switch (transOpcode)
{
case CTO_EndNum:
if (table->letterSign && checkAttr (currentInput[src],
CTC_Letter, 0))
dest--;
break;
case CTO_Repeated:
case CTO_Space:
dontContract = 0;
break;
case CTO_LargeSign:
if (prevTransOpcode == CTO_LargeSign)
if (dest > 0 && checkAttr (currentOutput[dest - 1], CTC_Space, 1))
dest--;
break;
case CTO_DecPoint:
if (table->numberSign)
{
TranslationTableRule *numRule = (TranslationTableRule *)
& table->ruleArea[table->numberSign];
if (!for_updatePositions
(&numRule->charsdots[numRule->charslen],
numRule->charslen, numRule->dotslen))
goto failure;
}
transOpcode = CTO_MidNum;
break;
case CTO_NoCont:
if (!dontContract)
doNocont ();
continue;
default:
break;
} /*end of action */
/* replacement processing */
switch (transOpcode)
{
case CTO_Replace:
src += transCharslen;
if (!putCharacters
(&transRule->charsdots[transCharslen], transRule->dotslen))
goto failure;
break;
case CTO_None:
if (!undefinedCharacter (currentInput[src]))
goto failure;
src++;
break;
case CTO_UpperCase:
/* Only needs special handling if not within compbrl and
*the table defines a capital sign. */
if (!
(mode & (compbrlAtCursor | compbrlLeftCursor) && src >=
compbrlStart
&& src <= compbrlEnd) && (transRule->dotslen == 1
&& table->capitalSign))
{
putCharacter (curCharDef->lowercase);
src++;
break;
}
default:
if (cursorStatus == 2)
cursorStatus = 1;
else
{
if (transRule->dotslen)
{
if (!for_updatePositions
(&transRule->charsdots[transCharslen],
transCharslen, transRule->dotslen))
goto failure;
}
else
{
for (k = src; k < (src + transCharslen); k++)
{
if (!putCharacter (currentInput[k]))
goto failure;
}
}
if (cursorStatus == 2)
cursorStatus = 1;
else
src += transCharslen;
}
break;
}
/* processing after replacement */
switch (transOpcode)
{
case CTO_Repeated:
{
/* Skip repeated characters. */
int srclim = srcmax - transCharslen;
if (mode & (compbrlAtCursor | compbrlLeftCursor) &&
compbrlStart < srclim)
/* Don't skip characters from compbrlStart onwards. */
srclim = compbrlStart - 1;
while ((src <= srclim)
&& compareChars (&transRule->charsdots[0],
&currentInput[src], transCharslen, 0))
{
/* Map skipped input positions to the previous output position. */
if (outputPositions != NULL)
{
int tcc;
for (tcc = 0; tcc < transCharslen; tcc++)
outputPositions[prevSrcMapping[src + tcc]] = dest - 1;
}
if (!cursorStatus && src <= cursorPosition
&& cursorPosition < src + transCharslen)
{
cursorStatus = 1;
cursorPosition = dest - 1;
}
src += transCharslen;
}
break;
}
case CTO_RepWord:
{
/* Skip repeated characters. */
int srclim = srcmax - transCharslen;
if (mode & (compbrlAtCursor | compbrlLeftCursor) &&
compbrlStart < srclim)
/* Don't skip characters from compbrlStart onwards. */
srclim = compbrlStart - 1;
while ((src <= srclim)
&& compareChars (repwordStart,
&currentInput[src], repwordLength, 0))
{
/* Map skipped input positions to the previous output position. */
if (outputPositions != NULL)
{
int tcc;
for (tcc = 0; tcc < transCharslen; tcc++)
outputPositions[prevSrcMapping[src + tcc]] = dest - 1;
}
if (!cursorStatus && src <= cursorPosition
&& cursorPosition < src + transCharslen)
{
cursorStatus = 1;
cursorPosition = dest - 1;
}
src += repwordLength + transCharslen;
}
src -= transCharslen;
break;
}
case CTO_JoinNum:
case CTO_JoinableWord:
while ((src < srcmax)
&& checkAttr (currentInput[src], CTC_Space, 0))
src++;
break;
default:
break;
}
if (((src > 0) && checkAttr (currentInput[src - 1], CTC_Space, 0)
&& (transOpcode != CTO_JoinableWord)))
{
srcword = src;
destword = dest;
}
if (srcSpacing != NULL && srcSpacing[src] >= '0' && srcSpacing[src] <=
'9')
destSpacing[dest] = srcSpacing[src];
if ((transOpcode >= CTO_Always && transOpcode <= CTO_None) ||
(transOpcode >= CTO_Digit && transOpcode <= CTO_LitDigit))
prevTransOpcode = transOpcode;
} /*end of translation loop */
if (haveEmphasis && !wordsMarked && prevPrevType != plain_text)
insertBrailleIndicators (2);
failure:
if (destword != 0 && src < srcmax
&& !checkAttr (currentInput[src], CTC_Space, 0))
{
src = srcword;
dest = destword;
}
if (src < srcmax)
{
while (checkAttr (currentInput[src], CTC_Space, 0))
if (++src == srcmax)
break;
}
realInlen = src;
return 1;
} /*first pass translation completed */
int EXPORT_CALL
lou_hyphenate (const char *tableList, const widechar
* inbuf, int inlen, char *hyphens, int mode)
{
#define HYPHSTRING 100
widechar workingBuffer[HYPHSTRING];
int inputPos[HYPHSTRING];
int k, kk;
int wordStart;
int wordEnd;
table = lou_getTable (tableList);
if (table == NULL || inbuf == NULL || hyphens
== NULL || table->hyphenStatesArray == 0 || inlen >= HYPHSTRING)
return 0;
if (mode != 0)
{
k = inlen;
kk = HYPHSTRING;
if (!lou_backTranslate (tableList, inbuf, &k,
&workingBuffer[0],
&kk, NULL, NULL, NULL, inputPos, NULL, 0))
return 0;
}
else
{
memcpy (&workingBuffer[0], inbuf, CHARSIZE * inlen);
kk = inlen;
}
for (wordStart = 0; wordStart < kk; wordStart++)
if (((findCharOrDots (workingBuffer[wordStart], 0))->attributes &
CTC_Letter))
break;
if (wordStart == kk)
return 0;
for (wordEnd = kk - 1; wordEnd >= 0; wordEnd--)
if (((findCharOrDots (workingBuffer[wordEnd], 0))->attributes &
CTC_Letter))
break;
for (k = wordStart; k <= wordEnd; k++)
{
TranslationTableCharacter *c = findCharOrDots (workingBuffer[k], 0);
if (!(c->attributes & CTC_Letter))
return 0;
}
if (!hyphenate
(&workingBuffer[wordStart], wordEnd - wordStart + 1,
&hyphens[wordStart]))
return 0;
if (mode != 0)
{
char hyphens2[HYPHSTRING];
kk = wordEnd + 1;
k = HYPHSTRING;
for (kk = wordStart; kk < wordEnd; kk++)
{
int hyphPos = inputPos[kk];
if (hyphPos > k || hyphPos < 0)
break;
if (hyphens[kk] & 1)
hyphens2[hyphPos] = '1';
else
hyphens2[hyphPos] = '0';
}
wordStart = inputPos[wordStart];
wordEnd = inputPos[wordEnd];
for (kk = wordStart; kk < k; kk++)
if (!table->noBreak || hyphens2[kk] == '0')
hyphens[kk] = hyphens2[kk];
else
{
TranslationTableRule *noBreakRule = (TranslationTableRule *)
& table->ruleArea[table->noBreak];
int kkk;
if (kk > wordStart)
for (kkk = 0; kkk < noBreakRule->charslen; kkk++)
if (inbuf[kk - 1] == noBreakRule->charsdots[kkk])
{
hyphens[kk] = '0';
break;
}
for (kkk = 0; kkk < noBreakRule->dotslen; kkk++);
if (inbuf[kk] ==
noBreakRule->charsdots[noBreakRule->charslen + kkk])
{
hyphens[kk] = '0';
break;
}
}
}
for (k = 0; k < inlen; k++)
if ((k <= wordStart) || (k >= wordEnd))
hyphens[k] = '0';
else if (hyphens[k] & 1)
hyphens[k] = '1';
else
hyphens[k] = '0';
hyphens[inlen] = 0;
return 1;
}
int EXPORT_CALL
lou_dotsToChar (const char *tableList, widechar * inbuf, widechar * outbuf,
int length, int mode)
{
int k;
widechar dots;
if (tableList == NULL || inbuf == NULL || outbuf == NULL)
return 0;
if ((mode & otherTrans))
return other_dotsToChar (tableList, inbuf, outbuf, length, mode);
table = lou_getTable (tableList);
if (table == NULL || length <= 0)
return 0;
for (k = 0; k < length; k++)
{
dots = inbuf[k];
if (!(dots & B16) && (dots & 0xff00) == 0x2800) /*Unicode braille */
dots = (dots & 0x00ff) | B16;
outbuf[k] = getCharFromDots (dots);
}
return 1;
}
int EXPORT_CALL
lou_charToDots (const char *tableList, const widechar * inbuf, widechar *
outbuf, int length, int mode)
{
int k;
if (tableList == NULL || inbuf == NULL || outbuf == NULL)
return 0;
if ((mode & otherTrans))
return other_charToDots (tableList, inbuf, outbuf, length, mode);
table = lou_getTable (tableList);
if (table == NULL || length <= 0)
return 0;
for (k = 0; k < length; k++)
if ((mode & ucBrl))
outbuf[k] = ((getDotsForChar (inbuf[k]) & 0xff) | 0x2800);
else
outbuf[k] = getDotsForChar (inbuf[k]);
return 1;
}