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