Annotation of embedaddon/sqlite3/ext/fts1/simple_tokenizer.c, revision 1.1

1.1     ! misho       1: /*
        !             2: ** The author disclaims copyright to this source code.
        !             3: **
        !             4: *************************************************************************
        !             5: ** Implementation of the "simple" full-text-search tokenizer.
        !             6: */
        !             7: 
        !             8: #include <assert.h>
        !             9: #if !defined(__APPLE__)
        !            10: #include <malloc.h>
        !            11: #else
        !            12: #include <stdlib.h>
        !            13: #endif
        !            14: #include <stdio.h>
        !            15: #include <string.h>
        !            16: #include <ctype.h>
        !            17: 
        !            18: #include "tokenizer.h"
        !            19: 
        !            20: /* Duplicate a string; the caller must free() the returned string.
        !            21:  * (We don't use strdup() since it's not part of the standard C library and
        !            22:  * may not be available everywhere.) */
        !            23: /* TODO(shess) Copied from fulltext.c, consider util.c for such
        !            24: ** things. */
        !            25: static char *string_dup(const char *s){
        !            26:   char *str = malloc(strlen(s) + 1);
        !            27:   strcpy(str, s);
        !            28:   return str;
        !            29: }
        !            30: 
        !            31: typedef struct simple_tokenizer {
        !            32:   sqlite3_tokenizer base;
        !            33:   const char *zDelim;          /* token delimiters */
        !            34: } simple_tokenizer;
        !            35: 
        !            36: typedef struct simple_tokenizer_cursor {
        !            37:   sqlite3_tokenizer_cursor base;
        !            38:   const char *pInput;          /* input we are tokenizing */
        !            39:   int nBytes;                  /* size of the input */
        !            40:   const char *pCurrent;        /* current position in pInput */
        !            41:   int iToken;                  /* index of next token to be returned */
        !            42:   char *zToken;                /* storage for current token */
        !            43:   int nTokenBytes;             /* actual size of current token */
        !            44:   int nTokenAllocated;         /* space allocated to zToken buffer */
        !            45: } simple_tokenizer_cursor;
        !            46: 
        !            47: static sqlite3_tokenizer_module simpleTokenizerModule;/* forward declaration */
        !            48: 
        !            49: static int simpleCreate(
        !            50:   int argc, const char **argv,
        !            51:   sqlite3_tokenizer **ppTokenizer
        !            52: ){
        !            53:   simple_tokenizer *t;
        !            54: 
        !            55:   t = (simple_tokenizer *) malloc(sizeof(simple_tokenizer));
        !            56:   /* TODO(shess) Delimiters need to remain the same from run to run,
        !            57:   ** else we need to reindex.  One solution would be a meta-table to
        !            58:   ** track such information in the database, then we'd only want this
        !            59:   ** information on the initial create.
        !            60:   */
        !            61:   if( argc>1 ){
        !            62:     t->zDelim = string_dup(argv[1]);
        !            63:   } else {
        !            64:     /* Build a string excluding alphanumeric ASCII characters */
        !            65:     char zDelim[0x80];               /* nul-terminated, so nul not a member */
        !            66:     int i, j;
        !            67:     for(i=1, j=0; i<0x80; i++){
        !            68:       if( !isalnum(i) ){
        !            69:         zDelim[j++] = i;
        !            70:       }
        !            71:     }
        !            72:     zDelim[j++] = '\0';
        !            73:     assert( j<=sizeof(zDelim) );
        !            74:     t->zDelim = string_dup(zDelim);
        !            75:   }
        !            76: 
        !            77:   *ppTokenizer = &t->base;
        !            78:   return SQLITE_OK;
        !            79: }
        !            80: 
        !            81: static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
        !            82:   simple_tokenizer *t = (simple_tokenizer *) pTokenizer;
        !            83: 
        !            84:   free((void *) t->zDelim);
        !            85:   free(t);
        !            86: 
        !            87:   return SQLITE_OK;
        !            88: }
        !            89: 
        !            90: static int simpleOpen(
        !            91:   sqlite3_tokenizer *pTokenizer,
        !            92:   const char *pInput, int nBytes,
        !            93:   sqlite3_tokenizer_cursor **ppCursor
        !            94: ){
        !            95:   simple_tokenizer_cursor *c;
        !            96: 
        !            97:   c = (simple_tokenizer_cursor *) malloc(sizeof(simple_tokenizer_cursor));
        !            98:   c->pInput = pInput;
        !            99:   c->nBytes = nBytes<0 ? (int) strlen(pInput) : nBytes;
        !           100:   c->pCurrent = c->pInput;        /* start tokenizing at the beginning */
        !           101:   c->iToken = 0;
        !           102:   c->zToken = NULL;               /* no space allocated, yet. */
        !           103:   c->nTokenBytes = 0;
        !           104:   c->nTokenAllocated = 0;
        !           105: 
        !           106:   *ppCursor = &c->base;
        !           107:   return SQLITE_OK;
        !           108: }
        !           109: 
        !           110: static int simpleClose(sqlite3_tokenizer_cursor *pCursor){
        !           111:   simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
        !           112: 
        !           113:   if( NULL!=c->zToken ){
        !           114:     free(c->zToken);
        !           115:   }
        !           116:   free(c);
        !           117: 
        !           118:   return SQLITE_OK;
        !           119: }
        !           120: 
        !           121: static int simpleNext(
        !           122:   sqlite3_tokenizer_cursor *pCursor,
        !           123:   const char **ppToken, int *pnBytes,
        !           124:   int *piStartOffset, int *piEndOffset, int *piPosition
        !           125: ){
        !           126:   simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
        !           127:   simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer;
        !           128:   int ii;
        !           129: 
        !           130:   while( c->pCurrent-c->pInput<c->nBytes ){
        !           131:     int n = (int) strcspn(c->pCurrent, t->zDelim);
        !           132:     if( n>0 ){
        !           133:       if( n+1>c->nTokenAllocated ){
        !           134:         c->zToken = realloc(c->zToken, n+1);
        !           135:       }
        !           136:       for(ii=0; ii<n; ii++){
        !           137:         /* TODO(shess) This needs expansion to handle UTF-8
        !           138:         ** case-insensitivity.
        !           139:         */
        !           140:         char ch = c->pCurrent[ii];
        !           141:         c->zToken[ii] = (unsigned char)ch<0x80 ? tolower(ch) : ch;
        !           142:       }
        !           143:       c->zToken[n] = '\0';
        !           144:       *ppToken = c->zToken;
        !           145:       *pnBytes = n;
        !           146:       *piStartOffset = (int) (c->pCurrent-c->pInput);
        !           147:       *piEndOffset = *piStartOffset+n;
        !           148:       *piPosition = c->iToken++;
        !           149:       c->pCurrent += n + 1;
        !           150: 
        !           151:       return SQLITE_OK;
        !           152:     }
        !           153:     c->pCurrent += n + 1;
        !           154:     /* TODO(shess) could strspn() to skip delimiters en masse.  Needs
        !           155:     ** to happen in two places, though, which is annoying.
        !           156:     */
        !           157:   }
        !           158:   return SQLITE_DONE;
        !           159: }
        !           160: 
        !           161: static sqlite3_tokenizer_module simpleTokenizerModule = {
        !           162:   0,
        !           163:   simpleCreate,
        !           164:   simpleDestroy,
        !           165:   simpleOpen,
        !           166:   simpleClose,
        !           167:   simpleNext,
        !           168: };
        !           169: 
        !           170: void get_simple_tokenizer_module(
        !           171:   sqlite3_tokenizer_module **ppModule
        !           172: ){
        !           173:   *ppModule = &simpleTokenizerModule;
        !           174: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>