1
0

simple_tokenizer.c 4.7 KB

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