Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / liblouis / src / liblouis / lou_translateString.c
1 /* liblouis Braille Translation and Back-Translation Library
2
3    Based on the Linux screenreader BRLTTY, copyright (C) 1999-2006 by
4    The BRLTTY Team
5
6    Copyright (C) 2004, 2005, 2006
7    ViewPlus Technologies, Inc. www.viewplus.com
8    and
9    abilitiessoft, Inc. www.abilitiessoft.com
10    All rights reserved
11
12    This file is part of Liblouis.
13
14    Liblouis is free software: you can redistribute it and/or modify it
15    under the terms of the GNU Lesser General Public License as
16    published by the Free Software Foundation, either version 3 of the
17    License, or (at your option) any later version.
18
19    Liblouis is distributed in the hope that it will be useful, but
20    WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22    Lesser General Public License for more details.
23
24    You should have received a copy of the GNU Lesser General Public
25    License along with Liblouis. If not, see
26    <http://www.gnu.org/licenses/>.
27
28    Maintained by John J. Boyer john.boyer@abilitiessoft.com
29    */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "louis.h"
36 #include "transcommon.ci"
37
38 #define MIN(a,b) (((a)<(b))?(a):(b))
39
40 static int translateString ();
41 static int compbrlStart = 0;
42 static int compbrlEnd = 0;
43
44 int EXPORT_CALL
45 lou_translateString (const char *tableList, const widechar
46                      * inbufx,
47                      int *inlen, widechar * outbuf, int *outlen, 
48                      formtype
49                      *typeform, char *spacing, int mode)
50 {
51   return
52     lou_translate (tableList, inbufx, inlen, outbuf, outlen, typeform,
53                    spacing, NULL, NULL, NULL, mode);
54 }
55
56 int EXPORT_CALL
57 lou_translate (const char *tableList, const widechar
58                * inbufx,
59                int *inlen, widechar * outbuf, int *outlen,
60                formtype *typeform, char *spacing, int *outputPos,
61                int *inputPos, int *cursorPos, int modex)
62 {
63   return trace_translate (tableList, inbufx, inlen, outbuf, outlen,
64                           typeform, spacing, outputPos, inputPos, cursorPos,
65                           NULL, NULL, modex);
66 }
67
68 int
69 trace_translate (const char *tableList, const widechar * inbufx,
70                  int *inlen, widechar * outbuf, int *outlen,
71                  formtype *typeform, char *spacing, int *outputPos,
72                  int *inputPos, int *cursorPos,
73                  const TranslationTableRule ** rules, int *rulesLen,
74                  int modex)
75 {
76   int k;
77   int goodTrans = 1;
78   if (tableList == NULL || inbufx == NULL || inlen == NULL || outbuf ==
79       NULL || outlen == NULL)
80     return 0;
81   logMessage(LOG_DEBUG, "Performing translation: tableList=%s, inlen=%d", tableList, *inlen);
82   logWidecharBuf(LOG_DEBUG, "Inbuf=", inbufx, *inlen);
83   if ((modex & otherTrans))
84     return other_translate (tableList, inbufx,
85                             inlen, outbuf, outlen,
86                             typeform, spacing, outputPos, inputPos, cursorPos,
87                             modex);
88   table = lou_getTable (tableList);
89   if (table == NULL || *inlen < 0 || *outlen < 0)
90     return 0;
91   currentInput = (widechar *) inbufx;
92   srcmax = 0;
93   while (srcmax < *inlen && currentInput[srcmax])
94     srcmax++;
95   destmax = *outlen;
96   haveEmphasis = 0;
97   if (!(typebuf = liblouis_allocMem (alloc_typebuf, srcmax, destmax)))
98     return 0;
99   if (typeform != NULL)
100     {
101       for (k = 0; k < srcmax; k++)
102         if ((typebuf[k] = typeform[k] & EMPHASIS))
103           haveEmphasis = 1;
104     }
105   else
106     memset (typebuf, 0, srcmax * sizeof (unsigned short));
107   if (!(spacing == NULL || *spacing == 'X'))
108     srcSpacing = (unsigned char *) spacing;
109   outputPositions = outputPos;
110   if (outputPos != NULL)
111     for (k = 0; k < srcmax; k++)
112       outputPos[k] = -1;
113   inputPositions = inputPos;
114   mode = modex;
115   if (cursorPos != NULL && *cursorPos >= 0)
116     {
117       cursorStatus = 0;
118       cursorPosition = *cursorPos;
119       if ((mode & (compbrlAtCursor | compbrlLeftCursor)))
120         {
121           compbrlStart = cursorPosition;
122           if (checkAttr (currentInput[compbrlStart], CTC_Space, 0))
123             compbrlEnd = compbrlStart + 1;
124           else
125             {
126               while (compbrlStart >= 0 && !checkAttr
127                      (currentInput[compbrlStart], CTC_Space, 0))
128                 compbrlStart--;
129               compbrlStart++;
130               compbrlEnd = cursorPosition;
131               if (!(mode & compbrlLeftCursor))
132                 while (compbrlEnd < srcmax && !checkAttr
133                        (currentInput[compbrlEnd], CTC_Space, 0))
134                   compbrlEnd++;
135             }
136         }
137     }
138   else
139     {
140       cursorPosition = -1;
141       cursorStatus = 1;         /*so it won't check cursor position */
142     }
143   if (!(passbuf1 = liblouis_allocMem (alloc_passbuf1, srcmax, destmax)))
144     return 0;
145   if (!(srcMapping = liblouis_allocMem (alloc_srcMapping, srcmax, destmax)))
146     return 0;
147   if (!
148       (prevSrcMapping =
149        liblouis_allocMem (alloc_prevSrcMapping, srcmax, destmax)))
150     return 0;
151   for (k = 0; k <= srcmax; k++)
152     srcMapping[k] = k;
153   srcMapping[srcmax] = srcmax;
154   if ((!(mode & pass1Only)) && (table->numPasses > 1 || table->corrections))
155     {
156       if (!(passbuf2 = liblouis_allocMem (alloc_passbuf2, srcmax, destmax)))
157         return 0;
158     }
159   if (srcSpacing != NULL)
160     {
161       if (!(destSpacing = liblouis_allocMem (alloc_destSpacing, srcmax,
162                                              destmax)))
163         goodTrans = 0;
164       else
165         memset (destSpacing, '*', destmax);
166     }
167   appliedRulesCount = 0;
168   if (rules != NULL && rulesLen != NULL)
169     {
170       appliedRules = rules;
171       maxAppliedRules = *rulesLen;
172     }
173   else
174     {
175       appliedRules = NULL;
176       maxAppliedRules = 0;
177     }
178   currentPass = 0;
179   if ((mode & pass1Only))
180     {
181       currentOutput = passbuf1;
182       memcpy (prevSrcMapping, srcMapping, destmax * sizeof (int));
183       goodTrans = translateString ();
184       currentPass = 5;          /*Certainly > table->numPasses */
185     }
186   while (currentPass <= table->numPasses && goodTrans)
187     {
188       memcpy (prevSrcMapping, srcMapping, destmax * sizeof (int));
189       switch (currentPass)
190         {
191         case 0:
192           if (table->corrections)
193             {
194               currentOutput = passbuf2;
195               goodTrans = makeCorrections ();
196               currentInput = passbuf2;
197               srcmax = dest;
198             }
199           break;
200         case 1:
201           currentOutput = passbuf1;
202           goodTrans = translateString ();
203           break;
204         case 2:
205           srcmax = dest;
206           currentInput = passbuf1;
207           currentOutput = passbuf2;
208           goodTrans = translatePass ();
209           break;
210         case 3:
211           srcmax = dest;
212           currentInput = passbuf2;
213           currentOutput = passbuf1;
214           goodTrans = translatePass ();
215           break;
216         case 4:
217           srcmax = dest;
218           currentInput = passbuf1;
219           currentOutput = passbuf2;
220           goodTrans = translatePass ();
221           break;
222         default:
223           break;
224         }
225       currentPass++;
226     }
227   if (goodTrans)
228     {
229       for (k = 0; k < dest; k++)
230         {
231           if (typeform != NULL)
232             {
233               if ((currentOutput[k] & (B7 | B8)))
234                 typeform[k] = '8';
235               else
236                 typeform[k] = '0';
237             }
238           if ((mode & dotsIO))
239             {
240               if ((mode & ucBrl))
241                 outbuf[k] = ((currentOutput[k] & 0xff) | 0x2800);
242               else
243                 outbuf[k] = currentOutput[k];
244             }
245           else
246             outbuf[k] = getCharFromDots (currentOutput[k]);
247         }
248       *inlen = realInlen;
249       *outlen = dest;
250       if (inputPositions != NULL)
251         memcpy (inputPositions, srcMapping, dest * sizeof (int));
252       if (outputPos != NULL)
253         {
254           int lastpos = 0;
255           for (k = 0; k < *inlen; k++)
256             if (outputPos[k] == -1)
257               outputPos[k] = lastpos;
258             else
259               lastpos = outputPos[k];
260         }
261     }
262   if (destSpacing != NULL)
263     {
264       memcpy (srcSpacing, destSpacing, srcmax);
265       srcSpacing[srcmax] = 0;
266     }
267   if (cursorPos != NULL && *cursorPos != -1)
268     {
269       if (outputPos != NULL)
270         *cursorPos = outputPos[*cursorPos];
271       else
272         *cursorPos = cursorPosition;
273     }
274   if (rulesLen != NULL)
275     *rulesLen = appliedRulesCount;
276   logMessage(LOG_DEBUG, "Translation complete: outlen=%d", *outlen);
277   logWidecharBuf(LOG_DEBUG, "Outbuf=", (const widechar *)outbuf, *outlen);
278   return goodTrans;
279 }
280
281 int EXPORT_CALL
282 lou_translatePrehyphenated (const char *tableList,
283                             const widechar * inbufx, int *inlen,
284                             widechar * outbuf, int *outlen,
285                             formtype *typeform, char *spacing,
286                             int *outputPos, int *inputPos, int *cursorPos,
287                             char *inputHyphens, char *outputHyphens,
288                             int modex)
289 {
290   int rv = 1;
291   int *alloc_inputPos = NULL;
292   if (inputHyphens != NULL)
293     {
294       if (outputHyphens == NULL)
295         return 0;
296       if (inputPos == NULL)
297         {
298           if ((alloc_inputPos = malloc (*outlen * sizeof (int))) == NULL)
299             outOfMemory ();
300           inputPos = alloc_inputPos;
301         }
302     }
303   if (lou_translate (tableList, inbufx, inlen, outbuf, outlen, typeform,
304                      spacing, outputPos, inputPos, cursorPos, modex))
305     {
306       if (inputHyphens != NULL)
307         {
308           int inpos = 0;
309           int outpos;
310           for (outpos = 0; outpos < *outlen; outpos++)
311             {
312               int new_inpos = inputPos[outpos];
313               if (new_inpos < inpos)
314                 {
315                   rv = 0;
316                   break;
317                 }
318               if (new_inpos > inpos)
319                 outputHyphens[outpos] = inputHyphens[new_inpos];
320               else
321                 outputHyphens[outpos] = '0';
322               inpos = new_inpos;
323             }
324         }
325     }
326   if (alloc_inputPos != NULL)
327     free (alloc_inputPos);
328   return rv;
329 }
330
331 static TranslationTableOpcode indicOpcode;
332 static const TranslationTableRule *indicRule;
333 static int dontContract = 0;
334
335 static int
336 hyphenate (const widechar * word, int wordSize, char *hyphens)
337 {
338   widechar *prepWord;
339   int i, k, limit;
340   int stateNum;
341   widechar ch;
342   HyphenationState *statesArray = (HyphenationState *)
343     & table->ruleArea[table->hyphenStatesArray];
344   HyphenationState *currentState;
345   HyphenationTrans *transitionsArray;
346   char *hyphenPattern;
347   int patternOffset;
348   if (!table->hyphenStatesArray || (wordSize + 3) > MAXSTRING)
349     return 0;
350   prepWord = (widechar *) calloc (wordSize + 3, sizeof (widechar));
351   /* prepWord is of the format ".hello."
352    * hyphens is the length of the word "hello" "00000" */
353   prepWord[0] = '.';
354   for (i = 0; i < wordSize; i++)
355     {
356       prepWord[i + 1] = (findCharOrDots (word[i], 0))->lowercase;
357       hyphens[i] = '0';
358     }
359   prepWord[wordSize + 1] = '.';
360
361   /* now, run the finite state machine */
362   stateNum = 0;
363
364   // we need to walk all of ".hello."
365   for (i = 0; i < wordSize + 2; i++)
366     {
367       ch = prepWord[i];
368       while (1)
369         {
370           if (stateNum == 0xffff)
371             {
372               stateNum = 0;
373               goto nextLetter;
374             }
375           currentState = &statesArray[stateNum];
376           if (currentState->trans.offset)
377             {
378               transitionsArray = (HyphenationTrans *) &
379                 table->ruleArea[currentState->trans.offset];
380               for (k = 0; k < currentState->numTrans; k++)
381                 {
382                   if (transitionsArray[k].ch == ch)
383                     {
384                       stateNum = transitionsArray[k].newState;
385                       goto stateFound;
386                     }
387                 }
388             }
389           stateNum = currentState->fallbackState;
390         }
391     stateFound:
392       currentState = &statesArray[stateNum];
393       if (currentState->hyphenPattern)
394         {
395           hyphenPattern =
396             (char *) &table->ruleArea[currentState->hyphenPattern];
397           patternOffset = i + 1 - strlen (hyphenPattern);
398
399           /* Need to ensure that we don't overrun hyphens,
400            * in some cases hyphenPattern is longer than the remaining letters,
401            * and if we write out all of it we would have overshot our buffer. */
402           limit = MIN (strlen (hyphenPattern), wordSize - patternOffset);
403           for (k = 0; k < limit; k++)
404             {
405               if (hyphens[patternOffset + k] < hyphenPattern[k])
406                 hyphens[patternOffset + k] = hyphenPattern[k];
407             }
408         }
409     nextLetter:;
410     }
411   hyphens[wordSize] = 0;
412   free (prepWord);
413   return 1;
414 }
415
416 static int destword;
417 static int srcword;
418 static int doCompTrans (int start, int end);
419
420 static int
421 for_updatePositions (const widechar * outChars, int inLength, int outLength)
422 {
423   int k;
424   if ((dest + outLength) > destmax || (src + inLength) > srcmax)
425     return 0;
426   memcpy (&currentOutput[dest], outChars, outLength * CHARSIZE);
427   if (!cursorStatus)
428     {
429       if ((mode & (compbrlAtCursor | compbrlLeftCursor)))
430         {
431           if (src >= compbrlStart)
432             {
433               cursorStatus = 2;
434               return (doCompTrans (compbrlStart, compbrlEnd));
435             }
436         }
437       else if (cursorPosition >= src && cursorPosition < (src + inLength))
438         {
439           cursorPosition = dest;
440           cursorStatus = 1;
441         }
442       else if (currentInput[cursorPosition] == 0 &&
443                cursorPosition == (src + inLength))
444         {
445           cursorPosition = dest + outLength / 2 + 1;
446           cursorStatus = 1;
447         }
448     }
449   else if (cursorStatus == 2 && cursorPosition == src)
450     cursorPosition = dest;
451   if (inputPositions != NULL || outputPositions != NULL)
452     {
453       if (outLength <= inLength)
454         {
455           for (k = 0; k < outLength; k++)
456             {
457               if (inputPositions != NULL)
458                 srcMapping[dest + k] = prevSrcMapping[src];
459               if (outputPositions != NULL)
460                 outputPositions[prevSrcMapping[src + k]] = dest;
461             }
462           for (k = outLength; k < inLength; k++)
463             if (outputPositions != NULL)
464               outputPositions[prevSrcMapping[src + k]] = dest;
465         }
466       else
467         {
468           for (k = 0; k < inLength; k++)
469             {
470               if (inputPositions != NULL)
471                 srcMapping[dest + k] = prevSrcMapping[src];
472               if (outputPositions != NULL)
473                 outputPositions[prevSrcMapping[src + k]] = dest;
474             }
475           for (k = inLength; k < outLength; k++)
476             if (inputPositions != NULL)
477               srcMapping[dest + k] = prevSrcMapping[src];
478         }
479     }
480   dest += outLength;
481   return 1;
482 }
483
484 static int
485 syllableBreak ()
486 {
487   int wordStart = 0;
488   int wordEnd = 0;
489   int wordSize = 0;
490   int k = 0;
491   char *hyphens = NULL;
492   for (wordStart = src; wordStart >= 0; wordStart--)
493     if (!((findCharOrDots (currentInput[wordStart], 0))->attributes &
494           CTC_Letter))
495       {
496         wordStart++;
497         break;
498       }
499   if (wordStart < 0)
500     wordStart = 0;
501   for (wordEnd = src; wordEnd < srcmax; wordEnd++)
502     if (!((findCharOrDots (currentInput[wordEnd], 0))->attributes &
503           CTC_Letter))
504       {
505         wordEnd--;
506         break;
507       }
508   if (wordEnd == srcmax)
509     wordEnd--;
510   /* At this stage wordStart is the 0 based index of the first letter in the word,
511    * wordEnd is the 0 based index of the last letter in the word.
512    * example: "hello" wordstart=0, wordEnd=4. */
513   wordSize = wordEnd - wordStart + 1;
514   hyphens = (char *) calloc (wordSize + 1, sizeof (char));
515   if (!hyphenate (&currentInput[wordStart], wordSize, hyphens))
516     {
517       free (hyphens);
518       return 0;
519     }
520   for (k = src - wordStart + 1; k < (src - wordStart + transCharslen); k++)
521     if (hyphens[k] & 1)
522       {
523         free (hyphens);
524         return 1;
525       }
526   free (hyphens);
527   return 0;
528 }
529
530 static TranslationTableCharacter *curCharDef;
531 static widechar before, after;
532 static TranslationTableCharacterAttributes beforeAttributes;
533 static TranslationTableCharacterAttributes afterAttributes;
534 static void
535 setBefore ()
536 {
537   if (src >= 2 && currentInput[src - 1] == ENDSEGMENT)
538     before = currentInput[src - 2];
539   else
540     before = (src == 0) ? ' ' : currentInput[src - 1];
541   beforeAttributes = (findCharOrDots (before, 0))->attributes;
542 }
543
544 static void
545 setAfter (int length)
546 {
547   if ((src + length + 2) < srcmax && currentInput[src + 1] == ENDSEGMENT)
548     after = currentInput[src + 2];
549   else
550     after = (src + length < srcmax) ? currentInput[src + length] : ' ';
551   afterAttributes = (findCharOrDots (after, 0))->attributes;
552 }
553
554 static int prevTypeform = plain_text;
555 static int prevSrc = 0;
556 static TranslationTableRule pseudoRule = {
557   0
558 };
559
560 static int
561 brailleIndicatorDefined (TranslationTableOffset offset)
562 {
563   if (!offset)
564     return 0;
565   indicRule = (TranslationTableRule *) & table->ruleArea[offset];
566   indicOpcode = indicRule->opcode;
567   return 1;
568 }
569
570 static int prevType = plain_text;
571 static int curType = plain_text;
572
573 typedef enum
574 {
575   firstWord,
576   lastWordBefore,
577   lastWordAfter,
578   firstLetter,
579   lastLetter,
580   singleLetter,
581   word,
582   lenPhrase
583 } emphCodes;
584
585 static int wordsMarked = 0;
586 static int finishEmphasis = 0;
587 static int wordCount = 0;
588 static int lastWord = 0;
589 static int startType = -1;
590 static int endType = 0;
591
592 static void
593 markWords (const TranslationTableOffset * offset)
594 {
595 /*Mark the beginnings of words*/
596   int numWords = 0;
597   int k;
598   wordsMarked = 1;
599   numWords = offset[lenPhrase];
600   if (!numWords)
601     numWords = 4;
602   if (wordCount < numWords)
603     {
604       for (k = src; k < endType; k++)
605         if (!checkAttr (currentInput[k - 1], CTC_Letter | CTC_Digit, 0) &&
606             checkAttr (currentInput[k], CTC_Digit | CTC_Letter, 0))
607           typebuf[k] |= STARTWORD;
608     }
609   else
610     {
611       int firstWord = 1;
612       int lastWord = src;
613       for (k = src; k < endType; k++)
614         {
615           if (!checkAttr (currentInput[k - 1], CTC_Letter | CTC_Digit, 0)
616               && checkAttr (currentInput[k], CTC_Digit | CTC_Letter, 0))
617             {
618               if (firstWord)
619                 {
620                   typebuf[k] |= FIRSTWORD;
621                   firstWord = 0;
622                 }
623               else
624                 lastWord = k;
625             }
626         }
627       typebuf[lastWord] |= STARTWORD;
628     }
629 }
630
631 static int
632 insertIndicators ()
633 {
634 /*Insert italic, bold, etc. indicators before words*/
635   int typeMark;
636   int ruleFound = 0;
637   if (!wordsMarked || !haveEmphasis)
638     return 1;
639   typeMark = typebuf[src] & (STARTWORD | FIRSTWORD);
640   if (!typeMark)
641     return 1;
642   switch (typebuf[src] & EMPHASIS)
643     {
644     case italic:
645       if ((typeMark & FIRSTWORD))
646         ruleFound = brailleIndicatorDefined (table->firstWordItal);
647       else
648         ruleFound = brailleIndicatorDefined (table->lastWordItalBefore);
649       break;
650     case bold:
651       if ((typeMark & FIRSTWORD))
652         ruleFound = brailleIndicatorDefined (table->firstWordBold);
653       else
654         ruleFound = brailleIndicatorDefined (table->lastWordBoldBefore);
655       break;
656     case underline:
657       if ((typeMark & FIRSTWORD))
658         ruleFound = brailleIndicatorDefined (table->firstWordUnder);
659       else
660         ruleFound = brailleIndicatorDefined (table->lastWordUnderBefore);
661       break;
662     default:
663       ruleFound = 0;
664       break;
665     }
666   if (ruleFound)
667     {
668       if (!for_updatePositions
669           (&indicRule->charsdots[0], 0, indicRule->dotslen))
670         return 0;
671     }
672   return 1;
673 }
674
675 static int
676 validMatch ()
677 {
678 /*Analyze the typeform parameter and also check for capitalization*/
679   TranslationTableCharacter *currentInputChar;
680   TranslationTableCharacter *ruleChar;
681   TranslationTableCharacterAttributes prevAttr = 0;
682   int k;
683   int kk = 0;
684   if (!transCharslen)
685     return 0;
686   for (k = src; k < src + transCharslen; k++)
687     {
688       if (currentInput[k] == ENDSEGMENT)
689         {
690           if (k == src && transCharslen == 1)
691             return 1;
692           else
693             return 0;
694         }
695       currentInputChar = findCharOrDots (currentInput[k], 0);
696       if (k == src)
697         prevAttr = currentInputChar->attributes;
698       ruleChar = findCharOrDots (transRule->charsdots[kk++], 0);
699       if ((currentInputChar->lowercase != ruleChar->lowercase))
700         return 0;
701       if (typebuf != NULL && (typebuf[src] & capsemph) == 0 &&
702           (typebuf[k] | typebuf[src]) != (typebuf[src]))
703         return 0;
704       if (currentInputChar->attributes != CTC_Letter)
705         {
706           if (k != (src + 1) && (prevAttr &
707                                  CTC_Letter)
708               && (currentInputChar->attributes & CTC_Letter)
709               &&
710               ((currentInputChar->
711                 attributes & (CTC_LowerCase | CTC_UpperCase |
712                               CTC_Letter)) !=
713                (prevAttr & (CTC_LowerCase | CTC_UpperCase | CTC_Letter))))
714             return 0;
715         }
716       prevAttr = currentInputChar->attributes;
717     }
718   return 1;
719 }
720
721 static int
722 checkMultCaps ()
723 {
724   int k;
725   for (k = 0; k < table->lenBeginCaps; k++)
726     if (k >= srcmax - src ||
727         !checkAttr (currentInput[src + k], CTC_UpperCase, 0))
728       return 0;
729   return 1;
730 }
731
732 static int prevPrevType = 0;
733 static int nextType = 0;
734 static TranslationTableCharacterAttributes prevPrevAttr = 0;
735
736 static int
737 beginEmphasis (const TranslationTableOffset * offset)
738 {
739   if (src != startType)
740     {
741       wordCount = finishEmphasis = wordsMarked = 0;
742       startType = lastWord = src;
743       for (endType = src; endType < srcmax; endType++)
744         {
745           if ((typebuf[endType] & EMPHASIS) != curType)
746             break;
747           if (checkAttr (currentInput[endType - 1], CTC_Space, 0)
748               && !checkAttr (currentInput[endType], CTC_Space, 0))
749             {
750               lastWord = endType;
751               wordCount++;
752             }
753         }
754     }
755   if ((beforeAttributes & CTC_Letter) && (endType - startType) ==
756       1 && brailleIndicatorDefined (offset[singleLetter]))
757     return 1;
758   else
759     if ((beforeAttributes & CTC_Letter) && brailleIndicatorDefined
760         (offset[firstLetter]))
761     return 1;
762   else if (brailleIndicatorDefined (offset[lastWordBefore]))
763     {
764       markWords (offset);
765       return 0;
766     }
767   else
768     return (brailleIndicatorDefined (offset[firstWord]));
769   return 0;
770 }
771
772 static int
773 endEmphasis (const TranslationTableOffset * offset)
774 {
775   if (wordsMarked)
776     return 0;
777   if (prevPrevType != prevType && nextType != prevType &&
778       brailleIndicatorDefined (offset[singleLetter]))
779     return 0;
780   else
781     if ((finishEmphasis || (src < srcmax && ((findCharOrDots
782                                               (currentInput[src + 1],
783                                                0))->attributes &
784                                              CTC_Letter)))
785         && brailleIndicatorDefined (offset[lastLetter]))
786     return 1;
787   else
788     return (brailleIndicatorDefined (offset[lastWordAfter]));
789   return 0;
790 }
791
792 static int
793 doCompEmph ()
794 {
795   int endEmph;
796   for (endEmph = src; (typebuf[endEmph] & computer_braille) && endEmph
797        <= srcmax; endEmph++);
798   return doCompTrans (src, endEmph);
799 }
800
801 static int
802 insertBrailleIndicators (int finish)
803 {
804 /*Insert braille indicators such as italic, bold, capital, 
805 * letter, number, etc.*/
806   typedef enum
807   {
808     checkNothing,
809     checkBeginTypeform,
810     checkEndTypeform,
811     checkNumber,
812     checkLetter,
813     checkBeginMultCaps,
814     checkEndMultCaps,
815     checkSingleCap,
816     checkAll
817   } checkThis;
818   checkThis checkWhat = checkNothing;
819   int ok = 0;
820   int k;
821   if (finish == 2)
822     {
823       while (dest > 0 && (currentOutput[dest - 1] == 0 ||
824                           currentOutput[dest - 1] == B16))
825         dest--;
826       finishEmphasis = 1;
827       prevType = prevPrevType;
828       curType = plain_text;
829       checkWhat = checkEndTypeform;
830     }
831   else
832     {
833       if (src == prevSrc && !finish)
834         return 1;
835       if (src != prevSrc)
836         {
837           if (haveEmphasis && src < srcmax)
838             nextType = typebuf[src + 1] & EMPHASIS;
839           else
840             nextType = plain_text;
841           if (src > 2)
842             {
843               if (haveEmphasis)
844                 prevPrevType = typebuf[src - 2] & EMPHASIS;
845               else
846                 prevPrevType = plain_text;
847               prevPrevAttr =
848                 (findCharOrDots (currentInput[src - 2], 0))->attributes;
849             }
850           else
851             {
852               prevPrevType = plain_text;
853               prevPrevAttr = CTC_Space;
854             }
855           if (haveEmphasis && (typebuf[src] & EMPHASIS) != prevTypeform)
856             {
857               prevType = prevTypeform & EMPHASIS;
858               curType = typebuf[src] & EMPHASIS;
859               checkWhat = checkEndTypeform;
860             }
861           else if (!finish)
862             checkWhat = checkNothing;
863           else
864             checkWhat = checkNumber;
865         }
866       if (finish == 1)
867         checkWhat = checkNumber;
868     }
869   do
870     {
871       ok = 0;
872       switch (checkWhat)
873         {
874         case checkNothing:
875           ok = 0;
876           break;
877         case checkBeginTypeform:
878           if (haveEmphasis)
879             switch (curType)
880               {
881               case plain_text:
882                 ok = 0;
883                 break;
884               case italic:
885                 ok = beginEmphasis (&table->firstWordItal);
886                 curType = 0;
887                 break;
888               case bold:
889                 ok = beginEmphasis (&table->firstWordBold);
890                 curType = 0;
891                 break;
892               case underline:
893                 ok = beginEmphasis (&table->firstWordUnder);
894                 curType = 0;
895                 break;
896               case computer_braille:
897                 ok = 0;
898                 doCompEmph ();
899                 curType = 0;
900                 break;
901               case italic + underline:
902                 ok = beginEmphasis (&table->firstWordUnder);
903                 curType -= underline;
904                 break;
905               case italic + bold:
906                 ok = beginEmphasis (&table->firstWordBold);
907                 curType -= bold;
908                 break;
909               case italic + computer_braille:
910                 ok = 0;
911                 doCompEmph ();
912                 curType -= computer_braille;
913                 break;
914               case underline + bold:
915                 beginEmphasis (&table->firstWordBold);
916                 curType -= bold;
917                 break;
918               case underline + computer_braille:
919                 ok = 0;
920                 doCompEmph ();
921                 curType -= computer_braille;
922                 break;
923               case bold + computer_braille:
924                 ok = 0;
925                 doCompEmph ();
926                 curType -= computer_braille;
927                 break;
928               default:
929                 ok = 0;
930                 curType = 0;
931                 break;
932               }
933           if (!curType)
934             {
935               if (!finish)
936                 checkWhat = checkNothing;
937               else
938                 checkWhat = checkNumber;
939             }
940           break;
941         case checkEndTypeform:
942           if (haveEmphasis)
943             switch (prevType)
944               {
945               case plain_text:
946                 ok = 0;
947                 break;
948               case italic:
949                 ok = endEmphasis (&table->firstWordItal);
950                 prevType = 0;
951                 break;
952               case bold:
953                 ok = endEmphasis (&table->firstWordBold);
954                 prevType = 0;
955                 break;
956               case underline:
957                 ok = endEmphasis (&table->firstWordUnder);
958                 prevType = 0;
959                 break;
960               case computer_braille:
961                 ok = 0;
962                 prevType = 0;
963                 break;
964               case italic + underline:
965                 ok = endEmphasis (&table->firstWordUnder);
966                 prevType -= underline;
967                 break;
968               case italic + bold:
969                 ok = endEmphasis (&table->firstWordBold);
970                 prevType -= bold;
971                 break;
972               case italic + computer_braille:
973                 ok = 1;
974                 prevType -= computer_braille;
975                 break;
976               case underline + bold:
977                 ok = endEmphasis (&table->firstWordBold);
978                 prevType -= bold;
979                 break;
980               case underline + computer_braille:
981                 ok = 0;
982                 prevType -= computer_braille;
983                 break;
984               case bold + computer_braille:
985                 ok = endEmphasis (&table->firstWordBold);
986                 prevType -= bold;
987                 break;
988               default:
989                 ok = 0;
990                 prevType = 0;
991                 break;
992               }
993           if (prevType == plain_text)
994             {
995               checkWhat = checkBeginTypeform;
996               prevTypeform = typebuf[src] & EMPHASIS;
997             }
998           break;
999         case checkNumber:
1000           if (brailleIndicatorDefined
1001               (table->numberSign) &&
1002               checkAttr (currentInput[src], CTC_Digit, 0) &&
1003               (prevTransOpcode == CTO_ExactDots
1004                || !(beforeAttributes & CTC_Digit))
1005               && prevTransOpcode != CTO_MidNum)
1006             {
1007               ok = 1;
1008               checkWhat = checkNothing;
1009             }
1010           else
1011             checkWhat = checkLetter;
1012           break;
1013         case checkLetter:
1014           if (!brailleIndicatorDefined (table->letterSign))
1015             {
1016               ok = 0;
1017               checkWhat = checkBeginMultCaps;
1018               break;
1019             }
1020           if (transOpcode == CTO_Contraction)
1021             {
1022               ok = 1;
1023               checkWhat = checkBeginMultCaps;
1024               break;
1025             }
1026           if ((checkAttr (currentInput[src], CTC_Letter, 0)
1027                && !(beforeAttributes & CTC_Letter))
1028               && (!checkAttr (currentInput[src + 1], CTC_Letter, 0)
1029                   || (beforeAttributes & CTC_Digit)))
1030             {
1031               ok = 1;
1032               if (src > 0)
1033                 for (k = 0; k < table->noLetsignBeforeCount; k++)
1034                   if (currentInput[src - 1] == table->noLetsignBefore[k])
1035                     {
1036                       ok = 0;
1037                       break;
1038                     }
1039               for (k = 0; k < table->noLetsignCount; k++)
1040                 if (currentInput[src] == table->noLetsign[k])
1041                   {
1042                     ok = 0;
1043                     break;
1044                   }
1045               if ((src + 1) < srcmax)
1046                 for (k = 0; k < table->noLetsignAfterCount; k++)
1047                   if (currentInput[src + 1] == table->noLetsignAfter[k])
1048                     {
1049                       ok = 0;
1050                       break;
1051                     }
1052             }
1053           checkWhat = checkBeginMultCaps;
1054           break;
1055         case checkBeginMultCaps:
1056           if (brailleIndicatorDefined (table->beginCapitalSign) &&
1057               !(beforeAttributes & CTC_UpperCase) && checkMultCaps ())
1058             {
1059               ok = 1;
1060               if (table->capsNoCont)
1061                 dontContract = 1;
1062               checkWhat = checkNothing;
1063             }
1064           else
1065             checkWhat = checkSingleCap;
1066           break;
1067         case checkEndMultCaps:
1068           if (brailleIndicatorDefined (table->endCapitalSign) &&
1069               (prevPrevAttr & CTC_UpperCase)
1070               && (beforeAttributes & CTC_UpperCase)
1071               && checkAttr (currentInput[src], CTC_LowerCase, 0))
1072             {
1073               ok = 1;
1074               if (table->capsNoCont)
1075                 dontContract = 0;
1076             }
1077           checkWhat = checkNothing;
1078           break;
1079         case checkSingleCap:
1080           if (brailleIndicatorDefined (table->capitalSign) && src < srcmax
1081               && checkAttr (currentInput[src], CTC_UpperCase, 0) &&
1082               (!(beforeAttributes & CTC_UpperCase) ||
1083                table->beginCapitalSign == 0))
1084             {
1085               ok = 1;
1086               checkWhat = checkNothing;
1087             }
1088           checkWhat = checkEndMultCaps;
1089           break;
1090         default:
1091           ok = 0;
1092           checkWhat = checkNothing;
1093           break;
1094         }
1095       if (ok && indicRule != NULL)
1096         {
1097           if (!for_updatePositions
1098               (&indicRule->charsdots[0], 0, indicRule->dotslen))
1099             return 0;
1100           if (cursorStatus == 2)
1101             checkWhat = checkNothing;
1102         }
1103     }
1104   while (checkWhat != checkNothing);
1105   finishEmphasis = 0;
1106   return 1;
1107 }
1108
1109 static int
1110 onlyLettersBehind ()
1111 {
1112   /* Actually, spaces, then letters */
1113   int k;
1114   if (!(beforeAttributes & CTC_Space))
1115     return 0;
1116   for (k = src - 2; k >= 0; k--)
1117     {
1118       TranslationTableCharacterAttributes attr = (findCharOrDots
1119                                                   (currentInput[k],
1120                                                    0))->attributes;
1121       if ((attr & CTC_Space))
1122         continue;
1123       if ((attr & CTC_Letter))
1124         return 1;
1125       else
1126         return 0;
1127     }
1128   return 1;
1129 }
1130
1131 static int
1132 onlyLettersAhead ()
1133 {
1134   /* Actullly, spaces, then letters */
1135   int k;
1136   if (!(afterAttributes & CTC_Space))
1137     return 0;
1138   for (k = src + transCharslen + 1; k < srcmax; k++)
1139     {
1140       TranslationTableCharacterAttributes attr = (findCharOrDots
1141                                                   (currentInput[k],
1142                                                    0))->attributes;
1143       if ((attr & CTC_Space))
1144         continue;
1145       if ((attr & (CTC_Letter | CTC_LitDigit)))
1146         return 1;
1147       else
1148         return 0;
1149     }
1150   return 0;
1151 }
1152
1153 static int
1154 noCompbrlAhead ()
1155 {
1156   int start = src + transCharslen;
1157   int end;
1158   int curSrc;
1159   if (start >= srcmax)
1160     return 1;
1161   while (start < srcmax && checkAttr (currentInput[start], CTC_Space, 0))
1162     start++;
1163   if (start == srcmax || (transOpcode == CTO_JoinableWord && (!checkAttr
1164                                                               (currentInput
1165                                                                [start],
1166                                                                CTC_Letter |
1167                                                                CTC_Digit, 0)
1168                                                               ||
1169                                                               !checkAttr
1170                                                               (currentInput
1171                                                                [start - 1],
1172                                                                CTC_Space,
1173                                                                0))))
1174     return 1;
1175   end = start;
1176   while (end < srcmax && !checkAttr (currentInput[end], CTC_Space, 0))
1177     end++;
1178   if ((mode & (compbrlAtCursor | compbrlLeftCursor)) && cursorPosition
1179       >= start && cursorPosition < end)
1180     return 0;
1181   /* Look ahead for rules with CTO_CompBrl */
1182   for (curSrc = start; curSrc < end; curSrc++)
1183     {
1184       int length = srcmax - curSrc;
1185       int tryThis;
1186       const TranslationTableCharacter *character1;
1187       const TranslationTableCharacter *character2;
1188       int k;
1189       character1 = findCharOrDots (currentInput[curSrc], 0);
1190       for (tryThis = 0; tryThis < 2; tryThis++)
1191         {
1192           TranslationTableOffset ruleOffset = 0;
1193           TranslationTableRule *testRule;
1194           unsigned long int makeHash = 0;
1195           switch (tryThis)
1196             {
1197             case 0:
1198               if (!(length >= 2))
1199                 break;
1200               /*Hash function optimized for forward translation */
1201               makeHash = (unsigned long int) character1->lowercase << 8;
1202               character2 = findCharOrDots (currentInput[curSrc + 1], 0);
1203               makeHash += (unsigned long int) character2->lowercase;
1204               makeHash %= HASHNUM;
1205               ruleOffset = table->forRules[makeHash];
1206               break;
1207             case 1:
1208               if (!(length >= 1))
1209                 break;
1210               length = 1;
1211               ruleOffset = character1->otherRules;
1212               break;
1213             }
1214           while (ruleOffset)
1215             {
1216               testRule =
1217                 (TranslationTableRule *) & table->ruleArea[ruleOffset];
1218               for (k = 0; k < testRule->charslen; k++)
1219                 {
1220                   character1 = findCharOrDots (testRule->charsdots[k], 0);
1221                   character2 = findCharOrDots (currentInput[curSrc + k], 0);
1222                   if (character1->lowercase != character2->lowercase)
1223                     break;
1224                 }
1225               if (tryThis == 1 || k == testRule->charslen)
1226                 {
1227                   if (testRule->opcode == CTO_CompBrl
1228                       || testRule->opcode == CTO_Literal)
1229                     return 0;
1230                 }
1231               ruleOffset = testRule->charsnext;
1232             }
1233         }
1234     }
1235   return 1;
1236 }
1237
1238 static widechar const *repwordStart;
1239 static int repwordLength;
1240 static int
1241 isRepeatedWord ()
1242 {
1243   int start;
1244   if (src == 0 || !checkAttr (currentInput[src - 1], CTC_Letter, 0))
1245     return 0;
1246   if ((src + transCharslen) >= srcmax || !checkAttr (currentInput[src +
1247                                                                   transCharslen],
1248                                                      CTC_Letter, 0))
1249     return 0;
1250   for (start = src - 2;
1251        start >= 0 && checkAttr (currentInput[start], CTC_Letter, 0); start--);
1252   start++;
1253   repwordStart = &currentInput[start];
1254   repwordLength = src - start;
1255   if (compareChars (repwordStart, &currentInput[src
1256                                                 + transCharslen],
1257                     repwordLength, 0))
1258     return 1;
1259   return 0;
1260 }
1261
1262 static void
1263 for_selectRule ()
1264 {
1265 /*check for valid Translations. Return value is in transRule. */
1266   int length = srcmax - src;
1267   int tryThis;
1268   const TranslationTableCharacter *character2;
1269   int k;
1270   curCharDef = findCharOrDots (currentInput[src], 0);
1271   for (tryThis = 0; tryThis < 3; tryThis++)
1272     {
1273       TranslationTableOffset ruleOffset = 0;
1274       unsigned long int makeHash = 0;
1275       switch (tryThis)
1276         {
1277         case 0:
1278           if (!(length >= 2))
1279             break;
1280           /*Hash function optimized for forward translation */
1281           makeHash = (unsigned long int) curCharDef->lowercase << 8;
1282           character2 = findCharOrDots (currentInput[src + 1], 0);
1283           makeHash += (unsigned long int) character2->lowercase;
1284           makeHash %= HASHNUM;
1285           ruleOffset = table->forRules[makeHash];
1286           break;
1287         case 1:
1288           if (!(length >= 1))
1289             break;
1290           length = 1;
1291           ruleOffset = curCharDef->otherRules;
1292           break;
1293         case 2:         /*No rule found */
1294           transRule = &pseudoRule;
1295           transOpcode = pseudoRule.opcode = CTO_None;
1296           transCharslen = pseudoRule.charslen = 1;
1297           pseudoRule.charsdots[0] = currentInput[src];
1298           pseudoRule.dotslen = 0;
1299           return;
1300           break;
1301         }
1302       while (ruleOffset)
1303         {
1304           transRule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
1305           transOpcode = transRule->opcode;
1306           transCharslen = transRule->charslen;
1307           if (tryThis == 1 || ((transCharslen <= length) && validMatch ()))
1308             {
1309               /* check this rule */
1310               setAfter (transCharslen);
1311               if ((!transRule->after || (beforeAttributes
1312                                          & transRule->after)) &&
1313                   (!transRule->before || (afterAttributes
1314                                           & transRule->before)))
1315                 switch (transOpcode)
1316                   {             /*check validity of this Translation */
1317                   case CTO_Space:
1318                   case CTO_Letter:
1319                   case CTO_UpperCase:
1320                   case CTO_LowerCase:
1321                   case CTO_Digit:
1322                   case CTO_LitDigit:
1323                   case CTO_Punctuation:
1324                   case CTO_Math:
1325                   case CTO_Sign:
1326                   case CTO_Hyphen:
1327                   case CTO_Replace:
1328                   case CTO_CompBrl:
1329                   case CTO_Literal:
1330                     return;
1331                   case CTO_Repeated:
1332                     if ((mode & (compbrlAtCursor | compbrlLeftCursor))
1333                         && src >= compbrlStart && src <= compbrlEnd)
1334                       break;
1335                     return;
1336                   case CTO_RepWord:
1337                     if (dontContract || (mode & noContractions))
1338                       break;
1339                     if (isRepeatedWord ())
1340                       return;
1341                     break;
1342                   case CTO_NoCont:
1343                     if (dontContract || (mode & noContractions))
1344                       break;
1345                     return;
1346                   case CTO_Syllable:
1347                     transOpcode = CTO_Always;
1348                   case CTO_Always:
1349                     if (dontContract || (mode & noContractions))
1350                       break;
1351                     return;
1352                   case CTO_ExactDots:
1353                     return;
1354                   case CTO_NoCross:
1355                     if (syllableBreak ())
1356                       break;
1357                     return;
1358                   case CTO_Context:
1359                     if (!srcIncremented || !passDoTest ())
1360                       break;
1361                     return;
1362                   case CTO_LargeSign:
1363                     if (dontContract || (mode & noContractions))
1364                       break;
1365                     if (!((beforeAttributes & (CTC_Space
1366                                                | CTC_Punctuation))
1367                           || onlyLettersBehind ())
1368                         || !((afterAttributes & CTC_Space)
1369                              || prevTransOpcode == CTO_LargeSign)
1370                         || (afterAttributes & CTC_Letter)
1371                         || !noCompbrlAhead ())
1372                       transOpcode = CTO_Always;
1373                     return;
1374                   case CTO_WholeWord:
1375                     if (dontContract || (mode & noContractions))
1376                       break;
1377                   case CTO_Contraction:
1378                     if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
1379                         && (afterAttributes & (CTC_Space | CTC_Punctuation)))
1380                       return;
1381                     break;
1382                   case CTO_PartWord:
1383                     if (dontContract || (mode & noContractions))
1384                       break;
1385                     if ((beforeAttributes & CTC_Letter)
1386                         || (afterAttributes & CTC_Letter))
1387                       return;
1388                     break;
1389                   case CTO_JoinNum:
1390                     if (dontContract || (mode & noContractions))
1391                       break;
1392                     if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
1393                         &&
1394                         (afterAttributes & CTC_Space) &&
1395                         (dest + transRule->dotslen < destmax))
1396                       {
1397                         int cursrc = src + transCharslen + 1;
1398                         while (cursrc < srcmax)
1399                           {
1400                             if (!checkAttr
1401                                 (currentInput[cursrc], CTC_Space, 0))
1402                               {
1403                                 if (checkAttr
1404                                     (currentInput[cursrc], CTC_Digit, 0))
1405                                   return;
1406                                 break;
1407                               }
1408                             cursrc++;
1409                           }
1410                       }
1411                     break;
1412                   case CTO_LowWord:
1413                     if (dontContract || (mode & noContractions))
1414                       break;
1415                     if ((beforeAttributes & CTC_Space)
1416                         && (afterAttributes & CTC_Space)
1417                         && (prevTransOpcode != CTO_JoinableWord))
1418                       return;
1419                     break;
1420                   case CTO_JoinableWord:
1421                     if (dontContract || (mode & noContractions))
1422                       break;
1423                     if (beforeAttributes & (CTC_Space | CTC_Punctuation)
1424                         && onlyLettersAhead () && noCompbrlAhead ())
1425                       return;
1426                     break;
1427                   case CTO_SuffixableWord:
1428                     if (dontContract || (mode & noContractions))
1429                       break;
1430                     if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
1431                         && (afterAttributes &
1432                             (CTC_Space | CTC_Letter | CTC_Punctuation)))
1433                       return;
1434                     break;
1435                   case CTO_PrefixableWord:
1436                     if (dontContract || (mode & noContractions))
1437                       break;
1438                     if ((beforeAttributes &
1439                          (CTC_Space | CTC_Letter | CTC_Punctuation))
1440                         && (afterAttributes & (CTC_Space | CTC_Punctuation)))
1441                       return;
1442                     break;
1443                   case CTO_BegWord:
1444                     if (dontContract || (mode & noContractions))
1445                       break;
1446                     if ((beforeAttributes & (CTC_Space | CTC_Punctuation))
1447                         && (afterAttributes & CTC_Letter))
1448                       return;
1449                     break;
1450                   case CTO_BegMidWord:
1451                     if (dontContract || (mode & noContractions))
1452                       break;
1453                     if ((beforeAttributes &
1454                          (CTC_Letter | CTC_Space | CTC_Punctuation))
1455                         && (afterAttributes & CTC_Letter))
1456                       return;
1457                     break;
1458                   case CTO_MidWord:
1459                     if (dontContract || (mode & noContractions))
1460                       break;
1461                     if (beforeAttributes & CTC_Letter
1462                         && afterAttributes & CTC_Letter)
1463                       return;
1464                     break;
1465                   case CTO_MidEndWord:
1466                     if (dontContract || (mode & noContractions))
1467                       break;
1468                     if (beforeAttributes & CTC_Letter
1469                         && afterAttributes & (CTC_Letter | CTC_Space |
1470                                               CTC_Punctuation))
1471                       return;
1472                     break;
1473                   case CTO_EndWord:
1474                     if (dontContract || (mode & noContractions))
1475                       break;
1476                     if (beforeAttributes & CTC_Letter
1477                         && afterAttributes & (CTC_Space | CTC_Punctuation))
1478                       return;
1479                     break;
1480                   case CTO_BegNum:
1481                     if (beforeAttributes & (CTC_Space | CTC_Punctuation)
1482                         && afterAttributes & CTC_Digit)
1483                       return;
1484                     break;
1485                   case CTO_MidNum:
1486                     if (prevTransOpcode != CTO_ExactDots
1487                         && beforeAttributes & CTC_Digit
1488                         && afterAttributes & CTC_Digit)
1489                       return;
1490                     break;
1491                   case CTO_EndNum:
1492                     if (beforeAttributes & CTC_Digit &&
1493                         prevTransOpcode != CTO_ExactDots)
1494                       return;
1495                     break;
1496                   case CTO_DecPoint:
1497                     if (!(afterAttributes & CTC_Digit))
1498                       break;
1499                     if (beforeAttributes & CTC_Digit)
1500                       transOpcode = CTO_MidNum;
1501                     return;
1502                   case CTO_PrePunc:
1503                     if (!checkAttr (currentInput[src], CTC_Punctuation, 0)
1504                         || (src > 0
1505                             && checkAttr (currentInput[src - 1], CTC_Letter,
1506                                           0)))
1507                       break;
1508                     for (k = src + transCharslen; k < srcmax; k++)
1509                       {
1510                         if (checkAttr
1511                             (currentInput[k], (CTC_Letter | CTC_Digit), 0))
1512                           return;
1513                         if (checkAttr (currentInput[k], CTC_Space, 0))
1514                           break;
1515                       }
1516                     break;
1517                   case CTO_PostPunc:
1518                     if (!checkAttr (currentInput[src], CTC_Punctuation, 0)
1519                         || (src < (srcmax - 1)
1520                             && checkAttr (currentInput[src + 1], CTC_Letter,
1521                                           0)))
1522                       break;
1523                     for (k = src; k >= 0; k--)
1524                       {
1525                         if (checkAttr
1526                             (currentInput[k], (CTC_Letter | CTC_Digit), 0))
1527                           return;
1528                         if (checkAttr (currentInput[k], CTC_Space, 0))
1529                           break;
1530                       }
1531                     break;
1532                   default:
1533                     break;
1534                   }
1535             }
1536 /*Done with checking this rule */
1537           ruleOffset = transRule->charsnext;
1538         }
1539     }
1540 }
1541
1542 static int
1543 undefinedCharacter (widechar c)
1544 {
1545 /*Display an undefined character in the output buffer*/
1546   int k;
1547   char *display;
1548   widechar displayDots[20];
1549   if (table->undefined)
1550     {
1551       TranslationTableRule *transRule = (TranslationTableRule *)
1552         & table->ruleArea[table->undefined];
1553       if (!for_updatePositions
1554           (&transRule->charsdots[transRule->charslen],
1555            transRule->charslen, transRule->dotslen))
1556         return 0;
1557       return 1;
1558     }
1559   display = showString (&c, 1);
1560   for (k = 0; k < strlen (display); k++)
1561     displayDots[k] = getDotsForChar (display[k]);
1562   if (!for_updatePositions (displayDots, 1, strlen(display)))
1563     return 0;
1564   return 1;
1565 }
1566
1567 static int
1568 putCharacter (widechar character)
1569 {
1570 /*Insert the dots equivalent of a character into the output buffer */
1571   TranslationTableCharacter *chardef;
1572   TranslationTableOffset offset;
1573   if (cursorStatus == 2)
1574     return 1;
1575   chardef = (findCharOrDots (character, 0));
1576   if ((chardef->attributes & CTC_Letter) && (chardef->attributes &
1577                                              CTC_UpperCase))
1578     chardef = findCharOrDots (chardef->lowercase, 0);
1579   offset = chardef->definitionRule;
1580   if (offset)
1581     {
1582       const TranslationTableRule *rule = (TranslationTableRule *)
1583         & table->ruleArea[offset];
1584       if (rule->dotslen)
1585         return for_updatePositions (&rule->charsdots[1], 1, rule->dotslen);
1586       {
1587         widechar d = getDotsForChar (character);
1588         return for_updatePositions (&d, 1, 1);
1589       }
1590     }
1591   return undefinedCharacter (character);
1592 }
1593
1594 static int
1595 putCharacters (const widechar * characters, int count)
1596 {
1597 /*Insert the dot equivalents of a series of characters in the output 
1598 * buffer */
1599   int k;
1600   for (k = 0; k < count; k++)
1601     if (!putCharacter (characters[k]))
1602       return 0;
1603   return 1;
1604 }
1605
1606 static int
1607 doCompbrl ()
1608 {
1609 /*Handle strings containing substrings defined by the compbrl opcode*/
1610   int stringStart, stringEnd;
1611   if (checkAttr (currentInput[src], CTC_Space, 0))
1612     return 1;
1613   if (destword)
1614     {
1615       src = srcword;
1616       dest = destword;
1617     }
1618   else
1619     {
1620       src = 0;
1621       dest = 0;
1622     }
1623   for (stringStart = src; stringStart >= 0; stringStart--)
1624     if (checkAttr (currentInput[stringStart], CTC_Space, 0))
1625       break;
1626   stringStart++;
1627   for (stringEnd = src; stringEnd < srcmax; stringEnd++)
1628     if (checkAttr (currentInput[stringEnd], CTC_Space, 0))
1629       break;
1630   return (doCompTrans (stringStart, stringEnd));
1631 }
1632
1633 static int
1634 putCompChar (widechar character)
1635 {
1636 /*Insert the dots equivalent of a character into the output buffer */
1637   TranslationTableOffset offset = (findCharOrDots
1638                                    (character, 0))->definitionRule;
1639   if (offset)
1640     {
1641       const TranslationTableRule *rule = (TranslationTableRule *)
1642         & table->ruleArea[offset];
1643       if (rule->dotslen)
1644         return for_updatePositions (&rule->charsdots[1], 1, rule->dotslen);
1645       {
1646         widechar d = getDotsForChar (character);
1647         return for_updatePositions (&d, 1, 1);
1648       }
1649     }
1650   return undefinedCharacter (character);
1651 }
1652
1653 static int
1654 doCompTrans (int start, int end)
1655 {
1656   int k;
1657   int haveEndsegment = 0;
1658   if (cursorStatus != 2 && brailleIndicatorDefined (table->begComp))
1659     if (!for_updatePositions
1660         (&indicRule->charsdots[0], 0, indicRule->dotslen))
1661       return 0;
1662   for (k = start; k < end; k++)
1663     {
1664       TranslationTableOffset compdots = 0;
1665       if (currentInput[k] == ENDSEGMENT)
1666         {
1667           haveEndsegment = 1;
1668           continue;
1669         }
1670       src = k;
1671       if (currentInput[k] < 256)
1672         compdots = table->compdotsPattern[currentInput[k]];
1673       if (compdots != 0)
1674         {
1675           transRule = (TranslationTableRule *) & table->ruleArea[compdots];
1676           if (!for_updatePositions
1677               (&transRule->charsdots[transRule->charslen],
1678                transRule->charslen, transRule->dotslen))
1679             return 0;
1680         }
1681       else if (!putCompChar (currentInput[k]))
1682         return 0;
1683     }
1684   if (cursorStatus != 2 && brailleIndicatorDefined (table->endComp))
1685     if (!for_updatePositions
1686         (&indicRule->charsdots[0], 0, indicRule->dotslen))
1687       return 0;
1688   src = end;
1689   if (haveEndsegment)
1690     {
1691       widechar endSegment = ENDSEGMENT;
1692       if (!for_updatePositions (&endSegment, 0, 1))
1693         return 0;
1694     }
1695   return 1;
1696 }
1697
1698 static int
1699 doNocont ()
1700 {
1701 /*Handle strings containing substrings defined by the nocont opcode*/
1702   if (checkAttr (currentInput[src], CTC_Space, 0) || dontContract
1703       || (mode & noContractions))
1704     return 1;
1705   if (destword)
1706     {
1707       src = srcword;
1708       dest = destword;
1709     }
1710   else
1711     {
1712       src = 0;
1713       dest = 0;
1714     }
1715   dontContract = 1;
1716   return 1;
1717 }
1718
1719 static int
1720 markSyllables ()
1721 {
1722   int k;
1723   int syllableMarker = 0;
1724   int currentMark = 0;
1725   if (typebuf == NULL || !table->syllables)
1726     return 1;
1727   src = 0;
1728   while (src < srcmax)
1729     {                           /*the main multipass translation loop */
1730       int length = srcmax - src;
1731       const TranslationTableCharacter *character = findCharOrDots
1732         (currentInput[src], 0);
1733       const TranslationTableCharacter *character2;
1734       int tryThis = 0;
1735       while (tryThis < 3)
1736         {
1737           TranslationTableOffset ruleOffset = 0;
1738           unsigned long int makeHash = 0;
1739           switch (tryThis)
1740             {
1741             case 0:
1742               if (!(length >= 2))
1743                 break;
1744               makeHash = (unsigned long int) character->lowercase << 8;
1745               character2 = findCharOrDots (currentInput[src + 1], 0);
1746               makeHash += (unsigned long int) character2->lowercase;
1747               makeHash %= HASHNUM;
1748               ruleOffset = table->forRules[makeHash];
1749               break;
1750             case 1:
1751               if (!(length >= 1))
1752                 break;
1753               length = 1;
1754               ruleOffset = character->otherRules;
1755               break;
1756             case 2:             /*No rule found */
1757               transOpcode = CTO_Always;
1758               ruleOffset = 0;
1759               break;
1760             }
1761           while (ruleOffset)
1762             {
1763               transRule =
1764                 (TranslationTableRule *) & table->ruleArea[ruleOffset];
1765               transOpcode = transRule->opcode;
1766               transCharslen = transRule->charslen;
1767               if (tryThis == 1 || (transCharslen <= length &&
1768                                    compareChars (&transRule->
1769                                                  charsdots[0],
1770                                                  &currentInput[src],
1771                                                  transCharslen, 0)))
1772                 {
1773                   if (transOpcode == CTO_Syllable)
1774                     {
1775                       tryThis = 4;
1776                       break;
1777                     }
1778                 }
1779               ruleOffset = transRule->charsnext;
1780             }
1781           tryThis++;
1782         }
1783       switch (transOpcode)
1784         {
1785         case CTO_Always:
1786           if (src >= srcmax)
1787             return 0;
1788           if (typebuf != NULL)
1789             typebuf[src++] |= currentMark;
1790           break;
1791         case CTO_Syllable:
1792           syllableMarker++;
1793           if (syllableMarker > 3)
1794             syllableMarker = 1;
1795           currentMark = syllableMarker << 6;
1796           /*The syllable marker is bits 6 and 7 of typebuf. */
1797           if ((src + transCharslen) > srcmax)
1798             return 0;
1799           for (k = 0; k < transCharslen; k++)
1800             typebuf[src++] |= currentMark;
1801           break;
1802         default:
1803           break;
1804         }
1805     }
1806   return 1;
1807 }
1808
1809 static int
1810 translateString ()
1811 {
1812 /*Main translation routine */
1813   int k;
1814   markSyllables ();
1815   srcword = 0;
1816   destword = 0;                 /* last word translated */
1817   dontContract = 0;
1818   prevTransOpcode = CTO_None;
1819   wordsMarked = 0;
1820   prevType = prevPrevType = curType = nextType = prevTypeform = plain_text;
1821   startType = prevSrc = -1;
1822   src = dest = 0;
1823   srcIncremented = 1;
1824   memset (passVariables, 0, sizeof(int) * NUMVAR);
1825   if (typebuf && table->capitalSign)
1826     for (k = 0; k < srcmax; k++)
1827       if (checkAttr (currentInput[k], CTC_UpperCase, 0))
1828         typebuf[k] |= capsemph;
1829   while (src < srcmax)
1830     {                           /*the main translation loop */
1831       setBefore ();
1832       if (!insertBrailleIndicators (0))
1833         goto failure;
1834       if (src >= srcmax)
1835         break;
1836       if (!insertIndicators ())
1837         goto failure;
1838       for_selectRule ();
1839       if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
1840         appliedRules[appliedRulesCount++] = transRule;
1841       srcIncremented = 1;
1842       prevSrc = src;
1843       switch (transOpcode)        /*Rules that pre-empt context and swap */
1844         {
1845         case CTO_CompBrl:
1846         case CTO_Literal:
1847           if (!doCompbrl ())
1848             goto failure;
1849           continue;
1850         default:
1851           break;
1852         }
1853       if (!insertBrailleIndicators (1))
1854         goto failure;
1855       if (transOpcode == CTO_Context || findAttribOrSwapRules ())
1856         switch (transOpcode)
1857           {
1858           case CTO_Context:
1859             if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
1860               appliedRules[appliedRulesCount++] = transRule;
1861             if (!passDoAction ())
1862               goto failure;
1863             if (endReplace == src)
1864               srcIncremented = 0;
1865             src = endReplace;
1866             continue;
1867           default:
1868             break;
1869           }
1870
1871 /*Processing before replacement*/
1872       switch (transOpcode)
1873         {
1874         case CTO_EndNum:
1875           if (table->letterSign && checkAttr (currentInput[src],
1876                                               CTC_Letter, 0))
1877             dest--;
1878           break;
1879         case CTO_Repeated:
1880         case CTO_Space:
1881           dontContract = 0;
1882           break;
1883         case CTO_LargeSign:
1884           if (prevTransOpcode == CTO_LargeSign)
1885           {
1886             int hasEndSegment = 0;
1887             while (dest > 0 && checkAttr (currentOutput[dest - 1], CTC_Space, 1))
1888             {
1889               if (currentOutput[dest - 1] == ENDSEGMENT)
1890               {
1891                 hasEndSegment = 1;
1892               }
1893               dest--;
1894             }
1895             if (hasEndSegment != 0)
1896             {
1897               currentOutput[dest] = 0xffff;
1898               dest++;
1899             }
1900           }
1901           break;
1902         case CTO_DecPoint:
1903           if (table->numberSign)
1904             {
1905               TranslationTableRule *numRule = (TranslationTableRule *)
1906                 & table->ruleArea[table->numberSign];
1907               if (!for_updatePositions
1908                   (&numRule->charsdots[numRule->charslen],
1909                    numRule->charslen, numRule->dotslen))
1910                 goto failure;
1911             }
1912           transOpcode = CTO_MidNum;
1913           break;
1914         case CTO_NoCont:
1915           if (!dontContract)
1916             doNocont ();
1917           continue;
1918         default:
1919           break;
1920         }                       /*end of action */
1921
1922       /* replacement processing */
1923       switch (transOpcode)
1924         {
1925         case CTO_Replace:
1926           src += transCharslen;
1927           if (!putCharacters
1928               (&transRule->charsdots[transCharslen], transRule->dotslen))
1929             goto failure;
1930           break;
1931         case CTO_None:
1932           if (!undefinedCharacter (currentInput[src]))
1933             goto failure;
1934           src++;
1935           break;
1936         case CTO_UpperCase:
1937           /* Only needs special handling if not within compbrl and
1938            *the table defines a capital sign. */
1939           if (!
1940               (mode & (compbrlAtCursor | compbrlLeftCursor) && src >=
1941                compbrlStart
1942                && src <= compbrlEnd) && (transRule->dotslen == 1
1943                                          && table->capitalSign))
1944             {
1945               putCharacter (curCharDef->lowercase);
1946               src++;
1947               break;
1948             }
1949         default:
1950           if (cursorStatus == 2)
1951             cursorStatus = 1;
1952           else
1953             {
1954               if (transRule->dotslen)
1955                 {
1956                   if (!for_updatePositions
1957                       (&transRule->charsdots[transCharslen],
1958                        transCharslen, transRule->dotslen))
1959                     goto failure;
1960                 }
1961               else
1962                 {
1963                   for (k = 0; k < transCharslen; k++)
1964                     {
1965                       if (!putCharacter (currentInput[src]))
1966                         goto failure;
1967                       src++;
1968                     }
1969                 }
1970               if (cursorStatus == 2)
1971                 cursorStatus = 1;
1972               else if (transRule->dotslen)
1973                 src += transCharslen;
1974             }
1975           break;
1976         }
1977
1978       /* processing after replacement */
1979       switch (transOpcode)
1980         {
1981         case CTO_Repeated:
1982           {
1983             /* Skip repeated characters. */
1984             int srclim = srcmax - transCharslen;
1985             if (mode & (compbrlAtCursor | compbrlLeftCursor) &&
1986                 compbrlStart < srclim)
1987               /* Don't skip characters from compbrlStart onwards. */
1988               srclim = compbrlStart - 1;
1989             while ((src <= srclim)
1990                    && compareChars (&transRule->charsdots[0],
1991                                     &currentInput[src], transCharslen, 0))
1992               {
1993                 /* Map skipped input positions to the previous output position. */
1994                 if (outputPositions != NULL)
1995                   {
1996                     int tcc;
1997                     for (tcc = 0; tcc < transCharslen; tcc++)
1998                       outputPositions[prevSrcMapping[src + tcc]] = dest - 1;
1999                   }
2000                 if (!cursorStatus && src <= cursorPosition
2001                     && cursorPosition < src + transCharslen)
2002                   {
2003                     cursorStatus = 1;
2004                     cursorPosition = dest - 1;
2005                   }
2006                 src += transCharslen;
2007               }
2008             break;
2009           }
2010         case CTO_RepWord:
2011           {
2012             /* Skip repeated characters. */
2013             int srclim = srcmax - transCharslen;
2014             if (mode & (compbrlAtCursor | compbrlLeftCursor) &&
2015                 compbrlStart < srclim)
2016               /* Don't skip characters from compbrlStart onwards. */
2017               srclim = compbrlStart - 1;
2018             while ((src <= srclim)
2019                    && compareChars (repwordStart,
2020                                     &currentInput[src], repwordLength, 0))
2021               {
2022                 /* Map skipped input positions to the previous output position. */
2023                 if (outputPositions != NULL)
2024                   {
2025                     int tcc;
2026                     for (tcc = 0; tcc < transCharslen; tcc++)
2027                       outputPositions[prevSrcMapping[src + tcc]] = dest - 1;
2028                   }
2029                 if (!cursorStatus && src <= cursorPosition
2030                     && cursorPosition < src + transCharslen)
2031                   {
2032                     cursorStatus = 1;
2033                     cursorPosition = dest - 1;
2034                   }
2035                 src += repwordLength + transCharslen;
2036               }
2037             src -= transCharslen;
2038             break;
2039           }
2040         case CTO_JoinNum:
2041         case CTO_JoinableWord:
2042           while (src < srcmax
2043                  && checkAttr (currentInput[src], CTC_Space, 0) &&
2044                  currentInput[src] != ENDSEGMENT)
2045             src++;
2046           break;
2047         default:
2048           break;
2049         }
2050       if (((src > 0) && checkAttr (currentInput[src - 1], CTC_Space, 0)
2051            && (transOpcode != CTO_JoinableWord)))
2052         {
2053           srcword = src;
2054           destword = dest;
2055         }
2056       if (srcSpacing != NULL && srcSpacing[src] >= '0' && srcSpacing[src] <=
2057           '9')
2058         destSpacing[dest] = srcSpacing[src];
2059       if ((transOpcode >= CTO_Always && transOpcode <= CTO_None) ||
2060           (transOpcode >= CTO_Digit && transOpcode <= CTO_LitDigit))
2061         prevTransOpcode = transOpcode;
2062     }                           /*end of translation loop */
2063   if (haveEmphasis && !wordsMarked && prevPrevType != plain_text)
2064     insertBrailleIndicators (2);
2065 failure:
2066   if (destword != 0 && src < srcmax
2067       && !checkAttr (currentInput[src], CTC_Space, 0))
2068     {
2069       src = srcword;
2070       dest = destword;
2071     }
2072   if (src < srcmax)
2073     {
2074       while (checkAttr (currentInput[src], CTC_Space, 0))
2075         if (++src == srcmax)
2076           break;
2077     }
2078   realInlen = src;
2079   return 1;
2080 }                               /*first pass translation completed */
2081
2082 int EXPORT_CALL
2083 lou_hyphenate (const char *tableList, const widechar
2084                * inbuf, int inlen, char *hyphens, int mode)
2085 {
2086 #define HYPHSTRING 100
2087   widechar workingBuffer[HYPHSTRING];
2088   int k, kk;
2089   int wordStart;
2090   int wordEnd;
2091   table = lou_getTable (tableList);
2092   if (table == NULL || inbuf == NULL || hyphens
2093       == NULL || table->hyphenStatesArray == 0 || inlen >= HYPHSTRING)
2094     return 0;
2095   if (mode != 0)
2096     {
2097       k = inlen;
2098       kk = HYPHSTRING;
2099       if (!lou_backTranslate (tableList, inbuf, &k,
2100                               &workingBuffer[0],
2101                               &kk, NULL, NULL, NULL, NULL, NULL, 0))
2102         return 0;
2103     }
2104   else
2105     {
2106       memcpy (&workingBuffer[0], inbuf, CHARSIZE * inlen);
2107       kk = inlen;
2108     }
2109   for (wordStart = 0; wordStart < kk; wordStart++)
2110     if (((findCharOrDots (workingBuffer[wordStart], 0))->attributes &
2111          CTC_Letter))
2112       break;
2113   if (wordStart == kk)
2114     return 0;
2115   for (wordEnd = kk - 1; wordEnd >= 0; wordEnd--)
2116     if (((findCharOrDots (workingBuffer[wordEnd], 0))->attributes &
2117          CTC_Letter))
2118       break;
2119   for (k = wordStart; k <= wordEnd; k++)
2120     {
2121       TranslationTableCharacter *c = findCharOrDots (workingBuffer[k], 0);
2122       if (!(c->attributes & CTC_Letter))
2123         return 0;
2124     }
2125   if (!hyphenate
2126       (&workingBuffer[wordStart], wordEnd - wordStart + 1,
2127        &hyphens[wordStart]))
2128     return 0;
2129   for (k = 0; k <= wordStart; k++)
2130     hyphens[k] = '0';
2131   if (mode != 0)
2132     {
2133       widechar workingBuffer2[HYPHSTRING];
2134       int outputPos[HYPHSTRING];
2135       char hyphens2[HYPHSTRING];
2136       kk = wordEnd - wordStart + 1;
2137       k = HYPHSTRING;
2138       if (!lou_translate (tableList, &workingBuffer[wordStart], &kk,
2139                           &workingBuffer2[0], &k, NULL,
2140                           NULL, &outputPos[0], NULL, NULL, 0))
2141         return 0;
2142       for (kk = 0; kk < k; kk++)
2143         {
2144           int hyphPos = outputPos[kk];
2145           if (hyphPos > k || hyphPos < 0)
2146             break;
2147           if (hyphens[wordStart + kk] & 1)
2148             hyphens2[hyphPos] = '1';
2149           else
2150             hyphens2[hyphPos] = '0';
2151         }
2152       for (kk = wordStart; kk < wordStart + k; kk++)
2153         if (!table->noBreak || hyphens2[kk] == '0')
2154           hyphens[kk] = hyphens2[kk];
2155         else
2156           {
2157             TranslationTableRule *noBreakRule = (TranslationTableRule *)
2158               & table->ruleArea[table->noBreak];
2159             int kkk;
2160             if (kk > 0)
2161               for (kkk = 0; kkk < noBreakRule->charslen; kkk++)
2162                 if (workingBuffer2[kk - 1] == noBreakRule->charsdots[kkk])
2163                   {
2164                     hyphens[kk] = '0';
2165                     break;
2166                   }
2167             for (kkk = 0; kkk < noBreakRule->dotslen; kkk++);
2168             if (workingBuffer2[kk] ==
2169                 noBreakRule->charsdots[noBreakRule->charslen + kkk])
2170               {
2171                 hyphens[kk] = '0';
2172                 break;
2173               }
2174           }
2175     }
2176   for (k = 0; k < inlen; k++)
2177     if (hyphens[k] & 1)
2178       hyphens[k] = '1';
2179     else
2180       hyphens[k] = '0';
2181   hyphens[inlen] = 0;
2182   return 1;
2183 }
2184
2185 int EXPORT_CALL
2186 lou_dotsToChar (const char *tableList, widechar * inbuf, widechar * outbuf,
2187                 int length, int mode)
2188 {
2189   int k;
2190   widechar dots;
2191   if (tableList == NULL || inbuf == NULL || outbuf == NULL)
2192     return 0;
2193   if ((mode & otherTrans))
2194     return other_dotsToChar (tableList, inbuf, outbuf, length, mode);
2195   table = lou_getTable (tableList);
2196   if (table == NULL || length <= 0)
2197     return 0;
2198   for (k = 0; k < length; k++)
2199     {
2200       dots = inbuf[k];
2201       if (!(dots & B16) && (dots & 0xff00) == 0x2800)   /*Unicode braille */
2202         dots = (dots & 0x00ff) | B16;
2203       outbuf[k] = getCharFromDots (dots);
2204     }
2205   return 1;
2206 }
2207
2208 int EXPORT_CALL
2209 lou_charToDots (const char *tableList, const widechar * inbuf, widechar *
2210                 outbuf, int length, int mode)
2211 {
2212   int k;
2213   if (tableList == NULL || inbuf == NULL || outbuf == NULL)
2214     return 0;
2215   if ((mode & otherTrans))
2216     return other_charToDots (tableList, inbuf, outbuf, length, mode);
2217
2218   table = lou_getTable (tableList);
2219   if (table == NULL || length <= 0)
2220     return 0;
2221   for (k = 0; k < length; k++)
2222     if ((mode & ucBrl))
2223       outbuf[k] = ((getDotsForChar (inbuf[k]) & 0xff) | 0x2800);
2224     else
2225       outbuf[k] = getDotsForChar (inbuf[k]);
2226   return 1;
2227 }