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