Annotation of embedaddon/sqlite3/ext/fts1/fts1_tokenizer1.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: /*
        !             9: ** The code in this file is only compiled if:
        !            10: **
        !            11: **     * The FTS1 module is being built as an extension
        !            12: **       (in which case SQLITE_CORE is not defined), or
        !            13: **
        !            14: **     * The FTS1 module is being built into the core of
        !            15: **       SQLite (in which case SQLITE_ENABLE_FTS1 is defined).
        !            16: */
        !            17: #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1)
        !            18: 
        !            19: 
        !            20: #include <assert.h>
        !            21: #include <stdlib.h>
        !            22: #include <stdio.h>
        !            23: #include <string.h>
        !            24: #include <ctype.h>
        !            25: 
        !            26: #include "fts1_tokenizer.h"
        !            27: 
        !            28: typedef struct simple_tokenizer {
        !            29:   sqlite3_tokenizer base;
        !            30:   char delim[128];             /* flag ASCII delimiters */
        !            31: } simple_tokenizer;
        !            32: 
        !            33: typedef struct simple_tokenizer_cursor {
        !            34:   sqlite3_tokenizer_cursor base;
        !            35:   const char *pInput;          /* input we are tokenizing */
        !            36:   int nBytes;                  /* size of the input */
        !            37:   int iOffset;                 /* current position in pInput */
        !            38:   int iToken;                  /* index of next token to be returned */
        !            39:   char *pToken;                /* storage for current token */
        !            40:   int nTokenAllocated;         /* space allocated to zToken buffer */
        !            41: } simple_tokenizer_cursor;
        !            42: 
        !            43: 
        !            44: /* Forward declaration */
        !            45: static const sqlite3_tokenizer_module simpleTokenizerModule;
        !            46: 
        !            47: static int isDelim(simple_tokenizer *t, unsigned char c){
        !            48:   return c<0x80 && t->delim[c];
        !            49: }
        !            50: 
        !            51: /*
        !            52: ** Create a new tokenizer instance.
        !            53: */
        !            54: static int simpleCreate(
        !            55:   int argc, const char * const *argv,
        !            56:   sqlite3_tokenizer **ppTokenizer
        !            57: ){
        !            58:   simple_tokenizer *t;
        !            59: 
        !            60:   t = (simple_tokenizer *) calloc(sizeof(*t), 1);
        !            61:   if( t==NULL ) return SQLITE_NOMEM;
        !            62: 
        !            63:   /* TODO(shess) Delimiters need to remain the same from run to run,
        !            64:   ** else we need to reindex.  One solution would be a meta-table to
        !            65:   ** track such information in the database, then we'd only want this
        !            66:   ** information on the initial create.
        !            67:   */
        !            68:   if( argc>1 ){
        !            69:     int i, n = strlen(argv[1]);
        !            70:     for(i=0; i<n; i++){
        !            71:       unsigned char ch = argv[1][i];
        !            72:       /* We explicitly don't support UTF-8 delimiters for now. */
        !            73:       if( ch>=0x80 ){
        !            74:         free(t);
        !            75:         return SQLITE_ERROR;
        !            76:       }
        !            77:       t->delim[ch] = 1;
        !            78:     }
        !            79:   } else {
        !            80:     /* Mark non-alphanumeric ASCII characters as delimiters */
        !            81:     int i;
        !            82:     for(i=1; i<0x80; i++){
        !            83:       t->delim[i] = !isalnum(i);
        !            84:     }
        !            85:   }
        !            86: 
        !            87:   *ppTokenizer = &t->base;
        !            88:   return SQLITE_OK;
        !            89: }
        !            90: 
        !            91: /*
        !            92: ** Destroy a tokenizer
        !            93: */
        !            94: static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
        !            95:   free(pTokenizer);
        !            96:   return SQLITE_OK;
        !            97: }
        !            98: 
        !            99: /*
        !           100: ** Prepare to begin tokenizing a particular string.  The input
        !           101: ** string to be tokenized is pInput[0..nBytes-1].  A cursor
        !           102: ** used to incrementally tokenize this string is returned in 
        !           103: ** *ppCursor.
        !           104: */
        !           105: static int simpleOpen(
        !           106:   sqlite3_tokenizer *pTokenizer,         /* The tokenizer */
        !           107:   const char *pInput, int nBytes,        /* String to be tokenized */
        !           108:   sqlite3_tokenizer_cursor **ppCursor    /* OUT: Tokenization cursor */
        !           109: ){
        !           110:   simple_tokenizer_cursor *c;
        !           111: 
        !           112:   c = (simple_tokenizer_cursor *) malloc(sizeof(*c));
        !           113:   if( c==NULL ) return SQLITE_NOMEM;
        !           114: 
        !           115:   c->pInput = pInput;
        !           116:   if( pInput==0 ){
        !           117:     c->nBytes = 0;
        !           118:   }else if( nBytes<0 ){
        !           119:     c->nBytes = (int)strlen(pInput);
        !           120:   }else{
        !           121:     c->nBytes = nBytes;
        !           122:   }
        !           123:   c->iOffset = 0;                 /* start tokenizing at the beginning */
        !           124:   c->iToken = 0;
        !           125:   c->pToken = NULL;               /* no space allocated, yet. */
        !           126:   c->nTokenAllocated = 0;
        !           127: 
        !           128:   *ppCursor = &c->base;
        !           129:   return SQLITE_OK;
        !           130: }
        !           131: 
        !           132: /*
        !           133: ** Close a tokenization cursor previously opened by a call to
        !           134: ** simpleOpen() above.
        !           135: */
        !           136: static int simpleClose(sqlite3_tokenizer_cursor *pCursor){
        !           137:   simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
        !           138:   free(c->pToken);
        !           139:   free(c);
        !           140:   return SQLITE_OK;
        !           141: }
        !           142: 
        !           143: /*
        !           144: ** Extract the next token from a tokenization cursor.  The cursor must
        !           145: ** have been opened by a prior call to simpleOpen().
        !           146: */
        !           147: static int simpleNext(
        !           148:   sqlite3_tokenizer_cursor *pCursor,  /* Cursor returned by simpleOpen */
        !           149:   const char **ppToken,               /* OUT: *ppToken is the token text */
        !           150:   int *pnBytes,                       /* OUT: Number of bytes in token */
        !           151:   int *piStartOffset,                 /* OUT: Starting offset of token */
        !           152:   int *piEndOffset,                   /* OUT: Ending offset of token */
        !           153:   int *piPosition                     /* OUT: Position integer of token */
        !           154: ){
        !           155:   simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor;
        !           156:   simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer;
        !           157:   unsigned char *p = (unsigned char *)c->pInput;
        !           158: 
        !           159:   while( c->iOffset<c->nBytes ){
        !           160:     int iStartOffset;
        !           161: 
        !           162:     /* Scan past delimiter characters */
        !           163:     while( c->iOffset<c->nBytes && isDelim(t, p[c->iOffset]) ){
        !           164:       c->iOffset++;
        !           165:     }
        !           166: 
        !           167:     /* Count non-delimiter characters. */
        !           168:     iStartOffset = c->iOffset;
        !           169:     while( c->iOffset<c->nBytes && !isDelim(t, p[c->iOffset]) ){
        !           170:       c->iOffset++;
        !           171:     }
        !           172: 
        !           173:     if( c->iOffset>iStartOffset ){
        !           174:       int i, n = c->iOffset-iStartOffset;
        !           175:       if( n>c->nTokenAllocated ){
        !           176:         c->nTokenAllocated = n+20;
        !           177:         c->pToken = realloc(c->pToken, c->nTokenAllocated);
        !           178:         if( c->pToken==NULL ) return SQLITE_NOMEM;
        !           179:       }
        !           180:       for(i=0; i<n; i++){
        !           181:         /* TODO(shess) This needs expansion to handle UTF-8
        !           182:         ** case-insensitivity.
        !           183:         */
        !           184:         unsigned char ch = p[iStartOffset+i];
        !           185:         c->pToken[i] = ch<0x80 ? tolower(ch) : ch;
        !           186:       }
        !           187:       *ppToken = c->pToken;
        !           188:       *pnBytes = n;
        !           189:       *piStartOffset = iStartOffset;
        !           190:       *piEndOffset = c->iOffset;
        !           191:       *piPosition = c->iToken++;
        !           192: 
        !           193:       return SQLITE_OK;
        !           194:     }
        !           195:   }
        !           196:   return SQLITE_DONE;
        !           197: }
        !           198: 
        !           199: /*
        !           200: ** The set of routines that implement the simple tokenizer
        !           201: */
        !           202: static const sqlite3_tokenizer_module simpleTokenizerModule = {
        !           203:   0,
        !           204:   simpleCreate,
        !           205:   simpleDestroy,
        !           206:   simpleOpen,
        !           207:   simpleClose,
        !           208:   simpleNext,
        !           209: };
        !           210: 
        !           211: /*
        !           212: ** Allocate a new simple tokenizer.  Return a pointer to the new
        !           213: ** tokenizer in *ppModule
        !           214: */
        !           215: void sqlite3Fts1SimpleTokenizerModule(
        !           216:   sqlite3_tokenizer_module const**ppModule
        !           217: ){
        !           218:   *ppModule = &simpleTokenizerModule;
        !           219: }
        !           220: 
        !           221: #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */

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