main.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * lws-api-test-fts - lws full-text search api test
  3. *
  4. * Written in 2010-2019 by Andy Green <[email protected]>
  5. *
  6. * This file is made available under the Creative Commons CC0 1.0
  7. * Universal Public Domain Dedication.
  8. */
  9. #include <libwebsockets.h>
  10. #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
  11. #include <getopt.h>
  12. #endif
  13. #include <fcntl.h>
  14. #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
  15. static struct option options[] = {
  16. { "help", no_argument, NULL, 'h' },
  17. { "createindex", no_argument, NULL, 'c' },
  18. { "index", required_argument, NULL, 'i' },
  19. { "debug", required_argument, NULL, 'd' },
  20. { "file", required_argument, NULL, 'f' },
  21. { "lines", required_argument, NULL, 'l' },
  22. { NULL, 0, 0, 0 }
  23. };
  24. #endif
  25. static const char *index_filepath = "/tmp/lws-fts-test-index";
  26. static char filepath[256];
  27. int main(int argc, char **argv)
  28. {
  29. int n, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
  30. int fd, fi, ft, createindex = 0, flags = LWSFTS_F_QUERY_AUTOCOMPLETE;
  31. struct lws_fts_search_params params;
  32. struct lws_fts_result *result;
  33. struct lws_fts_file *jtf;
  34. struct lws_fts *t;
  35. char buf[16384];
  36. do {
  37. #if defined(LWS_HAS_GETOPT_LONG) || defined(WIN32)
  38. n = getopt_long(argc, argv, "hd:i:cfl", options, NULL);
  39. #else
  40. n = getopt(argc, argv, "hd:i:cfl");
  41. #endif
  42. if (n < 0)
  43. continue;
  44. switch (n) {
  45. case 'i':
  46. strncpy(filepath, optarg, sizeof(filepath) - 1);
  47. filepath[sizeof(filepath) - 1] = '\0';
  48. index_filepath = filepath;
  49. break;
  50. case 'd':
  51. logs = atoi(optarg);
  52. break;
  53. case 'c':
  54. createindex = 1;
  55. break;
  56. case 'f':
  57. flags &= ~LWSFTS_F_QUERY_AUTOCOMPLETE;
  58. flags |= LWSFTS_F_QUERY_FILES;
  59. break;
  60. case 'l':
  61. flags |= LWSFTS_F_QUERY_FILES |
  62. LWSFTS_F_QUERY_FILE_LINES;
  63. break;
  64. case 'h':
  65. fprintf(stderr,
  66. "Usage: %s [--createindex]"
  67. "[--index=<index filepath>] "
  68. "[-d <log bitfield>] file1 file2 \n",
  69. argv[0]);
  70. exit(1);
  71. }
  72. } while (n >= 0);
  73. lws_set_log_level(logs, NULL);
  74. lwsl_user("LWS API selftest: full-text search\n");
  75. if (createindex) {
  76. lwsl_notice("Creating index\n");
  77. /*
  78. * create an index by shifting through argv and indexing each
  79. * file given there into a single combined index
  80. */
  81. ft = open(index_filepath, O_CREAT | O_WRONLY | O_TRUNC, 0600);
  82. if (ft < 0) {
  83. lwsl_err("%s: can't open index %s\n", __func__,
  84. index_filepath);
  85. goto bail;
  86. }
  87. t = lws_fts_create(ft);
  88. if (!t) {
  89. lwsl_err("%s: Unable to allocate trie\n", __func__);
  90. goto bail1;
  91. }
  92. while (optind < argc) {
  93. fi = lws_fts_file_index(t, argv[optind],
  94. strlen(argv[optind]), 1);
  95. if (fi < 0) {
  96. lwsl_err("%s: Failed to get file idx for %s\n",
  97. __func__, argv[optind]);
  98. goto bail1;
  99. }
  100. fd = open(argv[optind], O_RDONLY);
  101. if (fd < 0) {
  102. lwsl_err("unable to open %s for read\n",
  103. argv[optind]);
  104. goto bail;
  105. }
  106. do {
  107. int n = read(fd, buf, sizeof(buf));
  108. if (n <= 0)
  109. break;
  110. if (lws_fts_fill(t, fi, buf, n)) {
  111. lwsl_err("%s: lws_fts_fill failed\n",
  112. __func__);
  113. close(fd);
  114. goto bail;
  115. }
  116. } while (1);
  117. close(fd);
  118. optind++;
  119. }
  120. if (lws_fts_serialize(t)) {
  121. lwsl_err("%s: serialize failed\n", __func__);
  122. goto bail;
  123. }
  124. lws_fts_destroy(&t);
  125. close(ft);
  126. return 0;
  127. }
  128. /*
  129. * shift through argv searching for each token
  130. */
  131. jtf = lws_fts_open(index_filepath);
  132. if (!jtf)
  133. goto bail;
  134. while (optind < argc) {
  135. struct lws_fts_result_autocomplete *ac;
  136. struct lws_fts_result_filepath *fp;
  137. uint32_t *l, n;
  138. memset(&params, 0, sizeof(params));
  139. params.needle = argv[optind];
  140. params.flags = flags;
  141. params.max_autocomplete = 20;
  142. params.max_files = 20;
  143. result = lws_fts_search(jtf, &params);
  144. if (!result) {
  145. lwsl_err("%s: search failed\n", __func__);
  146. lws_fts_close(jtf);
  147. goto bail;
  148. }
  149. ac = result->autocomplete_head;
  150. fp = result->filepath_head;
  151. if (!ac)
  152. lwsl_notice("%s: no autocomplete results\n", __func__);
  153. while (ac) {
  154. lwsl_notice("%s: AC %s: %d agg hits\n", __func__,
  155. ((char *)(ac + 1)), ac->instances);
  156. ac = ac->next;
  157. }
  158. if (!fp)
  159. lwsl_notice("%s: no filepath results\n", __func__);
  160. while (fp) {
  161. lwsl_notice("%s: %s: (%d lines) %d hits \n", __func__,
  162. (((char *)(fp + 1)) + fp->matches_length),
  163. fp->lines_in_file, fp->matches);
  164. if (fp->matches_length) {
  165. l = (uint32_t *)(fp + 1);
  166. n = 0;
  167. while ((int)n++ < fp->matches)
  168. lwsl_notice(" %d\n", *l++);
  169. }
  170. fp = fp->next;
  171. }
  172. lwsac_free(&params.results_head);
  173. optind++;
  174. }
  175. lws_fts_close(jtf);
  176. return 0;
  177. bail1:
  178. close(ft);
  179. bail:
  180. lwsl_user("FAILED\n");
  181. return 1;
  182. }