xref: /aoo42x/main/i18npool/source/search/levdis.cxx (revision c1e8cc3a)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_i18npool.hxx"
26 /*************************************************************************
27 
28     Weighted Levenshtein Distance
29     including wildcards
30     '*' for any number (0 or more) of arbitrary characters
31     '?' for exactly one arbitrary character
32     escapeable with  backslash, "\*" or "\?"
33 
34     Return:
35         WLD if WLD <= nLimit, else nLimit+1
36 
37     or, if bSplitCount:
38         WLD if WLD <= nLimit
39         -WLD if Replace and Insert and Delete <= nLimit
40         else nLimit+1
41 
42     Recursive definition of WLD:
43 
44     WLD( X(i), Y(j) ) = min( WLD( X(i-1), Y(j-1) ) + p(i,j) ,
45                              WLD( X(i)  , Y(j-1) ) + q      ,
46                              WLD( X(i-1), Y(j)   ) + r      )
47 
48     X(i)   := the first i characters of the word X
49     Y(j)   := the first j characters of the word Y
50     p(i,j) := 0 if i-th character of X == j-th character of Y,
51               p else
52 
53     Boundary conditions:
54     WLD( X(0), Y(j) ) := j*q  (Y created by j inserts)
55     WLD( X(i), Y(0) ) := i*r  (Y created by i deletes)
56     WLD( X(0), Y(0) ) := 0
57 
58     Instead of recursions a dynamic algorithm is used.
59 
60     See also: German computer magazine
61     c't 07/89 pages 192-208 and c't 03/94 pages 230-239
62 
63 *************************************************************************/
64 
65 
66 #include <string.h>     // strlen()
67 
68 #if defined( _MSC_VER )
69 #pragma warning(once: 4068)
70 #endif
71 
72 #include "levdis.hxx"
73 
74 
75 #ifdef erTEST
76 #include <stdlib.h>
77 #include <stdio.h>
78 #include <iostream.h>
79 #endif
80 
81 #ifdef SOLARIS
82 #undef min
83 #endif
84 
85 #define LEVDISBIG   (nLimit + 1)    // Returnwert wenn Distanz > nLimit
86 #define LEVDISDOUBLEBUF 2048        // dadrueber wird nicht mehr gedoppelt
87 
88 // Balance, aus Geschwindigkeitsgruenden ist dieses keine Funktion
89 // c == cpPattern[jj] == cString[ii]
90 // erst wird bis Fundstelle gesucht, wenn dort die Balance gleich ist, wird
91 // auch nach der Fundstelle verglichen
92 #define LEVDISBALANCE(jj,ii)                        \
93 {                                                   \
94     if ( jj != ii )                                 \
95     {                                               \
96         sal_Int32 k;                                \
97         if ( jj > 0 )                               \
98             for ( k=0; k < jj; k++ )                \
99                 if ( cpPattern[k] == c )            \
100                     nBalance++;                     \
101         if ( ii > 0 )                               \
102             for ( k=0; k < ii; k++ )                \
103                 if ( cString[k] == c )              \
104                     nBalance--;                     \
105         if ( !nBalance )                            \
106         {                                           \
107             for ( k=jj+1; k < nPatternLen; k++ )    \
108                 if ( cpPattern[k] == c )            \
109                     nBalance++;                     \
110             for ( k=ii+1; k < nStringLen; k++ )     \
111                 if ( cString[k] == c )              \
112                     nBalance--;                     \
113         }                                           \
114     }                                               \
115 }
116 
117 static sal_Int32 Impl_WLD_StringLen( const sal_Unicode* pStr )
118 {
119     const sal_Unicode* pTempStr = pStr;
120     while( *pTempStr )
121         pTempStr++;
122     return (sal_Int32)(pTempStr-pStr);
123 }
124 
125 #ifdef erTESTMAT
126 #define erTESTMATMAX 180
127 static int npMatrix[erTESTMATMAX][erTESTMATMAX];        // nearly 64K
128 #endif
129 
130 // Distanz von String zu Pattern
131 int WLevDistance::WLD( const sal_Unicode* cString, sal_Int32 nStringLen )
132 {
133     int nSPMin = 0;     // StrafPunkteMinimum
134     int nRepS = 0;      // fuer SplitCount
135 
136 #ifdef erTESTMAT
137 {
138     for ( sal_Int32 r=0; r<=nStringLen && r < erTESTMATMAX; r++ )
139         for ( sal_Int32 c=0; c<=nPatternLen && c < erTESTMATMAX; c++ )
140             npMatrix[r][c] = 99;    // Matrix initialisieren, nur visuell
141 }
142 #endif
143 
144     // Laengendifferenz von Pattern und String
145     int nLenDiff = nPatternLen - nStars - nStringLen;
146     // mehr Einfuegungen oder Loeschungen noetig als Limit? => raus hier
147     if ( (nLenDiff * nInsQ0 > nLimit)
148             || ((nStars == 0) && (nLenDiff * nDelR0 < -nLimit)) )
149         return(LEVDISBIG);
150 
151     // wenn der zu vergleichende String groesser ist als das bisherige Array
152     // muss dieses angepasst werden
153     if ( nStringLen >= nArrayLen )
154     {
155         // gib ihm moeglichst mehr, damit nicht gleich naechstesmal
156         // wieder realloziert werden muss
157         if ( nStringLen < LEVDISDOUBLEBUF )
158             nArrayLen = 2 * nStringLen;
159         else
160             nArrayLen = nStringLen + 1;
161         npDistance = aDisMem.NewMem( nArrayLen );
162 #ifdef erTEST
163         if ( !npDistance )
164         {
165             cerr << "DOOM! (Damned, Out Of Memory)" << endl;
166             exit(1);
167         }
168 #endif
169     }
170 
171     // Anfangswerte der zweiten Spalte (erstes Pattern-Zeichen) berechnen
172     // die erste Spalte (0-Len Pattern) ist immer 0 .. nStringLen * nInsQ0,
173     // deren Minimum also 0
174     if ( nPatternLen == 0 )
175     {
176         // Anzahl der Loeschungen, um auf Pattern zu kommen
177         for ( sal_Int32 i=0; i <= nStringLen; i++ )
178             npDistance[i] = i * nDelR0;
179     }
180     else if ( cpPattern[0] == '*' && bpPatIsWild[0] )
181     {
182         // statt einem '*' ist alles einsetzbar
183         for ( sal_Int32 i=0; i <= nStringLen; i++ )
184             npDistance[i] = 0;
185     }
186     else
187     {
188         sal_Unicode c;
189         int nP;
190         c = cpPattern[0];
191         if ( c == '?' && bpPatIsWild[0] )
192             nP = 0;     // ein '?' kann jedes Zeichen sein
193         else
194             // Minimum von Ersetzen und Loeschen+Einfuegen Gewichtung
195             nP = Min3( nRepP0, nRepP0, nDelR0 + nInsQ0 );
196         npDistance[0] = nInsQ0;     // mit einfachem Einfuegen geht's los
197         npDistance[1] = nInsQ0;
198         npDistance[2] = nInsQ0;
199         int nReplacePos = -1;       // tristate Flag
200         int nDelCnt = 0;
201         for ( sal_Int32 i=1; i <= nStringLen; i++, nDelCnt += nDelR0 )
202         {
203             if ( cString[i-1] == c )
204                 nP = 0;     // Replace ab dieser Stelle ist 0
205             // Loeschungen um auf Pattern zu kommen + Replace
206             npDistance[i] = nDelCnt + nP;
207             if ( bSplitCount )
208             {
209                 if ( nReplacePos < 0 && nP )
210                 {   // diese Stelle wird ersetzt
211                     nRepS++;
212                     nReplacePos = i;
213 #ifdef erTESTMAT
214                     npMatrix[i][1] = -npDistance[i];
215 #endif
216                 }
217                 else if ( nReplacePos > 0 && !nP )
218                 {
219                     int nBalance = 0;   // gleiche Anzahl c
220                     LEVDISBALANCE( 0, i-1 );
221                     if ( !nBalance )
222                     {   // einer wurde ersetzt, der ein Insert war
223                         nRepS--;
224 #ifdef erTESTMAT
225                         npMatrix[nReplacePos][1] = npDistance[nReplacePos];
226 #endif
227                         nReplacePos = 0;
228                     }
229                 }
230             }
231         }
232         nSPMin = Min3( npDistance[0], npDistance[1], npDistance[2] );
233     }
234 #ifdef erTESTMAT
235 {
236     for ( sal_Int32 r=0; r<=nStringLen && r < erTESTMATMAX; r++ )
237     {
238         npMatrix[r][0] = r * nInsQ0;
239         if ( npMatrix[r][1] >= 0)
240             npMatrix[r][1] = npDistance[r];
241     }
242 }
243 #endif
244 
245     // Distanzmatrix berechnen
246     sal_Int32 j = 0;        // fuer alle Spalten des Pattern, solange nicht Limit
247     while ( (j < nPatternLen-1)
248             && nSPMin <= (bSplitCount ? 2 * nLimit : nLimit) )
249     {
250         sal_Unicode c;
251         int nP, nQ, nR, nPij, d1, d2;
252 
253         j++;
254         c = cpPattern[j];
255         if ( bpPatIsWild[j] )   // '*' oder '?' nicht escaped
256             nP = 0;     // kann ohne Strafpunkte ersetzt werden
257         else
258             nP = nRepP0;
259         if ( c == '*' && bpPatIsWild[j] )
260         {
261             nQ = 0;     // Einfuegen und Loeschen ohne Strafpunkte
262             nR = 0;
263         }
264         else
265         {
266             nQ = nInsQ0;    // normale Gewichtung
267             nR = nDelR0;
268         }
269         d2 = npDistance[0];
270         // Anzahl Einfuegungen um von Null-String auf Pattern zu kommen erhoehen
271         npDistance[0] = npDistance[0] + nQ;
272         nSPMin = npDistance[0];
273         int nReplacePos = -1;       // tristate Flag
274         // fuer jede Patternspalte den String durchgehen
275         for ( sal_Int32 i=1; i <= nStringLen; i++ )
276         {
277             d1 = d2;                // WLD( X(i-1), Y(j-1) )
278             d2 = npDistance[i];     // WLD( X(i)  , Y(j-1) )
279             if ( cString[i-1] == c )
280             {
281                 nPij = 0;           // p(i,j)
282                 if ( nReplacePos < 0 )
283                 {
284                     int nBalance = 0;   // gleiche Anzahl c
285                     LEVDISBALANCE( j, i-1 );
286                     if ( !nBalance )
287                         nReplacePos = 0;    // keine Ersetzung mehr
288                 }
289             }
290             else
291                 nPij = nP;
292             // WLD( X(i), Y(j) ) = min( WLD( X(i-1), Y(j-1) ) + p(i,j) ,
293             //                          WLD( X(i)  , Y(j-1) ) + q      ,
294             //                          WLD( X(i-1), Y(j)   ) + r      )
295             npDistance[i] = Min3( d1 + nPij, d2 + nQ, npDistance[i-1] + nR );
296             if ( npDistance[i] < nSPMin )
297                 nSPMin = npDistance[i];
298             if ( bSplitCount )
299             {
300                 if ( nReplacePos < 0 && nPij && npDistance[i] == d1 + nPij )
301                 {   // diese Stelle wird ersetzt
302                     nRepS++;
303                     nReplacePos = i;
304 #ifdef erTESTMAT
305                     npMatrix[i][j+1] = -npDistance[i];
306 #endif
307                 }
308                 else if ( nReplacePos > 0 && !nPij )
309                 {   // Zeichen in String und Pattern gleich.
310                     // wenn ab hier die gleiche Anzahl dieses Zeichens
311                     // sowohl in Pattern als auch in String ist, und vor
312                     // dieser Stelle das Zeichen gleich oft vorkommt, war das
313                     // Replace keins. Buchstabendreher werden hier erfasst
314                     // und der ReplaceS zurueckgenommen, wodurch das doppelte
315                     // Limit zum Tragen kommt.
316                     int nBalance = 0;   // gleiche Anzahl c
317                     LEVDISBALANCE( j, i-1 );
318                     if ( !nBalance )
319                     {   // einer wurde ersetzt, der ein Insert war
320                         nRepS--;
321 #ifdef erTESTMAT
322                         npMatrix[nReplacePos][j+1] = npDistance[nReplacePos];
323 #endif
324                         nReplacePos = 0;
325                     }
326                 }
327             }
328         }
329 #ifdef erTESTMAT
330 {
331         for ( sal_Int32 r=0; r<=nStringLen && r < erTESTMATMAX; r++ )
332             if ( npMatrix[r][j+1] >= 0)
333                 npMatrix[r][j+1] = npDistance[r];
334 }
335 #endif
336     }
337 #ifdef erTESTSPLIT
338     printf(" nRepS: %d ", nRepS );
339 #endif
340     if ( (nSPMin <= nLimit) && (npDistance[nStringLen] <= nLimit) )
341         return(npDistance[nStringLen]);
342     else
343     {
344         if ( bSplitCount )
345         {
346             if ( nRepS && nLenDiff > 0 )
347                 nRepS -= nLenDiff;      // Inserts wurden mitgezaehlt
348 #ifdef erTESTSPLIT
349             printf(" nRepSdiff: %d ", nRepS );
350 #endif
351             if ( (nSPMin <= 2 * nLimit)
352                     && (npDistance[nStringLen] <= 2 * nLimit)
353                     && (nRepS * nRepP0 <= nLimit) )
354                 return( -npDistance[nStringLen] );
355             return(LEVDISBIG);
356         }
357         return(LEVDISBIG);
358     }
359 }
360 
361 
362 
363 // Berechnung von nLimit,   nReplP0,    nInsQ0,     nDelR0,     bSplitCount
364 // aus Userwerten           nOtherX,    nShorterY,  nLongerZ,   bRelaxed
365 int WLevDistance::CalcLPQR( int nX, int nY, int nZ, bool bRelaxed )
366 {
367     int nMin, nMid, nMax;
368     if ( nX < 0 ) nX = 0;       // nur positive Werte
369     if ( nY < 0 ) nY = 0;
370     if ( nZ < 0 ) nZ = 0;
371     if ( 0 == (nMin = Min3( nX, nY, nZ )) )     // mindestens einer 0
372     {
373         nMax = Max3( nX, nY, nZ );      // entweder 0 bei drei 0 oder Max
374         if ( 0 == (nMid = Mid3( nX, nY, nZ )) )     // sogar zwei 0
375             nLimit = nMax;  // entweder 0 oder einziger >0
376         else        // einer 0
377             nLimit = KGV( nMid, nMax );
378     }
379     else        // alle drei nicht 0
380         nLimit = KGV( KGV( nX, nY ), nZ );
381     nRepP0 = ( nX ? nLimit / nX : nLimit + 1 );
382     nInsQ0 = ( nY ? nLimit / nY : nLimit + 1 );
383     nDelR0 = ( nZ ? nLimit / nZ : nLimit + 1 );
384     bSplitCount = bRelaxed;
385     return( nLimit );
386 }
387 
388 
389 
390 // Groesster Gemeinsamer Teiler nach Euklid (Kettendivision)
391 // Sonderfall: 0 und irgendwas geben 1
392 int WLevDistance::GGT( int a, int b )
393 {
394     if ( !a || !b )
395         return 1;
396     if ( a < 0 ) a = -a;
397     if ( b < 0 ) b = -b;
398     do
399     {
400         if ( a > b )
401             a -= int(a / b) * b;
402         else
403             b -= int(b / a) * a;
404     } while ( a && b );
405     return( a ? a : b);
406 }
407 
408 
409 
410 // Kleinstes Gemeinsames Vielfaches: a * b / GGT(a,b)
411 int WLevDistance::KGV( int a, int b )
412 {
413     if ( a > b )    // Ueberlauf unwahrscheinlicher machen
414         return( (a / GGT(a,b)) * b );
415     else
416         return( (b / GGT(a,b)) * a );
417 }
418 
419 
420 // Minimum von drei Werten
421 inline int WLevDistance::Min3( int x, int y, int z )
422 {
423     if ( x < y )
424         return( x < z ? x : z );
425     else
426         return( y < z ? y : z );
427 }
428 
429 
430 
431 // mittlerer von drei Werten
432 int WLevDistance::Mid3( int x, int y, int z )
433 {
434     int min = Min3(x,y,z);
435     if ( x == min )
436         return( y < z ? y : z);
437     else if ( y == min )
438         return( x < z ? x : z);
439     else        // z == min
440         return( x < y ? x : y);
441 }
442 
443 
444 
445 // Maximum von drei Werten
446 int WLevDistance::Max3( int x, int y, int z )
447 {
448     if ( x > y )
449         return( x > z ? x : z );
450     else
451         return( y > z ? y : z );
452 }
453 
454 
455 
456 // Daten aus CTor initialisieren
457 void WLevDistance::InitData( const sal_Unicode* cPattern )
458 {
459     cpPattern = aPatMem.GetcPtr();
460     bpPatIsWild = aPatMem.GetbPtr();
461     npDistance = aDisMem.GetPtr();
462     nStars = 0;
463     const sal_Unicode* cp1 = cPattern;
464     sal_Unicode* cp2 = cpPattern;
465     bool* bp = bpPatIsWild;
466     // Pattern kopieren, Sternchen zaehlen, escaped Jokers
467     while ( *cp1 )
468     {
469         if ( *cp1 == '\\' )     // maybe escaped
470         {
471             if ( *(cp1+1) == '*' || *(cp1+1) == '?' )   // naechstes Joker?
472             {
473                 cp1++;          // skip '\\'
474                 nPatternLen--;
475             }
476             *bp++ = false;
477         }
478         else if ( *cp1 == '*' || *cp1 == '?' )      // Joker
479         {
480             if ( *cp1 == '*' )
481                 nStars++;       // Sternchenzaehler erhoehen
482             *bp++ = true;
483         }
484         else
485             *bp++ = false;
486         *cp2++ = *cp1++;
487     }
488     *cp2 = '\0';
489 }
490 
491 
492 // CTor
493 
494 #ifdef erTEST
495 
496 WLevDistance::WLevDistance( const ::rtl::OUString& rPattern ) :
497     nPatternLen( rPattern.getLength() ),
498     aPatMem( nPatternLen + 1 ),
499     nArrayLen( nPatternLen + 1 ),
500     aDisMem( nArrayLen ),
501     nLimit( LEVDISDEFAULTLIMIT ),
502     nRepP0( LEVDISDEFAULT_P0 ),
503     nInsQ0( LEVDISDEFAULT_Q0 ),
504     nDelR0( LEVDISDEFAULT_R0 ),
505     bSplitCount( false )
506 {
507     InitData( rPattern.getStr() );
508 }
509 
510 #endif  // erTEST
511 
512 
513 WLevDistance::WLevDistance( const sal_Unicode* cPattern,
514                             int nOtherX, int nShorterY, int nLongerZ,
515                             bool bRelaxed ) :
516     nPatternLen( Impl_WLD_StringLen(cPattern) ),
517     aPatMem( nPatternLen + 1 ),
518     nArrayLen( nPatternLen + 1 ),
519     aDisMem( nArrayLen )
520 {
521     InitData( cPattern );
522     CalcLPQR( nOtherX, nShorterY, nLongerZ, bRelaxed );
523 }
524 
525 
526 // CopyCTor
527 WLevDistance::WLevDistance( const WLevDistance& rWLD ) :
528     nPatternLen( rWLD.nPatternLen ),
529     aPatMem( nPatternLen + 1 ),
530     nArrayLen( nPatternLen + 1 ),
531     aDisMem( nArrayLen ),
532     nLimit( rWLD.nLimit ),
533     nRepP0( rWLD.nRepP0 ),
534     nInsQ0( rWLD.nInsQ0 ),
535     nDelR0( rWLD.nDelR0 ),
536     nStars( rWLD.nStars ),
537     bSplitCount( rWLD.bSplitCount )
538 {
539     cpPattern = aPatMem.GetcPtr();
540     bpPatIsWild = aPatMem.GetbPtr();
541     npDistance = aDisMem.GetPtr();
542     sal_Int32 i;
543     for ( i=0; i<nPatternLen; i++ )
544     {
545         cpPattern[i] = rWLD.cpPattern[i];
546         bpPatIsWild[i] = rWLD.bpPatIsWild[i];
547     }
548     cpPattern[i] = '\0';
549 }
550 
551 
552 // DTor
553 WLevDistance::~WLevDistance()
554 {
555 }
556 
557 /*************************************************************************
558  * Test
559  *************************************************************************/
560 
561 #ifdef erTEST
562 
563 #define LINESIZE 1000
564 typedef char MAXSTRING [LINESIZE+1];
565 
566 #ifdef erTESTMAT
567 
568 void WLevDistance::ShowMatrix( const sal_Unicode* cString )
569 {
570     sal_Int32 r, c, l = Impl_WLD_StringLen(cString);
571     printf("   |   ");
572     for ( c=0; c<nPatternLen; c++ )
573 #error Error: conversion from sal_Unicode to char needed!
574         printf( " %c ", cpPattern[c] );
575     printf("\n---+---");
576     for ( c=0; c<nPatternLen; c++ )
577         printf( "---" );
578     for ( r=0; r<=l && r < erTESTMATMAX; r++ )
579     {
580 #error Error: conversion from sal_Unicode to char needed!
581         printf( "\n %c |", ( r==0 ? ' ' : cString[r-1] ) );
582         for ( c=0; c<=nPatternLen && c < erTESTMATMAX; c++ )
583             printf( "%2d ", npMatrix[r][c] );
584     }
585     printf("\n\n");
586 }
587 
588 #endif  // erTESTMAT
589 
590 // Delimiter fuer Token, \t Tab bleibt fuer immer an der ersten Stelle
591 MAXSTRING cDelim = "\t, ;(){}[]<>&=+-/%!|.\\'\"~";
592 
593 void WLevDistance::ShowTest()
594 {
595     printf("  \n");
596 #error Error: conversion from sal_Unicode to char needed!
597     printf(" a *cpPattern . . . . : %s\n", cpPattern);
598     printf(" b *bpPatIsWild . . . : ");
599     for ( sal_Int32 i=0; i<nPatternLen; i++ )
600         printf("%d", bpPatIsWild[i]);
601     printf("\n");
602     printf(" c nPatternLen  . . . : %d\n", (int)nPatternLen);
603     printf(" d nStars . . . . . . : %d\n", nStars);
604     printf(" e nLimit . . . . . . : %d\n", nLimit);
605     printf(" f nRepP0 (Ersetzen)  : %d\n", nRepP0);
606     printf(" g nInsQ0 (Einfuegen) : %d\n", nInsQ0);
607     printf(" h nDelR0 (Loeschen)  : %d\n", nDelR0);
608     printf(" i bSplitCount  . . . : %d\n", bSplitCount);
609 #error Error: conversion from sal_Unicode to char needed!
610     printf(" j cDelim . . . . . . : '%s'\n", cDelim);
611     printf(" ~\n");
612 }
613 
614 inline bool IsDelim( char c )
615 {
616     char* cp = cDelim;
617     while ( *cp )
618         if ( *cp++ == c )
619             return( true );
620     return( false );
621 }
622 
623 MAXSTRING cString, cLine, cIgString;
624 
625 int main( int argc, char **argv )
626 {
627     int nLim, nP0, nQ0, nR0, nX, nY, nZ;
628     int args = 0;
629     bool IgnoreCase = false, Direct = false, bStrict = false;
630     WLevDistance* pTest;
631     if ( argc < 2 )
632     {
633         printf("%s  Syntax:\n"
634             " ... [-i] cPattern [nOtherX, nShorterY, nLongerZ [bStrict [cDelim]]] [<stdin] [>stdout]\n"
635             " ...  -d  cPattern [nLimit [nRepP0 nInsQ0 nDelR0 [cDelim]]] [<stdin] [>stdout]\n"
636             , argv[0]);
637         exit(1);
638     }
639     if ( *argv[1] == '-' )
640     {
641         args++;
642         argc--;
643         switch ( *(argv[1]+1) )
644         {
645             case 'i':
646             {
647                 IgnoreCase = true;
648                 char* cp = argv[args+1];
649                 while ( (*cp = tolower( *cp )) != 0 )
650                     cp++;
651         break;
652             }
653             case 'd':
654                 Direct = true;
655         break;
656         }
657     }
658     if ( Direct )
659     {
660         if ( argc > 2 )
661             nLim = atoi(argv[args+2]);
662         else
663             nLim = LEVDISDEFAULTLIMIT;
664         if ( argc > 3 )
665         {
666             nP0 = atoi(argv[args+3]);
667             nQ0 = atoi(argv[args+4]);
668             nR0 = atoi(argv[args+5]);
669         }
670         else
671         {
672             nP0 = LEVDISDEFAULT_P0;
673             nQ0 = LEVDISDEFAULT_Q0;
674             nR0 = LEVDISDEFAULT_R0;
675         }
676         if ( argc > 6 )
677         {
678             strncpy( cDelim+1, argv[args+6], LINESIZE );    // \t Tab always remains
679             cDelim[LINESIZE-1] = 0;
680         }
681     }
682     else
683     {
684         if ( argc > 2 )
685         {
686             nX = atoi(argv[args+2]);
687             nY = atoi(argv[args+3]);
688             nZ = atoi(argv[args+4]);
689         }
690         else
691         {
692             nX = LEVDISDEFAULT_XOTHER;
693             nY = LEVDISDEFAULT_YSHORTER;
694             nZ = LEVDISDEFAULT_ZLONGER;
695         }
696         if ( argc > 5 )
697             bStrict = atoi(argv[args+5]);
698         if ( argc > 6 )
699         {
700             strncpy( cDelim+1, argv[args+6], LINESIZE );    // \t Tab always remains
701             cDelim[LINESIZE-1] = 0;
702         }
703     }
704     if ( Direct )
705     {
706 #error Error: conversion from char to OUString needed!
707         pTest = new WLevDistance( argv[args+1] );
708 #ifdef erTESTDEFAULT
709         pTest->ShowTest();
710 #endif
711         pTest->SetLimit( nLim );
712         pTest->SetReplaceP0( nP0 );
713         pTest->SetInsertQ0( nQ0 );
714         pTest->SetDeleteR0( nR0 );
715     }
716     else
717     {
718 #error Error: conversion from char to sal_Unicode needed!
719         pTest = new WLevDistance( argv[args+1], nX, nY, nZ, !bStrict );
720 #ifdef erTESTCCTOR
721         WLevDistance aTmp( *pTest );
722         aTmp.ShowTest();
723 #endif
724         nLim = pTest->GetLimit();
725     }
726     pTest->ShowTest();
727     do
728     {
729         char* cp1, *cp2;
730         static long unsigned int nLine = 0;
731         cp1 = cLine;
732         cin.getline( cLine, LINESIZE ) ;
733         nLine++;
734         while ( *cp1 )
735         {
736             while ( *cp1 && IsDelim(*cp1) )
737                 cp1++;
738             cp2 = cString;
739             while ( *cp1 && !IsDelim(*cp1) )
740                 *cp2++ = *cp1++;
741             *cp2 = '\0';
742             while ( *cp1 && IsDelim(*cp1) )
743                 cp1++;
744             if ( *cString )
745             {
746                 int ret;
747                 if ( IgnoreCase )
748                 {
749                     char* cpi1 = cString;
750                     char* cpi2 = cIgString;
751                     while ( *cpi1 )
752                         *cpi2++ = tolower( *cpi1++ );
753                     *cpi2 = '\0';
754 #error Error: conversion from char to OUString / sal_Unicode,length needed!
755                     ret = pTest->WLD( cIgString );
756                 }
757                 else
758 #error Error: conversion from char to OUString / sal_Unicode,length needed!
759                     ret = pTest->WLD( cString );
760 #ifdef erTESTMAT
761                 printf("\n# %3d : %s\n", ret, cString);
762 #error Error: conversion from char to sal_Unicode needed!
763                 pTest->ShowMatrix( cString );
764 #else
765                 if ( ret <= nLim )
766                     printf("# %3d : %s\t(line %lu)\t%s\n", ret, cString, nLine, cLine);
767 #endif
768             }
769         }
770     } while ( !cin.eof() );
771     return 0;
772 }
773 
774 #endif  // erTEST
775 
776