root/libswish3/trunk/src/libswish3/tokenizer.c

Revision 2176, 23.9 kB (checked in by karpet, 2 months ago)

all tests passing, all (known) leaks fixed

Line 
1 /*
2  * This file is part of libswish3
3  * Copyright (C) 2008 Peter Karman
4  *
5  *  libswish3 is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  libswish3 is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with libswish3; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20 /* utf8 tokenizer */
21
22 #include <wchar.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <wctype.h>
26 #include <err.h>
27 #include <stdarg.h>
28
29 #include "libswish3.h"
30
31 extern int SWISH_DEBUG;
32
33 static int is_ignore_start_utf8(
34     int c
35 );
36 static int is_ignore_end_utf8(
37     int c
38 );
39 static int is_ignore_word_utf8(
40     int c
41 );
42 static int is_ignore_start_ascii(
43     char c
44 );
45 static int is_ignore_end_ascii(
46     char c
47 );
48 static int is_ignore_word_ascii(
49     char c
50 );
51 static void make_ascii_tables(
52 );
53 static int strip_utf8_chrs(
54     xmlChar *token,
55     int len
56 );
57 static int strip_ascii_chrs(
58     xmlChar *word,
59     int len
60 );
61
62 static int
63 is_ignore_start_utf8(
64     int c
65 )
66 {
67     return (!c || iswspace((wint_t) c) || iswcntrl(c) || iswpunct(c)
68         )
69         ? 1 : 0;
70 }
71
72 static int
73 is_ignore_end_utf8(
74     int c
75 )
76 {
77     return (!c || iswspace(c) || iswcntrl(c) || iswpunct(c)
78         )
79         ? 1 : 0;
80 }
81
82 static int
83 is_ignore_word_utf8(
84     int c
85 )
86 {
87     if (c == '\'')              /*  contractions allowed */
88         return 0;
89
90     if (!c || iswspace(c) || iswcntrl(c) || iswpunct(c)
91         )
92         return 1;
93
94     return 0;
95 }
96
97 static int
98 is_ignore_start_ascii(
99     char c
100 )
101 {
102     return (!c || isspace(c) || iscntrl(c) || ispunct(c)
103         )
104         ? 1 : 0;
105
106 }
107
108 static int
109 is_ignore_end_ascii(
110     char c
111 )
112 {
113     return (!c || isspace(c) || iscntrl(c) || ispunct(c)
114         )
115         ? 1 : 0;
116 }
117
118 static int
119 is_ignore_word_ascii(
120     char c
121 )
122 {
123     if (c == '\'')              /*  contractions allowed */
124         return 0;
125
126     return (!c || isspace(c) || iscntrl(c) || ispunct(c)
127         )
128         ? 1 : 0;
129 }
130
131 /************************************************
132 *   mimic the Swish-e WordCharacters lookup tables
133 *   using the default is*() functions.
134 *************************************************/
135
136 static boolean ascii_init = 0;
137 static char ascii_word_table[128];
138 static char ascii_start_table[128];
139 static char ascii_end_table[128];
140
141 static void
142 make_ascii_tables(
143 )
144 {
145     int i;
146     for (i = 0; i < 127; i++) {
147         if (is_ignore_word_ascii(i))
148             ascii_word_table[i] = 0;
149         else
150             ascii_word_table[i] = 1;
151
152         if (is_ignore_end_ascii(i))
153             ascii_end_table[i] = 0;
154         else
155             ascii_end_table[i] = 1;
156
157         if (is_ignore_start_ascii(i))
158             ascii_start_table[i] = 0;
159         else
160             ascii_start_table[i] = 1;
161
162     }
163     ascii_init = 1;
164 }
165
166 /*************************************************
167 * remove all ignorable start/end chars
168 * and return new length of token
169 * based on code in swish-e vers2 swish_words.c
170 *************************************************/
171
172 static int
173 strip_utf8_chrs(
174     xmlChar *token,
175     int len
176 )
177 {
178     int i, j, k, chr_len, start, end, token_len, cp;
179     xmlChar chr[5];
180
181     start = 0;
182     end = 0;
183
184     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
185         SWISH_DEBUG_MSG("Before: %s", token);
186
187 // end chrs -- must do before start chars
188     j = len;
189     for (i = len; i >= 0; swish_utf8_prev_chr(token, &i)) {
190         chr_len = j - i;
191         if (!chr_len) {
192             j = i;
193             continue;
194         }
195         for (k = 0; k < chr_len; k++) {
196             chr[k] = token[i + k];
197         }
198         chr[k] = '\0';
199         if (is_ignore_end_utf8(swish_utf8_codepoint(chr))) {
200             token[i] = '\0';
201             end++;
202         }
203         else {
204             break;
205         }
206     }
207
208     chr[0] = '\0';
209     j = 0;
210
211 // start chrs
212     for (i = 0; token[j] != '\0'; swish_utf8_next_chr(token, &i)) {
213         chr_len = i - j;
214         if (!chr_len) {
215             j = i;
216             continue;
217         }
218         for (k = 0; k < chr_len; k++) {
219             chr[k] = token[j + k];
220         }
221         chr[k] = '\0';
222         cp = swish_utf8_codepoint(chr);
223
224         if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
225             SWISH_DEBUG_MSG("start chr_len %d chr: %s  [%d]", chr_len, chr, cp);
226
227         if (!is_ignore_start_utf8(cp)) {
228             break;
229         }
230         else {
231             if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
232                 SWISH_DEBUG_MSG("ignore_start %s", chr);
233
234             token += i;
235             start++;
236         }
237     }
238
239     token_len = xmlStrlen(token) + 1;
240
241     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
242         SWISH_DEBUG_MSG("After: %s (stripped %d start chars, %d end chars, len=%d)",
243                         token, start, end, token_len);
244
245     return token_len;
246 }
247
248 static int
249 strip_ascii_chrs(
250     xmlChar *word,
251     int len
252 )
253 {
254     int i, j, k, wlen, start, end;
255     start = 0;
256     end = 0;
257
258     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
259         SWISH_DEBUG_MSG("Before: %s", word);
260
261 /* end chars -- must do before start chars */
262
263     i = len;
264
265 /* Iteratively strip off the last character if it's an ignore character */
266     while (i-- > 0) {
267
268         if (!ascii_end_table[word[i]]) {
269             word[i] = '\0';
270             end++;
271         }
272         else {
273             break;
274         }
275     }
276
277 /* start chars */
278     i = 0;
279
280     while (word[i]) {
281         k = i;
282         if (ascii_start_table[word[k]]) {
283             break;
284         }
285         else {
286             i = k + 1;
287             start++;
288         }
289     }
290
291 /* If all the chars are valid, just leave word alone */
292     if (i != 0) {
293         for (k = i, j = 0; word[k] != '\0'; j++, k++) {
294             word[j] = word[k];
295         }
296
297 /* Add the NULL */
298         word[j] = '\0';
299     }
300
301     wlen = xmlStrlen(word) + 1;
302
303     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
304         SWISH_DEBUG_MSG("After: %s (stripped %d start chars, %d end chars, wlen=%d)",
305                         word, start, end, wlen);
306
307     return wlen;
308 }
309
310 swish_TokenList *
311 swish_init_token_list(
312 )
313 {
314     swish_TokenList *tl;
315     tl = swish_xmalloc(sizeof(swish_TokenList));
316     tl->buf = xmlBufferCreateSize((size_t) SWISH_BUFFER_CHUNK_SIZE);
317     tl->n = 0;
318     tl->pos = 0;
319     tl->ref_cnt = 0;
320     tl->tokens = swish_xmalloc(sizeof(swish_Token *) * SWISH_TOKEN_LIST_SIZE);
321     tl->contexts = swish_init_hash(8);
322
323     if (!ascii_init)
324         make_ascii_tables();
325
326     if (SWISH_DEBUG & SWISH_DEBUG_MEMORY) {
327         SWISH_DEBUG_MSG("TokenList ptr 0x%x", (long int)tl);
328         SWISH_DEBUG_MSG("TokenList->tokens ptr 0x%x", (long int)tl->tokens);
329     }
330
331     return tl;
332 }
333
334 void
335 swish_free_token_list(
336     swish_TokenList *tl
337 )
338 {
339     if (tl->ref_cnt != 0) {
340         SWISH_WARN("freeing TokenList with ref_cnt != 0 (%d)", tl->ref_cnt);
341     }
342
343     while (tl->n) {
344         tl->n--;
345         tl->tokens[tl->n]->ref_cnt--;
346         if (tl->tokens[tl->n]->ref_cnt < 1)
347             swish_free_token(tl->tokens[tl->n]);
348     }
349
350     swish_xfree(tl->tokens);
351     xmlBufferFree(tl->buf);
352     swish_hash_free(tl->contexts); // MUST free **after** tokens
353     swish_xfree(tl);
354 }
355
356 int
357 swish_add_token(
358     swish_TokenList *tl,
359     xmlChar *token,
360     int token_len,
361     swish_MetaName *meta,
362     xmlChar *context
363 )
364 {
365     int num_of_allocs;
366     swish_Token *stoken;
367     const xmlChar *buf;
368
369     if (!token_len || !xmlStrlen(token)) {
370         SWISH_CROAK("can't add empty token to token list");
371     }
372
373     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
374         SWISH_DEBUG_MSG("adding token: %s  meta=%s", token, meta->name);
375
376     stoken = swish_init_token();
377    
378     /* grab the current buffer and point ->value into the buffer */
379     buf = xmlBufferContent(tl->buf);
380     buf += xmlBufferLength(tl->buf);    // point at last byte which will become first byte
381     stoken->value = (xmlChar*)buf;
382     stoken->len = token_len - 1;    // -1 to exlude the NULL
383     stoken->pos = ++tl->pos;
384     stoken->meta = meta;
385     stoken->meta->ref_cnt++;
386    
387     /* cache the context string and point at the cached value */
388     swish_hash_exists_or_add( tl->contexts, context, context );
389     stoken->context = swish_hash_fetch( tl->contexts, context );
390    
391     stoken->ref_cnt++;
392     swish_set_token_value(tl, token, token_len);
393
394     num_of_allocs = tl->n / SWISH_TOKEN_LIST_SIZE;
395
396     if (SWISH_DEBUG & SWISH_DEBUG_MEMORY) {
397         SWISH_DEBUG_MSG("TokenList size: %d  num_allocs = %d  modulus %d", tl->n,
398                         num_of_allocs, tl->n % SWISH_TOKEN_LIST_SIZE);
399     }
400
401     if (num_of_allocs && !(tl->n % SWISH_TOKEN_LIST_SIZE)) {
402         if (SWISH_DEBUG & SWISH_DEBUG_MEMORY) {
403             SWISH_DEBUG_MSG("realloc for tokens: 0x%x", (long int)tl->tokens);
404         }
405
406         tl->tokens =
407             (swish_Token **)swish_xrealloc(tl->tokens,
408                                            sizeof(swish_Token) * (SWISH_TOKEN_LIST_SIZE *
409                                                                   ++num_of_allocs));
410
411     }
412     tl->tokens[tl->n++] = stoken;
413     return tl->n;
414 }
415
416 int
417 swish_set_token_value(
418     swish_TokenList *tl,
419     xmlChar *token,
420     int len
421 )
422 {
423     int ret;
424     ret = xmlBufferAdd(tl->buf, token, len);    // include the NULL
425     if (ret != 0) {
426         SWISH_CROAK("error appending token to buffer: %d", ret);
427     }
428     return ret;
429 }
430
431 swish_Token *
432 swish_init_token(
433 )
434 {
435     swish_Token *t;
436     t = swish_xmalloc(sizeof(swish_Token));
437     t->pos = 0;
438     t->meta = NULL;
439     t->context = NULL;
440     t->value = NULL;
441     t->len = 0;
442     t->ref_cnt = 0;
443     return t;
444 }
445
446 void
447 swish_free_token(
448     swish_Token *t
449 )
450 {
451     if (t->ref_cnt != 0) {
452         SWISH_WARN("freeing Token with ref_cnt != 0 (%d)", t->ref_cnt);
453     }
454    
455     if (SWISH_DEBUG & SWISH_DEBUG_MEMORY) {
456         SWISH_DEBUG_MSG("freeing Token 0x%x with MetaName ref_cnt %d",
457             (long int)t, t->meta->ref_cnt);
458     }
459    
460     t->meta->ref_cnt--;
461     if (t->meta->ref_cnt == 0) {
462         if (SWISH_DEBUG & SWISH_DEBUG_MEMORY) {
463             SWISH_DEBUG_MSG("Token's MetaName ref_cnt == 0 ... freeing MetaName");
464         }
465         swish_free_metaname(t->meta);
466     }
467    
468     swish_xfree(t);
469 }
470
471 void
472 swish_debug_token(
473     swish_Token *t
474 )
475 {
476     SWISH_DEBUG_MSG("\n\
477     t->ref_cnt      = %d\n\
478     t->pos          = %d\n\
479     t->context      = %s\n\
480     t->meta         = %d [%s]\n\
481     t->len          = %d\n\
482     t->value        = %s\n\
483     ", t->ref_cnt, t->pos, t->context, t->meta->id, t->meta->name, t->len, t->value);
484
485 }
486
487 void
488 swish_debug_token_list(
489     swish_TokenIterator *it
490 )
491 {
492     swish_Token *t;
493 /*
494     SWISH_DEBUG_MSG("Token buf:\n%s", xmlBufferContent(it->tl->buf));
495     SWISH_DEBUG_MSG("Number of tokens: %d", it->tl->n);
496 */
497     while ((t = swish_next_token(it)) != NULL) {
498         swish_debug_token(t);
499     }
500 }
501
502 swish_TokenIterator *
503 swish_init_token_iterator(
504     swish_Analyzer *a
505 )
506 {
507     swish_TokenIterator *it;
508     it = swish_xmalloc(sizeof(swish_TokenIterator));
509     it->a = a;
510     it->a->ref_cnt++;
511     it->pos = 0;
512     it->tl = swish_init_token_list();
513     it->tl->ref_cnt++;
514     it->ref_cnt = 0;
515     return it;
516 }
517
518 void
519 swish_free_token_iterator(
520     swish_TokenIterator *it
521 )
522 {
523     if (it->ref_cnt != 0) {
524         SWISH_WARN("freeing TokenIterator with ref_cnt != 0 (%d)", it->ref_cnt);
525     }
526    
527     if (SWISH_DEBUG & SWISH_DEBUG_MEMORY) {
528         SWISH_DEBUG_MSG(
529         "freeing TokenIterator %d with TokenList ref_cnt %d and Analyzer ref_cnt %d",
530         it, it->tl->ref_cnt, it->a->ref_cnt);
531     }
532    
533     it->a->ref_cnt--;
534     if (SWISH_DEBUG & SWISH_DEBUG_MEMORY) {
535         SWISH_DEBUG_MSG("freeing TokenIterator with Analyzer ref_cnt = %d",
536             it->a->ref_cnt);
537     }
538     if (it->a->ref_cnt == 0)
539         swish_free_analyzer(it->a);
540        
541     it->tl->ref_cnt--;
542     if (it->tl->ref_cnt == 0)
543         swish_free_token_list(it->tl);
544    
545     swish_xfree(it);
546 }
547
548 swish_Token *
549 swish_next_token(
550     swish_TokenIterator *it
551 )
552 {
553     swish_Token *t;
554     t = NULL;
555    
556 /* SWISH_DEBUG_MSG("next_token: %d %d", it->pos, it->tl->n); */
557     if (it->pos >= it->tl->n)
558         return NULL;
559
560    
561     t = it->tl->tokens[it->pos++];
562     return t;
563 }
564
565 /* returns number of tokens added to TokenList */
566 int
567 swish_tokenize3(
568     swish_TokenIterator *ti,
569     xmlChar *buf,
570     swish_MetaName *meta,
571     xmlChar *context
572 )
573 {
574     if (swish_is_ascii(buf)) {
575         return swish_tokenize3_ascii(ti, buf, meta, context);
576     }
577     else {
578         return swish_tokenize3_utf8(ti, buf, meta, context);
579     }
580 }
581
582 int
583 swish_tokenize3_utf8(
584     swish_TokenIterator *ti,
585     xmlChar *buf,
586     swish_MetaName *meta,
587     xmlChar *context
588 )
589 {
590     int nstart, byte_pos, prev_pos, i, chr_len, cp, token_len, maxwordlen, minwordlen;
591     swish_TokenList *tl;
592     boolean inside_token;
593     xmlChar chr[5];             /*  max len of UCS32 plus NULL */
594     xmlChar *token, *copy, *buf_lower;
595    
596     tl          = ti->tl;
597     maxwordlen      = ti->a->maxwordlen;
598     minwordlen      = ti->a->minwordlen;
599     token       = swish_xmalloc(sizeof(xmlChar) * maxwordlen);
600     buf_lower   = swish_utf8_str_tolower(buf);
601     nstart      = tl->n;
602     inside_token = 0;
603     byte_pos    = 0;
604     prev_pos    = 0;
605     token_len   = 0;
606
607     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
608         SWISH_DEBUG_MSG("starting tokenize3 for meta=%s", meta->name);
609
610 /*
611        iterate over each utf8 character, evaluating its Unicode value,
612        and creating tokens
613 */
614
615     for (byte_pos = 0; buf_lower[prev_pos] != '\0';
616          swish_utf8_next_chr(buf_lower, &byte_pos)) {
617         chr_len = byte_pos - prev_pos;
618         if (!chr_len) {
619             prev_pos = byte_pos;
620             continue;
621         }
622
623         for (i = 0; i < chr_len; i++) {
624             chr[i] = buf[prev_pos + i];
625         }
626         chr[i] = '\0';
627
628         cp = swish_utf8_codepoint(chr);
629
630         if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER) {
631             SWISH_DEBUG_MSG("%d %d: ut8 chr '%s' unicode %d  len %d next byte: %d",
632                             byte_pos, prev_pos, chr, cp, chr_len, buf[prev_pos + 1]);
633
634         }
635        
636         prev_pos = byte_pos;
637
638         if (is_ignore_word_utf8(cp)) {
639
640             if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
641                 SWISH_DEBUG_MSG("%s is ignore_word", chr);
642
643             if (inside_token) {
644                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
645                     SWISH_DEBUG_MSG("found end of token: '%s'", chr);
646
647                 inside_token = 0;       /*  turn off flag */
648
649                 token[++token_len] = '\0';
650                 copy = token;
651                 token_len = strip_utf8_chrs(token, token_len);
652
653                 if (token[0] != '\0' && token_len >= minwordlen) {
654
655                     swish_add_token(tl, token, token_len, meta, context);
656
657                 }
658                 else {
659                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
660                         SWISH_DEBUG_MSG("skipping token '%s' -- too short: %d", token,
661                                         token_len);
662                 }
663
664                 token = copy;   /*  restore to top of array so we do not leak */
665
666                 if (cp == SWISH_TOKENPOS_BUMPER[0]) {
667                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
668                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
669                     tl->pos++;
670                 }
671
672                 continue;
673
674             }
675             else {
676                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
677                     SWISH_DEBUG_MSG("ignoring chr '%s'", chr);
678
679                 if (cp == SWISH_TOKENPOS_BUMPER[0]) {
680                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
681                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
682                     tl->pos++;
683                 }
684
685                 continue;
686             }
687
688         }
689         else {
690
691             if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
692                 SWISH_DEBUG_MSG("%s is NOT ignore_word", chr);
693
694             if (inside_token) {
695
696                 /* edge case */
697                 if ((chr_len + token_len) > maxwordlen) {
698                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
699                         SWISH_DEBUG_MSG("token_len = %d  forcing end of token: '%s'",
700                                         token_len, chr);
701                     continue;
702                 }
703
704                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
705                     SWISH_DEBUG_MSG("adding to token: '%s'", chr);
706
707                 memcpy(&token[token_len], chr, chr_len * sizeof(xmlChar));
708                 token[token_len + chr_len] = '\0';
709                 token_len += chr_len;
710
711                 if (token_len >= maxwordlen || buf[byte_pos] == '\0') {
712
713                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
714                         SWISH_DEBUG_MSG("token_len = %d  forcing end of token: '%s'",
715                                         token_len, chr);
716
717                     inside_token = 0;   /*  turn off flag */
718
719                     token[++token_len] = '\0';
720                     copy = token;
721                     token_len = strip_utf8_chrs(token, token_len);
722
723                     if (token[0] != '\0' && token_len >= minwordlen) {
724
725                         swish_add_token(tl, token, token_len, meta, context);
726
727                     }
728                     else {
729                         if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
730                             SWISH_DEBUG_MSG("skipping token '%s' -- too short: %d", token,
731                                             token_len);
732                     }
733
734                     token = copy;       /*  restore to top of array */
735
736                 }
737
738                 if (cp == SWISH_TOKENPOS_BUMPER[0]) {
739                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
740                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
741                     tl->pos++;
742                 }
743
744                 continue;
745
746             }
747             else {
748
749                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
750                     SWISH_DEBUG_MSG("start a token with '%s'", chr);
751
752                 token[0] = '\0';
753                 token_len = 0;
754                 inside_token = 1;       /*  turn on flag */
755                 /* edge case */
756                 if (chr_len > maxwordlen)
757                     continue;
758
759                 memcpy(&token[0], chr, chr_len * sizeof(xmlChar));
760                 token[chr_len] = '\0';
761                 token_len += chr_len;
762                
763                 /* special case for one-character tokens */
764                 if (buf_lower[prev_pos] == '\0' && minwordlen == 1) {
765                     inside_token        = 0;
766                     token[token_len++]  = '\0';
767                     swish_add_token(tl, token, token_len, meta, context);
768                 }
769
770                 if (cp == SWISH_TOKENPOS_BUMPER[0]) {
771                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
772                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
773                     tl->pos++;
774                 }
775
776                 continue;
777
778             }
779
780         }
781
782     }
783
784     swish_xfree(token);
785     swish_xfree(buf_lower);
786     return tl->n - nstart;
787 }
788
789 int
790 swish_tokenize3_ascii(
791     swish_TokenIterator *ti,
792     xmlChar *buf,
793     swish_MetaName *meta,
794     xmlChar *context
795 )
796 {
797     char c, nextc;
798     boolean inside_token;
799     int i, token_len, nstart, maxwordlen, minwordlen;
800     xmlChar *token, *copy;
801     swish_TokenList *tl;
802    
803     tl              = ti->tl;
804     maxwordlen      = ti->a->maxwordlen;
805     minwordlen      = ti->a->minwordlen;
806     token           = swish_xmalloc(sizeof(xmlChar) * maxwordlen);
807     nstart          = tl->n;
808     token_len       = 0;
809     token[0]        = '\0';
810     inside_token    = 0;
811
812     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
813         SWISH_DEBUG_MSG("tokenizing string: '%s'", buf);
814
815     for (i = 0; buf[i] != '\0'; i++) {
816         c = (char)tolower(buf[i]);
817         nextc = (char)tolower(buf[i + 1]);
818
819         if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
820             SWISH_DEBUG_MSG(" char: %c lower: %c  int: %d %#x (next is %c)", buf[i], c,
821                             (int)c, (unsigned int)c, nextc);
822                            
823         if (!ascii_word_table[(int)c]) {
824
825             if (inside_token) {
826                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
827                     SWISH_DEBUG_MSG("found end of token: '%c' at %d", c, i);
828
829                 inside_token = 0;
830                 token[token_len++] = '\0';
831                 copy = token;
832                 token_len = strip_ascii_chrs(token, token_len);
833
834                 if (token[0] != '\0' && token_len >= minwordlen) {
835                     swish_add_token(tl, token, token_len, meta, context);
836                 }
837                 else {
838                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
839                         SWISH_DEBUG_MSG("skipping token '%s' -- too short: %d", token,
840                                         token_len);
841                 }
842
843                 token = copy;
844                
845                 if (c == SWISH_TOKENPOS_BUMPER[0]) {
846                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
847                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
848                     tl->pos++;
849                 }
850
851
852                 continue;
853
854             }
855             else {
856                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
857                     SWISH_DEBUG_MSG("ignoring char '%c'", c);
858
859                 if (c == SWISH_TOKENPOS_BUMPER[0]) {
860                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
861                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
862                     tl->pos++;
863                 }
864
865                 continue;
866             }
867
868         }
869         else {
870
871             if (inside_token) {
872
873                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
874                     SWISH_DEBUG_MSG("adding to token: '%c' %d", c, i);
875
876                 token[token_len++] = c;
877
878                 if (token_len >= maxwordlen || nextc == '\0') {
879
880                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
881                         SWISH_DEBUG_MSG("forcing end of token: '%c' %d", c, i);
882
883                     inside_token = 0;
884
885                     token[token_len++] = '\0';
886                     copy = token;
887                     token_len = strip_ascii_chrs(token, token_len);
888
889                     if (token[0] != '\0' && token_len >= minwordlen) {
890                         swish_add_token(tl, token, token_len, meta, context);
891                     }
892                     else {
893                         if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
894                             SWISH_DEBUG_MSG("skipping token '%s' -- too short: %d", token,
895                                             token_len);
896                     }
897
898                     token = copy;
899
900                 }
901
902                 if (c == SWISH_TOKENPOS_BUMPER[0]) {
903                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
904                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
905                     tl->pos++;
906                 }
907
908                 continue;
909
910             }
911             else {
912
913                 if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
914                     SWISH_DEBUG_MSG("start a token with '%c' %d", c, i);
915
916                 token_len = 0;
917                 inside_token = 1;
918                 token[token_len++] = c;
919                
920                 /* special case for one-character tokens */
921                 if (nextc == '\0' && minwordlen == 1) {
922                     inside_token        = 0;
923                     token[token_len++]  = '\0';
924                     swish_add_token(tl, token, token_len, meta, context);
925                 }
926                
927                 if (c == SWISH_TOKENPOS_BUMPER[0]) {
928                     if (SWISH_DEBUG & SWISH_DEBUG_TOKENIZER)
929                         SWISH_DEBUG_MSG("found tokenpos bumper byte at pos %d", tl->pos);
930                     tl->pos++;
931                 }
932
933                 continue;
934
935             }
936
937         }
938
939     }
940
941     swish_xfree(token);
942     return tl->n - nstart;
943 }
Note: See TracBrowser for help on using the browser.