Annotation of embedaddon/sqlite3/ext/fts2/fts2_icu.c, revision 1.1

1.1     ! misho       1: /*
        !             2: ** 2007 June 22
        !             3: **
        !             4: ** The author disclaims copyright to this source code.  In place of
        !             5: ** a legal notice, here is a blessing:
        !             6: **
        !             7: **    May you do good and not evil.
        !             8: **    May you find forgiveness for yourself and forgive others.
        !             9: **    May you share freely, never taking more than you give.
        !            10: **
        !            11: *************************************************************************
        !            12: ** This file implements a tokenizer for fts2 based on the ICU library.
        !            13: ** 
        !            14: ** $Id: fts2_icu.c,v 1.3 2008/12/18 05:30:26 danielk1977 Exp $
        !            15: */
        !            16: 
        !            17: #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2)
        !            18: #ifdef SQLITE_ENABLE_ICU
        !            19: 
        !            20: #include <assert.h>
        !            21: #include <string.h>
        !            22: #include "fts2_tokenizer.h"
        !            23: 
        !            24: #include <unicode/ubrk.h>
        !            25: #include <unicode/ucol.h>
        !            26: #include <unicode/ustring.h>
        !            27: #include <unicode/utf16.h>
        !            28: 
        !            29: typedef struct IcuTokenizer IcuTokenizer;
        !            30: typedef struct IcuCursor IcuCursor;
        !            31: 
        !            32: struct IcuTokenizer {
        !            33:   sqlite3_tokenizer base;
        !            34:   char *zLocale;
        !            35: };
        !            36: 
        !            37: struct IcuCursor {
        !            38:   sqlite3_tokenizer_cursor base;
        !            39: 
        !            40:   UBreakIterator *pIter;      /* ICU break-iterator object */
        !            41:   int nChar;                  /* Number of UChar elements in pInput */
        !            42:   UChar *aChar;               /* Copy of input using utf-16 encoding */
        !            43:   int *aOffset;               /* Offsets of each character in utf-8 input */
        !            44: 
        !            45:   int nBuffer;
        !            46:   char *zBuffer;
        !            47: 
        !            48:   int iToken;
        !            49: };
        !            50: 
        !            51: /*
        !            52: ** Create a new tokenizer instance.
        !            53: */
        !            54: static int icuCreate(
        !            55:   int argc,                            /* Number of entries in argv[] */
        !            56:   const char * const *argv,            /* Tokenizer creation arguments */
        !            57:   sqlite3_tokenizer **ppTokenizer      /* OUT: Created tokenizer */
        !            58: ){
        !            59:   IcuTokenizer *p;
        !            60:   int n = 0;
        !            61: 
        !            62:   if( argc>0 ){
        !            63:     n = strlen(argv[0])+1;
        !            64:   }
        !            65:   p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n);
        !            66:   if( !p ){
        !            67:     return SQLITE_NOMEM;
        !            68:   }
        !            69:   memset(p, 0, sizeof(IcuTokenizer));
        !            70: 
        !            71:   if( n ){
        !            72:     p->zLocale = (char *)&p[1];
        !            73:     memcpy(p->zLocale, argv[0], n);
        !            74:   }
        !            75: 
        !            76:   *ppTokenizer = (sqlite3_tokenizer *)p;
        !            77: 
        !            78:   return SQLITE_OK;
        !            79: }
        !            80: 
        !            81: /*
        !            82: ** Destroy a tokenizer
        !            83: */
        !            84: static int icuDestroy(sqlite3_tokenizer *pTokenizer){
        !            85:   IcuTokenizer *p = (IcuTokenizer *)pTokenizer;
        !            86:   sqlite3_free(p);
        !            87:   return SQLITE_OK;
        !            88: }
        !            89: 
        !            90: /*
        !            91: ** Prepare to begin tokenizing a particular string.  The input
        !            92: ** string to be tokenized is pInput[0..nBytes-1].  A cursor
        !            93: ** used to incrementally tokenize this string is returned in 
        !            94: ** *ppCursor.
        !            95: */
        !            96: static int icuOpen(
        !            97:   sqlite3_tokenizer *pTokenizer,         /* The tokenizer */
        !            98:   const char *zInput,                    /* Input string */
        !            99:   int nInput,                            /* Length of zInput in bytes */
        !           100:   sqlite3_tokenizer_cursor **ppCursor    /* OUT: Tokenization cursor */
        !           101: ){
        !           102:   IcuTokenizer *p = (IcuTokenizer *)pTokenizer;
        !           103:   IcuCursor *pCsr;
        !           104: 
        !           105:   const int32_t opt = U_FOLD_CASE_DEFAULT;
        !           106:   UErrorCode status = U_ZERO_ERROR;
        !           107:   int nChar;
        !           108: 
        !           109:   UChar32 c;
        !           110:   int iInput = 0;
        !           111:   int iOut = 0;
        !           112: 
        !           113:   *ppCursor = 0;
        !           114: 
        !           115:   if( nInput<0 ){
        !           116:     nInput = strlen(zInput);
        !           117:   }
        !           118:   nChar = nInput+1;
        !           119:   pCsr = (IcuCursor *)sqlite3_malloc(
        !           120:       sizeof(IcuCursor) +                /* IcuCursor */
        !           121:       nChar * sizeof(UChar) +            /* IcuCursor.aChar[] */
        !           122:       (nChar+1) * sizeof(int)            /* IcuCursor.aOffset[] */
        !           123:   );
        !           124:   if( !pCsr ){
        !           125:     return SQLITE_NOMEM;
        !           126:   }
        !           127:   memset(pCsr, 0, sizeof(IcuCursor));
        !           128:   pCsr->aChar = (UChar *)&pCsr[1];
        !           129:   pCsr->aOffset = (int *)&pCsr->aChar[nChar];
        !           130: 
        !           131:   pCsr->aOffset[iOut] = iInput;
        !           132:   U8_NEXT(zInput, iInput, nInput, c); 
        !           133:   while( c>0 ){
        !           134:     int isError = 0;
        !           135:     c = u_foldCase(c, opt);
        !           136:     U16_APPEND(pCsr->aChar, iOut, nChar, c, isError);
        !           137:     if( isError ){
        !           138:       sqlite3_free(pCsr);
        !           139:       return SQLITE_ERROR;
        !           140:     }
        !           141:     pCsr->aOffset[iOut] = iInput;
        !           142: 
        !           143:     if( iInput<nInput ){
        !           144:       U8_NEXT(zInput, iInput, nInput, c);
        !           145:     }else{
        !           146:       c = 0;
        !           147:     }
        !           148:   }
        !           149: 
        !           150:   pCsr->pIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status);
        !           151:   if( !U_SUCCESS(status) ){
        !           152:     sqlite3_free(pCsr);
        !           153:     return SQLITE_ERROR;
        !           154:   }
        !           155:   pCsr->nChar = iOut;
        !           156: 
        !           157:   ubrk_first(pCsr->pIter);
        !           158:   *ppCursor = (sqlite3_tokenizer_cursor *)pCsr;
        !           159:   return SQLITE_OK;
        !           160: }
        !           161: 
        !           162: /*
        !           163: ** Close a tokenization cursor previously opened by a call to icuOpen().
        !           164: */
        !           165: static int icuClose(sqlite3_tokenizer_cursor *pCursor){
        !           166:   IcuCursor *pCsr = (IcuCursor *)pCursor;
        !           167:   ubrk_close(pCsr->pIter);
        !           168:   sqlite3_free(pCsr->zBuffer);
        !           169:   sqlite3_free(pCsr);
        !           170:   return SQLITE_OK;
        !           171: }
        !           172: 
        !           173: /*
        !           174: ** Extract the next token from a tokenization cursor.
        !           175: */
        !           176: static int icuNext(
        !           177:   sqlite3_tokenizer_cursor *pCursor,  /* Cursor returned by simpleOpen */
        !           178:   const char **ppToken,               /* OUT: *ppToken is the token text */
        !           179:   int *pnBytes,                       /* OUT: Number of bytes in token */
        !           180:   int *piStartOffset,                 /* OUT: Starting offset of token */
        !           181:   int *piEndOffset,                   /* OUT: Ending offset of token */
        !           182:   int *piPosition                     /* OUT: Position integer of token */
        !           183: ){
        !           184:   IcuCursor *pCsr = (IcuCursor *)pCursor;
        !           185: 
        !           186:   int iStart = 0;
        !           187:   int iEnd = 0;
        !           188:   int nByte = 0;
        !           189: 
        !           190:   while( iStart==iEnd ){
        !           191:     UChar32 c;
        !           192: 
        !           193:     iStart = ubrk_current(pCsr->pIter);
        !           194:     iEnd = ubrk_next(pCsr->pIter);
        !           195:     if( iEnd==UBRK_DONE ){
        !           196:       return SQLITE_DONE;
        !           197:     }
        !           198: 
        !           199:     while( iStart<iEnd ){
        !           200:       int iWhite = iStart;
        !           201:       U8_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c);
        !           202:       if( u_isspace(c) ){
        !           203:         iStart = iWhite;
        !           204:       }else{
        !           205:         break;
        !           206:       }
        !           207:     }
        !           208:     assert(iStart<=iEnd);
        !           209:   }
        !           210: 
        !           211:   do {
        !           212:     UErrorCode status = U_ZERO_ERROR;
        !           213:     if( nByte ){
        !           214:       char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte);
        !           215:       if( !zNew ){
        !           216:         return SQLITE_NOMEM;
        !           217:       }
        !           218:       pCsr->zBuffer = zNew;
        !           219:       pCsr->nBuffer = nByte;
        !           220:     }
        !           221: 
        !           222:     u_strToUTF8(
        !           223:         pCsr->zBuffer, pCsr->nBuffer, &nByte,    /* Output vars */
        !           224:         &pCsr->aChar[iStart], iEnd-iStart,       /* Input vars */
        !           225:         &status                                  /* Output success/failure */
        !           226:     );
        !           227:   } while( nByte>pCsr->nBuffer );
        !           228: 
        !           229:   *ppToken = pCsr->zBuffer;
        !           230:   *pnBytes = nByte;
        !           231:   *piStartOffset = pCsr->aOffset[iStart];
        !           232:   *piEndOffset = pCsr->aOffset[iEnd];
        !           233:   *piPosition = pCsr->iToken++;
        !           234: 
        !           235:   return SQLITE_OK;
        !           236: }
        !           237: 
        !           238: /*
        !           239: ** The set of routines that implement the simple tokenizer
        !           240: */
        !           241: static const sqlite3_tokenizer_module icuTokenizerModule = {
        !           242:   0,                           /* iVersion */
        !           243:   icuCreate,                   /* xCreate  */
        !           244:   icuDestroy,                  /* xCreate  */
        !           245:   icuOpen,                     /* xOpen    */
        !           246:   icuClose,                    /* xClose   */
        !           247:   icuNext,                     /* xNext    */
        !           248: };
        !           249: 
        !           250: /*
        !           251: ** Set *ppModule to point at the implementation of the ICU tokenizer.
        !           252: */
        !           253: void sqlite3Fts2IcuTokenizerModule(
        !           254:   sqlite3_tokenizer_module const**ppModule
        !           255: ){
        !           256:   *ppModule = &icuTokenizerModule;
        !           257: }
        !           258: 
        !           259: #endif /* defined(SQLITE_ENABLE_ICU) */
        !           260: #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */

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