Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / liblouis / src / liblouis / transcommon.ci
1 /* This file contains code common to the translator and back-translator. 
2 * It is included immediately after the headr files. */
3
4 /* liblouis Braille Translation and Back-Translation 
5 Library
6
7    Based on the Linux screenreader BRLTTY, copyright (C) 1999-2006 by
8    The BRLTTY Team
9
10    Copyright (C) 2004, 2005, 2006
11    ViewPlus Technologies, Inc. www.viewplus.com
12    and
13    JJB Software, Inc. www.jjb-software.com
14    All rights reserved
15
16    This file is free software; you can redistribute it and/or modify it
17    under the terms of the Lesser or Library GNU General Public License 
18    as published by the
19    Free Software Foundation; either version 3, or (at your option) any
20    later version.
21
22    This file is distributed in the hope that it will be useful, but
23    WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
25    Library GNU General Public License for more details.
26
27    You should have received a copy of the Library GNU General Public 
28    License along with this program; see the file COPYING.  If not, write to
29    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
30    Boston, MA 02110-1301, USA.
31
32    Maintained by John J. Boyer john.boyer@abilitiessoft.com
33    */
34
35 /*additional bits in typebuf*/
36 #define capsemph 0x8000
37 #define EMPHASIS 0x000f
38 #define STARTWORD 0x4000
39 #define FIRSTWORD 0x2000
40 #define SYLLABLEMARKS 0x00c0
41 #define INTERNALMARKS 0xff00
42
43 static const TranslationTableHeader *table;
44 static int src, srcmax;
45 static int dest, destmax;
46 static int mode;
47 static int currentPass = 1;
48 static const widechar *currentInput;
49 static widechar *passbuf1 = NULL;
50 static widechar *passbuf2 = NULL;
51 static widechar *currentOutput;
52 static int *prevSrcMapping = NULL;
53 static int *srcMapping = NULL;
54 static unsigned short *typebuf = NULL;
55 static unsigned char *srcSpacing = NULL;
56 static unsigned char *destSpacing = NULL;
57 static int haveEmphasis = 0;
58 static TranslationTableOpcode transOpcode;
59 static TranslationTableOpcode prevTransOpcode;
60 static const TranslationTableRule *transRule;
61 static int transCharslen;
62 static int checkAttr (const widechar c,
63                       const TranslationTableCharacterAttributes a, int nm);
64 static int putCharacter (widechar c);
65 static int makeCorrections ();
66 static int passDoTest ();
67 static int passDoAction ();
68 static int passVariables[NUMVAR];
69 static int passCharDots;
70 static int passSrc;
71 static widechar const *passInstructions;
72 static int passIC;              /*Instruction counter */
73 static int startMatch;
74 static int endMatch;
75 static int startReplace;
76 static int endReplace;
77 static int realInlen;
78 static int srcIncremented;
79 static int *outputPositions;
80 static int *inputPositions;
81 static int cursorPosition;
82 static int cursorStatus;
83 static const TranslationTableRule **appliedRules;
84 static int maxAppliedRules;
85 static int appliedRulesCount;
86
87 static TranslationTableCharacter *
88 findCharOrDots (widechar c, int m)
89 {
90 /*Look up character or dot pattern in the appropriate  
91 * table. */
92   static TranslationTableCharacter noChar =
93     { 0, 0, 0, CTC_Space, 32, 32, 32 };
94   static TranslationTableCharacter noDots =
95     { 0, 0, 0, CTC_Space, B16, B16, B16 };
96   TranslationTableCharacter *notFound;
97   TranslationTableCharacter *character;
98   TranslationTableOffset bucket;
99   unsigned long int makeHash = (unsigned long int) c % HASHNUM;
100   if (m == 0)
101     {
102       bucket = table->characters[makeHash];
103       notFound = &noChar;
104     }
105   else
106     {
107       bucket = table->dots[makeHash];
108       notFound = &noDots;
109     }
110   while (bucket)
111     {
112       character = (TranslationTableCharacter *) & table->ruleArea[bucket];
113       if (character->realchar == c)
114         return character;
115       bucket = character->next;
116     }
117   notFound->realchar = notFound->uppercase = notFound->lowercase = c;
118   return notFound;
119 }
120
121 static int
122 checkAttr (const widechar c, const TranslationTableCharacterAttributes
123            a, int m)
124 {
125   static widechar prevc = 0;
126   static TranslationTableCharacterAttributes preva = 0;
127   if (c != prevc)
128     {
129       preva = (findCharOrDots (c, m))->attributes;
130       prevc = c;
131     }
132   return ((preva & a) ? 1 : 0);
133 }
134
135 static int
136 findAttribOrSwapRules ()
137 {
138   int save_transCharslen = transCharslen;
139   const TranslationTableRule *save_transRule = transRule;
140   TranslationTableOpcode save_transOpcode = transOpcode;
141   TranslationTableOffset ruleOffset;
142   ruleOffset = table->attribOrSwapRules[currentPass];
143   transCharslen = 0;
144   while (ruleOffset)
145     {
146       transRule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
147       transOpcode = transRule->opcode;
148       if (passDoTest ())
149         return 1;
150       ruleOffset = transRule->charsnext;
151     }
152   transCharslen = save_transCharslen;
153   transRule = save_transRule;
154   transOpcode = save_transOpcode;
155   return 0;
156 }
157
158 static int
159 compareChars (const widechar * address1, const widechar * address2, int
160               count, int m)
161 {
162   int k;
163   if (!count)
164     return 0;
165   for (k = 0; k < count; k++)
166     if ((findCharOrDots (address1[k], m))->lowercase !=
167         (findCharOrDots (address2[k], m))->lowercase)
168       return 0;
169   return 1;
170 }
171
172 static int
173 makeCorrections ()
174 {
175   if (!table->corrections)
176     return 1;
177   src = 0;
178   dest = 0;
179   srcIncremented = 1;
180   memset (passVariables, 0, sizeof(int) * NUMVAR);
181   while (src < srcmax)
182     {
183       int length = srcmax - src;
184       const TranslationTableCharacter *character = findCharOrDots
185         (currentInput[src], 0);
186       const TranslationTableCharacter *character2;
187       int tryThis = 0;
188       if (!findAttribOrSwapRules ())
189         while (tryThis < 3)
190           {
191             TranslationTableOffset ruleOffset = 0;
192             unsigned long int makeHash = 0;
193             switch (tryThis)
194               {
195               case 0:
196                 if (!(length >= 2))
197                   break;
198                 makeHash = (unsigned long int) character->lowercase << 8;
199                 character2 = findCharOrDots (currentInput[src + 1], 0);
200                 makeHash += (unsigned long int) character2->lowercase;
201                 makeHash %= HASHNUM;
202                 ruleOffset = table->forRules[makeHash];
203                 break;
204               case 1:
205                 if (!(length >= 1))
206                   break;
207                 length = 1;
208                 ruleOffset = character->otherRules;
209                 break;
210               case 2:           /*No rule found */
211                 transOpcode = CTO_Always;
212                 ruleOffset = 0;
213                 break;
214               }
215             while (ruleOffset)
216               {
217                 transRule =
218                   (TranslationTableRule *) & table->ruleArea[ruleOffset];
219                 transOpcode = transRule->opcode;
220                 transCharslen = transRule->charslen;
221                 if (tryThis == 1 || (transCharslen <= length &&
222                                      compareChars (&transRule->
223                                                    charsdots[0],
224                                                    &currentInput[src],
225                                                    transCharslen, 0)))
226                   {
227                     if (srcIncremented && transOpcode == CTO_Correct &&
228                         passDoTest ())
229                       {
230                         tryThis = 4;
231                         break;
232                       }
233                   }
234                 ruleOffset = transRule->charsnext;
235               }
236             tryThis++;
237           }
238       srcIncremented = 1;
239
240       switch (transOpcode)
241         {
242         case CTO_Always:
243           if (dest >= destmax)
244             goto failure;
245           srcMapping[dest] = prevSrcMapping[src];
246           currentOutput[dest++] = currentInput[src++];
247           break;
248         case CTO_Correct:
249           if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
250             appliedRules[appliedRulesCount++] = transRule;
251           if (!passDoAction ())
252             goto failure;
253           if (endReplace == src)
254             srcIncremented = 0;
255           src = endReplace;
256           break;
257         default:
258           break;
259         }
260     }
261
262   {                             // We have to transform typebuf accordingly
263     int pos;
264     unsigned short *typebuf_temp;
265     if ((typebuf_temp = malloc (dest * sizeof (unsigned short))) == NULL)
266       outOfMemory ();
267     for (pos = 0; pos < dest; pos++)
268       typebuf_temp[pos] = typebuf[srcMapping[pos]];
269     memcpy (typebuf, typebuf_temp, dest * sizeof (unsigned short));
270     free (typebuf_temp);
271   }
272
273 failure:
274   realInlen = src;
275   return 1;
276 }
277
278 static int
279 matchCurrentInput ()
280 {
281   int k;
282   int kk = passSrc;
283   for (k = passIC + 2; k < passIC + 2 + passInstructions[passIC + 1]; k++)
284     if (currentInput[kk] == ENDSEGMENT || passInstructions[k] !=
285         currentInput[kk++])
286       return 0;
287   return 1;
288 }
289
290 static int
291 swapTest (int swapIC, int *callSrc)
292 {
293   int curLen;
294   int curTest;
295   int curSrc = *callSrc;
296   TranslationTableOffset swapRuleOffset;
297   TranslationTableRule *swapRule;
298   swapRuleOffset =
299     (passInstructions[swapIC + 1] << 16) | passInstructions[swapIC + 2];
300   swapRule = (TranslationTableRule *) & table->ruleArea[swapRuleOffset];
301   for (curLen = 0; curLen < passInstructions[swapIC + 3]; curLen++)
302     {
303       if (swapRule->opcode == CTO_SwapDd)
304         {
305           for (curTest = 1; curTest < swapRule->charslen; curTest += 2)
306             {
307               if (currentInput[curSrc] == swapRule->charsdots[curTest])
308                 break;
309             }
310         }
311       else
312         {
313           for (curTest = 0; curTest < swapRule->charslen; curTest++)
314             {
315               if (currentInput[curSrc] == swapRule->charsdots[curTest])
316                 break;
317             }
318         }
319       if (curTest >= swapRule->charslen)
320         return 0;
321       curSrc++;
322     }
323   if (passInstructions[swapIC + 3] == passInstructions[swapIC + 4])
324     {
325       *callSrc = curSrc;
326       return 1;
327     }
328   while (curLen < passInstructions[swapIC + 4])
329     {
330       if (swapRule->opcode == CTO_SwapDd)
331         {
332           for (curTest = 1; curTest < swapRule->charslen; curTest += 2)
333             {
334               if (currentInput[curSrc] == swapRule->charsdots[curTest])
335                 break;
336             }
337         }
338       else
339         {
340           for (curTest = 0; curTest < swapRule->charslen; curTest++)
341             {
342               if (currentInput[curSrc] == swapRule->charsdots[curTest])
343                 break;
344             }
345         }
346       if (curTest >= swapRule->charslen)
347         {
348           *callSrc = curSrc;
349           return 1;
350         }
351       curSrc++;
352       curLen++;
353     }
354   *callSrc = curSrc;
355   return 1;
356 }
357
358 static int
359 swapReplace (int start, int end)
360 {
361   TranslationTableOffset swapRuleOffset;
362   TranslationTableRule *swapRule;
363   widechar *replacements;
364   int curRep;
365   int curPos;
366   int curTest;
367   int curSrc;
368   swapRuleOffset =
369     (passInstructions[passIC + 1] << 16) | passInstructions[passIC + 2];
370   swapRule = (TranslationTableRule *) & table->ruleArea[swapRuleOffset];
371   replacements = &swapRule->charsdots[swapRule->charslen];
372   for (curSrc = start; curSrc < end; curSrc++)
373     {
374       for (curTest = 0; curTest < swapRule->charslen; curTest++)
375         if (currentInput[curSrc] == swapRule->charsdots[curTest])
376           break;
377       if (curTest == swapRule->charslen)
378         continue;
379       curPos = 0;
380       for (curRep = 0; curRep < curTest; curRep++)
381         if (swapRule->opcode == CTO_SwapCc)
382           curPos++;
383         else
384           curPos += replacements[curPos];
385       if (swapRule->opcode == CTO_SwapCc)
386         {
387           if ((dest + 1) >= srcmax)
388             return 0;
389           srcMapping[dest] = prevSrcMapping[curSrc];
390           currentOutput[dest++] = replacements[curPos];
391         }
392       else
393         {
394           int k;
395           if ((dest + replacements[curPos] - 1) >= destmax)
396             return 0;
397           for (k = dest + replacements[curPos] - 1; k >= dest; --k)
398             srcMapping[k] = prevSrcMapping[curSrc];
399           memcpy (&currentOutput[dest], &replacements[curPos + 1],
400                   (replacements[curPos]) * CHARSIZE);
401           dest += replacements[curPos] - 1;
402         }
403     }
404   return 1;
405 }
406
407 static TranslationTableRule *groupingRule;
408 static widechar groupingOp;
409
410 static int
411 replaceGrouping ()
412 {
413   widechar startCharDots = groupingRule->charsdots[2 * passCharDots];
414   widechar endCharDots = groupingRule->charsdots[2 * passCharDots + 1];
415   widechar *curin = (widechar *) currentInput;
416   int curPos;
417   int level = 0;
418   TranslationTableOffset replaceOffset = passInstructions[passIC + 1] <<
419     16 | (passInstructions[passIC + 2] & 0xff);
420   TranslationTableRule *replaceRule = (TranslationTableRule *) &
421     table->ruleArea[replaceOffset];
422   widechar replaceStart = replaceRule->charsdots[2 * passCharDots];
423   widechar replaceEnd = replaceRule->charsdots[2 * passCharDots + 1];
424   if (groupingOp == pass_groupstart)
425     {
426       curin[startReplace] = replaceStart;
427       for (curPos = startReplace + 1; curPos < srcmax; curPos++)
428         {
429           if (currentInput[curPos] == startCharDots)
430             level--;
431           if (currentInput[curPos] == endCharDots)
432             level++;
433           if (level == 1)
434             break;
435         }
436       if (curPos == srcmax)
437         return 0;
438       curin[curPos] = replaceEnd;
439     }
440   else
441     {
442       if (transOpcode == CTO_Context)
443         {
444           startCharDots = groupingRule->charsdots[2];
445           endCharDots = groupingRule->charsdots[3];
446           replaceStart = replaceRule->charsdots[2];
447           replaceEnd = replaceRule->charsdots[3];
448         }
449       currentOutput[dest] = replaceEnd;
450       for (curPos = dest - 1; curPos >= 0; curPos--)
451         {
452           if (currentOutput[curPos] == endCharDots)
453             level--;
454           if (currentOutput[curPos] == startCharDots)
455             level++;
456           if (level == 1)
457             break;
458         }
459       if (curPos < 0)
460         return 0;
461       currentOutput[curPos] = replaceStart;
462       dest++;
463     }
464   return 1;
465 }
466
467 static int
468 removeGrouping ()
469 {
470   widechar startCharDots = groupingRule->charsdots[2 * passCharDots];
471   widechar endCharDots = groupingRule->charsdots[2 * passCharDots + 1];
472   widechar *curin = (widechar *) currentInput;
473   int curPos;
474   int level = 0;
475   if (groupingOp == pass_groupstart)
476     {
477       for (curPos = startReplace + 1; curPos < srcmax; curPos++)
478         {
479           if (currentInput[curPos] == startCharDots)
480             level--;
481           if (currentInput[curPos] == endCharDots)
482             level++;
483           if (level == 1)
484             break;
485         }
486       if (curPos == srcmax)
487         return 0;
488       curPos++;
489       for (; curPos < srcmax; curPos++)
490         curin[curPos - 1] = curin[curPos];
491       srcmax--;
492     }
493   else
494     {
495       for (curPos = dest - 1; curPos >= 0; curPos--)
496         {
497           if (currentOutput[curPos] == endCharDots)
498             level--;
499           if (currentOutput[curPos] == startCharDots)
500             level++;
501           if (level == 1)
502             break;
503         }
504       if (curPos < 0)
505         return 0;
506       curPos++;
507       for (; curPos < dest; curPos++)
508         currentOutput[curPos - 1] = currentOutput[curPos];
509       dest--;
510     }
511   return 1;
512 }
513
514 static int searchIC;
515 static int searchSrc;
516
517 static int
518 doPassSearch ()
519 {
520   int level = 0;
521   int k, kk;
522   int not = 0;
523   TranslationTableOffset ruleOffset;
524   TranslationTableRule *rule;
525   TranslationTableCharacterAttributes attributes;
526   int stepper = passSrc;
527   while (stepper < srcmax)
528     {
529       searchIC = passIC + 1;
530       searchSrc = stepper;
531       while (searchIC < transRule->dotslen)
532         {
533           int itsTrue = 1;
534           if (searchSrc > srcmax)
535             return 0;
536           switch (passInstructions[searchIC])
537             {
538             case pass_lookback:
539               searchSrc -= passInstructions[searchIC + 1];
540               if (searchSrc < 0)
541                 searchSrc = 0;
542               searchIC += 2;
543               break;
544             case pass_not:
545               not = 1;
546               searchIC++;
547               continue;
548             case pass_string:
549             case pass_dots:
550               kk = searchSrc;
551               for (k = searchIC + 2;
552                    k < searchIC + 2 + passInstructions[searchIC + 1]; k++)
553                 if (currentInput[kk] == ENDSEGMENT || passInstructions[k] !=
554                     currentInput[kk++])
555                   {
556                     itsTrue = 0;
557                     break;
558                   }
559               searchSrc += passInstructions[searchIC + 1];
560               searchIC += passInstructions[searchIC + 1] + 2;
561               break;
562             case pass_startReplace:
563               searchIC++;
564               break;
565             case pass_endReplace:
566               searchIC++;
567               break;
568             case pass_attributes:
569               attributes =
570                 (passInstructions[searchIC + 1] << 16) |
571                 passInstructions[searchIC + 2];
572               for (k = 0; k < passInstructions[searchIC + 3]; k++)
573                 {
574                   if (currentInput[searchSrc] == ENDSEGMENT)
575                     itsTrue = 0;
576                   else
577                     itsTrue =
578                       (((findCharOrDots (currentInput[searchSrc++],
579                                          passCharDots)->
580                          attributes & attributes)) ? 1 : 0);
581                   if (!itsTrue)
582                     break;
583                 }
584               if (itsTrue)
585                 {
586                   for (k = passInstructions[searchIC + 3]; k <
587                        passInstructions[searchIC + 4]; k++)
588                     {
589                       if (currentInput[searchSrc] == ENDSEGMENT)
590                         {
591                           itsTrue = 0;
592                           break;
593                         }
594                       if (!
595                           (findCharOrDots (currentInput[searchSrc],
596                                            passCharDots)->
597                            attributes & attributes))
598                         break;
599                       searchSrc++;
600                     }
601                 }
602               searchIC += 5;
603               break;
604             case pass_groupstart:
605             case pass_groupend:
606               ruleOffset = (passInstructions[searchIC + 1] << 16) |
607                 passInstructions[searchIC + 2];
608               rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
609               if (passInstructions[searchIC] == pass_groupstart)
610                 itsTrue =
611                   (currentInput[searchSrc] == rule->charsdots[2 *
612                                                               passCharDots]) ?
613                   1 : 0;
614               else
615                 itsTrue =
616                   (currentInput[searchSrc] == rule->charsdots[2 *
617                                                               passCharDots +
618                                                               1]) ? 1 : 0;
619               if (groupingRule != NULL && groupingOp == pass_groupstart
620                   && rule == groupingRule)
621                 {
622                   if (currentInput[searchSrc] == rule->charsdots[2 *
623                                                                  passCharDots])
624                     level--;
625                   else if (currentInput[searchSrc] ==
626                            rule->charsdots[2 * passCharDots + 1])
627                     level++;
628                 }
629               searchSrc++;
630               searchIC += 3;
631               break;
632             case pass_swap:
633               itsTrue = swapTest (searchIC, &searchSrc);
634               searchIC += 5;
635               break;
636             case pass_eq:
637               if (passVariables[passInstructions[searchIC + 1]] !=
638                   passInstructions[searchIC + 2])
639                 itsTrue = 0;
640               searchIC += 3;
641               break;
642             case pass_lt:
643               if (passVariables[passInstructions[searchIC + 1]] >=
644                   passInstructions[searchIC + 2])
645                 itsTrue = 0;
646               searchIC += 3;
647               break;
648             case pass_gt:
649               if (passVariables[passInstructions[searchIC + 1]] <=
650                   passInstructions[searchIC + 2])
651                 itsTrue = 0;
652               searchIC += 3;
653               break;
654             case pass_lteq:
655               if (passVariables[passInstructions[searchIC + 1]] >
656                   passInstructions[searchIC + 2])
657                 itsTrue = 0;
658               searchIC += 3;
659               break;
660             case pass_gteq:
661               if (passVariables[passInstructions[searchIC + 1]] <
662                   passInstructions[searchIC + 2])
663                 itsTrue = 0;
664               searchIC += 3;
665               break;
666             case pass_endTest:
667               if (itsTrue)
668                 {
669                   if ((groupingRule && level == 1) || !groupingRule)
670                     return 1;
671                 }
672               searchIC = transRule->dotslen;
673               break;
674             default:
675               break;
676             }
677           if ((!not && !itsTrue) || (not && itsTrue))
678             break;
679           not = 0;
680         }
681       stepper++;
682     }
683   return 0;
684 }
685
686 static int
687 passDoTest ()
688 {
689   int k;
690   int not = 0;
691   TranslationTableOffset ruleOffset = 0;
692   TranslationTableRule *rule = NULL;
693   TranslationTableCharacterAttributes attributes = 0;
694   groupingRule = NULL;
695   passSrc = src;
696   passInstructions = &transRule->charsdots[transCharslen];
697   passIC = 0;
698   startMatch = endMatch = passSrc;
699   startReplace = endReplace = -1;
700   if (transOpcode == CTO_Context || transOpcode == CTO_Correct)
701     passCharDots = 0;
702   else
703     passCharDots = 1;
704   while (passIC < transRule->dotslen)
705     {
706       int itsTrue = 1;
707       if (passSrc > srcmax)
708         return 0;
709       switch (passInstructions[passIC])
710         {
711         case pass_first:
712           if (passSrc != 0)
713             itsTrue = 0;
714           passIC++;
715           break;
716         case pass_last:
717           if (passSrc != srcmax)
718             itsTrue = 0;
719           passIC++;
720           break;
721         case pass_lookback:
722           passSrc -= passInstructions[passIC + 1];
723           if (passSrc < 0)
724             passSrc = 0;
725           passIC += 2;
726           break;
727         case pass_not:
728           not = 1;
729           passIC++;
730           continue;
731         case pass_string:
732         case pass_dots:
733           itsTrue = matchCurrentInput ();
734           passSrc += passInstructions[passIC + 1];
735           passIC += passInstructions[passIC + 1] + 2;
736           break;
737         case pass_startReplace:
738           startReplace = passSrc;
739           passIC++;
740           break;
741         case pass_endReplace:
742           endReplace = passSrc;
743           passIC++;
744           break;
745         case pass_attributes:
746           attributes =
747             (passInstructions[passIC + 1] << 16) | passInstructions[passIC +
748                                                                     2];
749           for (k = 0; k < passInstructions[passIC + 3]; k++)
750             {
751               if (currentInput[passSrc] == ENDSEGMENT)
752                 itsTrue = 0;
753               else
754                 itsTrue =
755                   (((findCharOrDots (currentInput[passSrc++],
756                                      passCharDots)->
757                      attributes & attributes)) ? 1 : 0);
758               if (!itsTrue)
759                 break;
760             }
761           if (itsTrue)
762             {
763               for (k = passInstructions[passIC + 3]; k <
764                    passInstructions[passIC + 4]; k++)
765                 {
766                   if (currentInput[passSrc] == ENDSEGMENT)
767                     {
768                       itsTrue = 0;
769                       break;
770                     }
771                   else
772                     if (!
773                         (findCharOrDots (currentInput[passSrc],
774                                          passCharDots)->
775                          attributes & attributes))
776                     break;
777                   passSrc++;
778                 }
779             }
780           passIC += 5;
781           break;
782         case pass_groupstart:
783         case pass_groupend:
784           ruleOffset = (passInstructions[passIC + 1] << 16) |
785             passInstructions[passIC + 2];
786           rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
787           if (passIC == 0 || (passIC > 0 && passInstructions[passIC - 1] ==
788                               pass_startReplace))
789             {
790               groupingRule = rule;
791               groupingOp = passInstructions[passIC];
792             }
793           if (passInstructions[passIC] == pass_groupstart)
794             itsTrue = (currentInput[passSrc] == rule->charsdots[2 *
795                                                                 passCharDots])
796               ? 1 : 0;
797           else
798             itsTrue = (currentInput[passSrc] == rule->charsdots[2 *
799                                                                 passCharDots +
800                                                                 1]) ? 1 : 0;
801           passSrc++;
802           passIC += 3;
803           break;
804         case pass_swap:
805           itsTrue = swapTest (passIC, &passSrc);
806           passIC += 5;
807           break;
808         case pass_eq:
809           if (passVariables[passInstructions[passIC + 1]] !=
810               passInstructions[passIC + 2])
811             itsTrue = 0;
812           passIC += 3;
813           break;
814         case pass_lt:
815           if (passVariables[passInstructions[passIC + 1]] >=
816               passInstructions[passIC + 2])
817             itsTrue = 0;
818           passIC += 3;
819           break;
820         case pass_gt:
821           if (passVariables[passInstructions[passIC + 1]] <=
822               passInstructions[passIC + 2])
823             itsTrue = 0;
824           passIC += 3;
825           break;
826         case pass_lteq:
827           if (passVariables[passInstructions[passIC + 1]] >
828               passInstructions[passIC + 2])
829             itsTrue = 0;
830           passIC += 3;
831           break;
832         case pass_gteq:
833           if (passVariables[passInstructions[passIC + 1]] <
834               passInstructions[passIC + 2])
835             itsTrue = 0;
836           passIC += 3;
837           break;
838         case pass_search:
839           itsTrue = doPassSearch ();
840           if ((!not && !itsTrue) || (not && itsTrue))
841             return 0;
842           passIC = searchIC;
843           passSrc = searchSrc;
844         case pass_endTest:
845           passIC++;
846           endMatch = passSrc;
847           if (startReplace == -1)
848             {
849               startReplace = startMatch;
850               endReplace = endMatch;
851             }
852           return 1;
853           break;
854         default:
855           return 0;
856         }
857       if ((!not && !itsTrue) || (not && itsTrue))
858         return 0;
859       not = 0;
860     }
861   return 0;
862 }
863
864 static int
865 passDoAction ()
866 {
867   int k;
868   TranslationTableOffset ruleOffset = 0;
869   TranslationTableRule *rule = NULL;
870   if ((dest + startReplace - startMatch) > destmax)
871     return 0;
872   if (transOpcode != CTO_Context)
873     memmove (&srcMapping[dest], &prevSrcMapping[startMatch],
874              (startReplace - startMatch) * sizeof (int));
875   for (k = startMatch; k < startReplace; k++)
876     if (transOpcode == CTO_Context)
877       {
878         if (!putCharacter (currentInput[k]))
879           return 0;
880       }
881     else
882       currentOutput[dest++] = currentInput[k];
883   while (passIC < transRule->dotslen)
884     switch (passInstructions[passIC])
885       {
886       case pass_string:
887       case pass_dots:
888         if ((dest + passInstructions[passIC + 1]) > destmax)
889           return 0;
890         for (k = 0; k < passInstructions[passIC + 1]; ++k)
891           srcMapping[dest + k] = prevSrcMapping[startReplace];
892         memcpy (&currentOutput[dest], &passInstructions[passIC + 2],
893                 passInstructions[passIC + 1] * CHARSIZE);
894         dest += passInstructions[passIC + 1];
895         passIC += passInstructions[passIC + 1] + 2;
896         break;
897       case pass_eq:
898         passVariables[passInstructions[passIC + 1]] =
899           passInstructions[passIC + 2];
900         passIC += 3;
901         break;
902       case pass_hyphen:
903         passVariables[passInstructions[passIC + 1]]--;
904         if (passVariables[passInstructions[passIC + 1]] < 0)
905           passVariables[passInstructions[passIC + 1]] = 0;
906         passIC += 2;
907         break;
908       case pass_plus:
909         passVariables[passInstructions[passIC + 1]]++;
910         passIC += 2;
911         break;
912       case pass_groupstart:
913         ruleOffset = (passInstructions[passIC + 1] << 16) |
914           passInstructions[passIC + 2];
915         rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
916         srcMapping[dest] = prevSrcMapping[startMatch];
917         currentOutput[dest++] = rule->charsdots[2 * passCharDots];
918         passIC += 3;
919         break;
920       case pass_groupend:
921         ruleOffset = (passInstructions[passIC + 1] << 16) |
922           passInstructions[passIC + 2];
923         rule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
924         srcMapping[dest] = prevSrcMapping[startMatch];
925         currentOutput[dest++] = rule->charsdots[2 * passCharDots + 1];
926         passIC += 3;
927         break;
928       case pass_swap:
929         if (!swapReplace (startReplace, endReplace))
930           return 0;
931         passIC += 3;
932         break;
933       case pass_groupreplace:
934         if (!groupingRule || !replaceGrouping ())
935           return 0;
936         passIC += 3;
937         break;
938       case pass_omit:
939         if (groupingRule)
940           removeGrouping ();
941         passIC++;
942         break;
943       case pass_copy:
944         dest -= startReplace - startMatch;
945         k = endReplace - startReplace;
946         if ((dest + k) > destmax)
947           return 0;
948         memmove (&srcMapping[dest], &prevSrcMapping[startReplace],
949                  k * sizeof (int));
950         memcpy (&currentOutput[dest], &currentInput[startReplace],
951                 k * CHARSIZE);
952         dest += k;
953         passIC++;
954         endReplace = passSrc;
955         break;
956       default:
957         return 0;
958       }
959   return 1;
960 }
961
962 static int
963 checkDots ()
964 {
965   int k;
966   int kk = src;
967   for (k = 0; k < transCharslen; k++)
968     if (transRule->charsdots[k] != currentInput[kk++])
969       return 0;
970   return 1;
971 }
972
973 static void
974 passSelectRule ()
975 {
976   int length = srcmax - src;
977   const TranslationTableCharacter *dots;
978   const TranslationTableCharacter *dots2;
979   int tryThis;
980   TranslationTableOffset ruleOffset = 0;
981   unsigned long int makeHash = 0;
982   if (findAttribOrSwapRules ())
983     return;
984   dots = findCharOrDots (currentInput[src], 1);
985   for (tryThis = 0; tryThis < 3; tryThis++)
986     {
987       switch (tryThis)
988         {
989         case 0:
990           if (!(length >= 2))
991             break;
992 /*Hash function optimized for forward translation */
993           makeHash = (unsigned long int) dots->lowercase << 8;
994           dots2 = findCharOrDots (currentInput[src + 1], 1);
995           makeHash += (unsigned long int) dots2->lowercase;
996           makeHash %= HASHNUM;
997           ruleOffset = table->forRules[makeHash];
998           break;
999         case 1:
1000           if (!(length >= 1))
1001             break;
1002           length = 1;
1003           ruleOffset = dots->otherRules;
1004           break;
1005         case 2:         /*No rule found */
1006           transOpcode = CTO_Always;
1007           return;
1008           break;
1009         }
1010       while (ruleOffset)
1011         {
1012           transRule = (TranslationTableRule *) & table->ruleArea[ruleOffset];
1013           transOpcode = transRule->opcode;
1014           transCharslen = transRule->charslen;
1015           if (tryThis == 1 || ((transCharslen <= length) && checkDots ()))
1016             switch (transOpcode)
1017               {                 /*check validity of this Translation */
1018               case CTO_Pass2:
1019                 if (currentPass != 2 || !srcIncremented)
1020                   break;
1021                 if (!passDoTest ())
1022                   break;
1023                 return;
1024               case CTO_Pass3:
1025                 if (currentPass != 3 || !srcIncremented)
1026                   break;
1027                 if (!passDoTest ())
1028                   break;
1029                 return;
1030               case CTO_Pass4:
1031                 if (currentPass != 4 || !srcIncremented)
1032                   break;
1033                 if (!passDoTest ())
1034                   break;
1035                 return;
1036               default:
1037                 break;
1038               }
1039           ruleOffset = transRule->charsnext;
1040         }
1041     }
1042   return;
1043 }
1044
1045 static int
1046 translatePass ()
1047 {
1048   prevTransOpcode = CTO_None;
1049   src = dest = 0;
1050   srcIncremented = 1;
1051   memset (passVariables, 0, sizeof(int) * NUMVAR);
1052   while (src < srcmax)
1053     {                           /*the main multipass translation loop */
1054       passSelectRule ();
1055       srcIncremented = 1;
1056       switch (transOpcode)
1057         {
1058         case CTO_Context:
1059         case CTO_Pass2:
1060         case CTO_Pass3:
1061         case CTO_Pass4:
1062           if (appliedRules != NULL && appliedRulesCount < maxAppliedRules)
1063             appliedRules[appliedRulesCount++] = transRule;
1064           if (!passDoAction ())
1065             goto failure;
1066           if (endReplace == src)
1067             srcIncremented = 0;
1068           src = endReplace;
1069           break;
1070         case CTO_Always:
1071           if ((dest + 1) > destmax)
1072             goto failure;
1073           srcMapping[dest] = prevSrcMapping[src];
1074           currentOutput[dest++] = currentInput[src++];
1075           break;
1076         default:
1077           goto failure;
1078         }
1079     }
1080   srcMapping[dest] = prevSrcMapping[src];
1081 failure:if (src < srcmax)
1082     {
1083       while (checkAttr (currentInput[src], CTC_Space, 1))
1084         if (++src == srcmax)
1085           break;
1086     }
1087   return 1;
1088 }