| /* 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 (¤tOutput[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 (¤tInput[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 = ¤tInput[start]; |
| repwordLength = src - start; |
| if (compareChars (repwordStart, ¤tInput[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], |
| ¤tInput[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], |
| ¤tInput[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, |
| ¤tInput[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 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, NULL, 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; |
| for (k = 0; k <= wordStart; k++) |
| hyphens[k] = '0'; |
| if (mode != 0) |
| { |
| widechar workingBuffer2[HYPHSTRING]; |
| int outputPos[HYPHSTRING]; |
| char hyphens2[HYPHSTRING]; |
| kk = wordEnd - wordStart + 1; |
| k = HYPHSTRING; |
| if (!lou_translate (tableList, &workingBuffer[wordStart], &kk, |
| &workingBuffer2[0], &k, NULL, |
| NULL, &outputPos[0], NULL, NULL, 0)) |
| return 0; |
| for (kk = 0; kk < k; kk++) |
| { |
| int hyphPos = outputPos[kk]; |
| if (hyphPos > k || hyphPos < 0) |
| break; |
| if (hyphens[wordStart + kk] & 1) |
| hyphens2[hyphPos] = '1'; |
| else |
| hyphens2[hyphPos] = '0'; |
| } |
| for (kk = wordStart; kk < wordStart + k; kk++) |
| if (!table->noBreak || hyphens2[kk] == '0') |
| hyphens[kk] = hyphens2[kk]; |
| else |
| { |
| TranslationTableRule *noBreakRule = (TranslationTableRule *) |
| & table->ruleArea[table->noBreak]; |
| int kkk; |
| if (kk > 0) |
| for (kkk = 0; kkk < noBreakRule->charslen; kkk++) |
| if (workingBuffer2[kk - 1] == noBreakRule->charsdots[kkk]) |
| { |
| hyphens[kk] = '0'; |
| break; |
| } |
| for (kkk = 0; kkk < noBreakRule->dotslen; kkk++); |
| if (workingBuffer2[kk] == |
| noBreakRule->charsdots[noBreakRule->charslen + kkk]) |
| { |
| hyphens[kk] = '0'; |
| break; |
| } |
| } |
| } |
| for (k = 0; k < inlen; k++) |
| 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; |
| } |