1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci#include "private-lib-misc-fts.h"
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#include <stdio.h>
29d4afb5ceSopenharmony_ci#include <string.h>
30d4afb5ceSopenharmony_ci#include <assert.h>
31d4afb5ceSopenharmony_ci#include <fcntl.h>
32d4afb5ceSopenharmony_ci#include <sys/types.h>
33d4afb5ceSopenharmony_ci#include <sys/stat.h>
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ci#define AC_COUNT_STASHED_CHILDREN 8
36d4afb5ceSopenharmony_ci
37d4afb5ceSopenharmony_cistruct ch {
38d4afb5ceSopenharmony_ci	jg2_file_offset ofs;
39d4afb5ceSopenharmony_ci	char name[64];
40d4afb5ceSopenharmony_ci	int inst;
41d4afb5ceSopenharmony_ci	int child_agg;
42d4afb5ceSopenharmony_ci	int name_length;
43d4afb5ceSopenharmony_ci	int effpos;
44d4afb5ceSopenharmony_ci	int descendents;
45d4afb5ceSopenharmony_ci};
46d4afb5ceSopenharmony_ci
47d4afb5ceSopenharmony_cistruct wac {
48d4afb5ceSopenharmony_ci	struct ch ch[AC_COUNT_STASHED_CHILDREN];
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_ci	jg2_file_offset self;
51d4afb5ceSopenharmony_ci	jg2_file_offset tifs;
52d4afb5ceSopenharmony_ci	int child_count;
53d4afb5ceSopenharmony_ci	int child;
54d4afb5ceSopenharmony_ci
55d4afb5ceSopenharmony_ci	int agg;
56d4afb5ceSopenharmony_ci	int desc;
57d4afb5ceSopenharmony_ci	char done_children;
58d4afb5ceSopenharmony_ci	char once;
59d4afb5ceSopenharmony_ci};
60d4afb5ceSopenharmony_ci
61d4afb5ceSopenharmony_cistruct linetable {
62d4afb5ceSopenharmony_ci	struct linetable *next;
63d4afb5ceSopenharmony_ci
64d4afb5ceSopenharmony_ci	int chunk_line_number_start;
65d4afb5ceSopenharmony_ci	int chunk_line_number_count;
66d4afb5ceSopenharmony_ci
67d4afb5ceSopenharmony_ci	off_t chunk_filepos_start;
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci	off_t vli_ofs_in_index;
70d4afb5ceSopenharmony_ci};
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_cistatic uint32_t
73d4afb5ceSopenharmony_cib32(unsigned char *b)
74d4afb5ceSopenharmony_ci{
75d4afb5ceSopenharmony_ci	return (uint32_t)((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
76d4afb5ceSopenharmony_ci}
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_cistatic uint16_t
79d4afb5ceSopenharmony_cib16(unsigned char *b)
80d4afb5ceSopenharmony_ci{
81d4afb5ceSopenharmony_ci	return (uint16_t)((b[0] << 8) | b[1]);
82d4afb5ceSopenharmony_ci}
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_cistatic int
85d4afb5ceSopenharmony_cilws_fts_filepath(struct lws_fts_file *jtf, int filepath_index, char *result,
86d4afb5ceSopenharmony_ci		 size_t len, uint32_t *ofs_linetable, uint32_t *lines)
87d4afb5ceSopenharmony_ci{
88d4afb5ceSopenharmony_ci	unsigned char buf[256 + 15];
89d4afb5ceSopenharmony_ci	uint32_t flen;
90d4afb5ceSopenharmony_ci	int ra, bp = 0;
91d4afb5ceSopenharmony_ci	size_t m;
92d4afb5ceSopenharmony_ci	off_t o;
93d4afb5ceSopenharmony_ci
94d4afb5ceSopenharmony_ci	if (filepath_index > jtf->filepaths)
95d4afb5ceSopenharmony_ci		return 1;
96d4afb5ceSopenharmony_ci
97d4afb5ceSopenharmony_ci	if (lseek(jtf->fd, (off_t)(jtf->filepath_table + (4 * (unsigned int)filepath_index)),
98d4afb5ceSopenharmony_ci			SEEK_SET) < 0) {
99d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to seek\n", __func__);
100d4afb5ceSopenharmony_ci
101d4afb5ceSopenharmony_ci		return 1;
102d4afb5ceSopenharmony_ci	}
103d4afb5ceSopenharmony_ci
104d4afb5ceSopenharmony_ci	ra = (int)read(jtf->fd, buf, 4);
105d4afb5ceSopenharmony_ci	if (ra < 0)
106d4afb5ceSopenharmony_ci		return 1;
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci	o = (off_t)b32(buf);
109d4afb5ceSopenharmony_ci	if (lseek(jtf->fd, o, SEEK_SET) < 0) {
110d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to seek\n", __func__);
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci		return 1;
113d4afb5ceSopenharmony_ci	}
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci	ra = (int)read(jtf->fd, buf, sizeof(buf));
116d4afb5ceSopenharmony_ci	if (ra < 0)
117d4afb5ceSopenharmony_ci		return 1;
118d4afb5ceSopenharmony_ci
119d4afb5ceSopenharmony_ci	if (ofs_linetable)
120d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], ofs_linetable);
121d4afb5ceSopenharmony_ci	else
122d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &flen);
123d4afb5ceSopenharmony_ci	if (lines)
124d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], lines);
125d4afb5ceSopenharmony_ci	else
126d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &flen);
127d4afb5ceSopenharmony_ci	bp += rq32(&buf[bp], &flen);
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci	m = flen;
130d4afb5ceSopenharmony_ci	if (len - 1 < m)
131d4afb5ceSopenharmony_ci		m = flen - 1;
132d4afb5ceSopenharmony_ci
133d4afb5ceSopenharmony_ci	strncpy(result, (char *)&buf[bp], m);
134d4afb5ceSopenharmony_ci	result[m] = '\0';
135d4afb5ceSopenharmony_ci	result[len - 1] = '\0';
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_ci	return 0;
138d4afb5ceSopenharmony_ci}
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci/*
141d4afb5ceSopenharmony_ci * returns -1 for fail or fd open on the trie file.
142d4afb5ceSopenharmony_ci *
143d4afb5ceSopenharmony_ci * *root is set to the position of the root trie entry.
144d4afb5ceSopenharmony_ci * *flen is set to the length of the whole file
145d4afb5ceSopenharmony_ci */
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ciint
148d4afb5ceSopenharmony_cilws_fts_adopt(struct lws_fts_file *jtf)
149d4afb5ceSopenharmony_ci{
150d4afb5ceSopenharmony_ci	unsigned char buf[256];
151d4afb5ceSopenharmony_ci	off_t ot;
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	if (read(jtf->fd, buf, TRIE_FILE_HDR_SIZE) != TRIE_FILE_HDR_SIZE) {
154d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to read file header\n", __func__);
155d4afb5ceSopenharmony_ci		goto bail;
156d4afb5ceSopenharmony_ci	}
157d4afb5ceSopenharmony_ci
158d4afb5ceSopenharmony_ci	if (buf[0] != 0xca || buf[1] != 0x7a ||
159d4afb5ceSopenharmony_ci	    buf[2] != 0x5f || buf[3] != 0x75) {
160d4afb5ceSopenharmony_ci		lwsl_err("%s: bad magic %02X %02X %02X %02X\n", __func__,
161d4afb5ceSopenharmony_ci			 buf[0], buf[1], buf[2], buf[3]);
162d4afb5ceSopenharmony_ci		goto bail;
163d4afb5ceSopenharmony_ci	}
164d4afb5ceSopenharmony_ci
165d4afb5ceSopenharmony_ci	jtf->root = b32(&buf[4]);
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci	ot = lseek(jtf->fd, 0, SEEK_END);
168d4afb5ceSopenharmony_ci	if (ot < 0) {
169d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to seek\n", __func__);
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci		goto bail;
172d4afb5ceSopenharmony_ci	}
173d4afb5ceSopenharmony_ci	jtf->flen = (jg2_file_offset)ot;
174d4afb5ceSopenharmony_ci
175d4afb5ceSopenharmony_ci	if (jtf->flen != b32(&buf[8])) {
176d4afb5ceSopenharmony_ci		lwsl_err("%s: file size doesn't match expected\n", __func__);
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci		goto bail;
179d4afb5ceSopenharmony_ci	}
180d4afb5ceSopenharmony_ci
181d4afb5ceSopenharmony_ci	jtf->filepath_table = b32(&buf[12]);
182d4afb5ceSopenharmony_ci	jtf->filepaths = (int)b32(&buf[16]);
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci	return jtf->fd;
185d4afb5ceSopenharmony_ci
186d4afb5ceSopenharmony_cibail:
187d4afb5ceSopenharmony_ci	return -1;
188d4afb5ceSopenharmony_ci}
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_cistruct lws_fts_file *
191d4afb5ceSopenharmony_cilws_fts_open(const char *filepath)
192d4afb5ceSopenharmony_ci{
193d4afb5ceSopenharmony_ci	struct lws_fts_file *jtf;
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci	jtf = lws_malloc(sizeof(*jtf), "fts open");
196d4afb5ceSopenharmony_ci	if (!jtf)
197d4afb5ceSopenharmony_ci		goto bail1;
198d4afb5ceSopenharmony_ci
199d4afb5ceSopenharmony_ci	jtf->fd = open(filepath, O_RDONLY);
200d4afb5ceSopenharmony_ci	if (jtf->fd < 0) {
201d4afb5ceSopenharmony_ci		lwsl_err("%s: unable to open %s\n", __func__, filepath);
202d4afb5ceSopenharmony_ci		goto bail2;
203d4afb5ceSopenharmony_ci	}
204d4afb5ceSopenharmony_ci
205d4afb5ceSopenharmony_ci	if (lws_fts_adopt(jtf) < 0)
206d4afb5ceSopenharmony_ci		goto bail3;
207d4afb5ceSopenharmony_ci
208d4afb5ceSopenharmony_ci	return jtf;
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_cibail3:
211d4afb5ceSopenharmony_ci	close(jtf->fd);
212d4afb5ceSopenharmony_cibail2:
213d4afb5ceSopenharmony_ci	lws_free(jtf);
214d4afb5ceSopenharmony_cibail1:
215d4afb5ceSopenharmony_ci	return NULL;
216d4afb5ceSopenharmony_ci}
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_civoid
219d4afb5ceSopenharmony_cilws_fts_close(struct lws_fts_file *jtf)
220d4afb5ceSopenharmony_ci{
221d4afb5ceSopenharmony_ci	close(jtf->fd);
222d4afb5ceSopenharmony_ci	lws_free(jtf);
223d4afb5ceSopenharmony_ci}
224d4afb5ceSopenharmony_ci
225d4afb5ceSopenharmony_ci#define grab(_pos, _size) { \
226d4afb5ceSopenharmony_ci		bp = 0; \
227d4afb5ceSopenharmony_ci		if (lseek(jtf->fd, (off_t)(_pos), SEEK_SET) < 0) { \
228d4afb5ceSopenharmony_ci			lwsl_err("%s: unable to seek\n", __func__); \
229d4afb5ceSopenharmony_ci\
230d4afb5ceSopenharmony_ci			goto bail; \
231d4afb5ceSopenharmony_ci		} \
232d4afb5ceSopenharmony_ci\
233d4afb5ceSopenharmony_ci		ra = (int)read(jtf->fd, buf, (size_t)(_size)); \
234d4afb5ceSopenharmony_ci		if (ra < 0) \
235d4afb5ceSopenharmony_ci			goto bail; \
236d4afb5ceSopenharmony_ci}
237d4afb5ceSopenharmony_ci
238d4afb5ceSopenharmony_cistatic struct linetable *
239d4afb5ceSopenharmony_cilws_fts_cache_chunktable(struct lws_fts_file *jtf, uint32_t ofs_linetable,
240d4afb5ceSopenharmony_ci			 struct lwsac **linetable_head)
241d4afb5ceSopenharmony_ci{
242d4afb5ceSopenharmony_ci	struct linetable *lt, *first = NULL, **prev = NULL;
243d4afb5ceSopenharmony_ci	unsigned char buf[8];
244d4afb5ceSopenharmony_ci	int line = 1, bp, ra;
245d4afb5ceSopenharmony_ci	off_t cfs = 0;
246d4afb5ceSopenharmony_ci
247d4afb5ceSopenharmony_ci	*linetable_head = NULL;
248d4afb5ceSopenharmony_ci
249d4afb5ceSopenharmony_ci	do {
250d4afb5ceSopenharmony_ci		grab(ofs_linetable, sizeof(buf));
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci		lt = lwsac_use(linetable_head, sizeof(*lt), 0);
253d4afb5ceSopenharmony_ci		if (!lt)
254d4afb5ceSopenharmony_ci			goto bail;
255d4afb5ceSopenharmony_ci		if (!first)
256d4afb5ceSopenharmony_ci			first = lt;
257d4afb5ceSopenharmony_ci
258d4afb5ceSopenharmony_ci		lt->next = NULL;
259d4afb5ceSopenharmony_ci		if (prev)
260d4afb5ceSopenharmony_ci			*prev = lt;
261d4afb5ceSopenharmony_ci		prev = &lt->next;
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci		lt->chunk_line_number_start = line;
264d4afb5ceSopenharmony_ci		lt->chunk_line_number_count = b16(&buf[bp + 2]);
265d4afb5ceSopenharmony_ci		lt->vli_ofs_in_index = (off_t)(ofs_linetable + 8);
266d4afb5ceSopenharmony_ci		lt->chunk_filepos_start = cfs;
267d4afb5ceSopenharmony_ci
268d4afb5ceSopenharmony_ci		line += lt->chunk_line_number_count;
269d4afb5ceSopenharmony_ci
270d4afb5ceSopenharmony_ci		cfs += (int32_t)b32(&buf[bp + 4]);
271d4afb5ceSopenharmony_ci		ofs_linetable += b16(&buf[bp]);
272d4afb5ceSopenharmony_ci
273d4afb5ceSopenharmony_ci	} while (b16(&buf[bp]));
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci	return first;
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_cibail:
278d4afb5ceSopenharmony_ci	lwsac_free(linetable_head);
279d4afb5ceSopenharmony_ci
280d4afb5ceSopenharmony_ci	return NULL;
281d4afb5ceSopenharmony_ci}
282d4afb5ceSopenharmony_ci
283d4afb5ceSopenharmony_cistatic int
284d4afb5ceSopenharmony_cilws_fts_getfileoffset(struct lws_fts_file *jtf, struct linetable *ltstart,
285d4afb5ceSopenharmony_ci		      int line, off_t *_ofs)
286d4afb5ceSopenharmony_ci{
287d4afb5ceSopenharmony_ci	struct linetable *lt = ltstart;
288d4afb5ceSopenharmony_ci	unsigned char buf[LWS_FTS_LINES_PER_CHUNK * 5];
289d4afb5ceSopenharmony_ci	uint32_t ll;
290d4afb5ceSopenharmony_ci	off_t ofs;
291d4afb5ceSopenharmony_ci	int bp, ra;
292d4afb5ceSopenharmony_ci
293d4afb5ceSopenharmony_ci	/* first figure out which chunk */
294d4afb5ceSopenharmony_ci
295d4afb5ceSopenharmony_ci	do {
296d4afb5ceSopenharmony_ci		if (line >= lt->chunk_line_number_start &&
297d4afb5ceSopenharmony_ci		    line < lt->chunk_line_number_start +
298d4afb5ceSopenharmony_ci		    	    lt->chunk_line_number_count)
299d4afb5ceSopenharmony_ci			break;
300d4afb5ceSopenharmony_ci
301d4afb5ceSopenharmony_ci		lt = lt->next;
302d4afb5ceSopenharmony_ci	} while (lt);
303d4afb5ceSopenharmony_ci
304d4afb5ceSopenharmony_ci	if (!lt)
305d4afb5ceSopenharmony_ci		goto bail;
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci	/* we know it's in this chunk */
308d4afb5ceSopenharmony_ci
309d4afb5ceSopenharmony_ci	ofs = lt->chunk_filepos_start;
310d4afb5ceSopenharmony_ci	line -= lt->chunk_line_number_start;
311d4afb5ceSopenharmony_ci
312d4afb5ceSopenharmony_ci	grab(lt->vli_ofs_in_index, sizeof(buf));
313d4afb5ceSopenharmony_ci
314d4afb5ceSopenharmony_ci	bp = 0;
315d4afb5ceSopenharmony_ci	while (line) {
316d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &ll);
317d4afb5ceSopenharmony_ci		ofs += (int32_t)ll;
318d4afb5ceSopenharmony_ci		line--;
319d4afb5ceSopenharmony_ci	}
320d4afb5ceSopenharmony_ci
321d4afb5ceSopenharmony_ci	/* we know the offset it is at in the original file */
322d4afb5ceSopenharmony_ci
323d4afb5ceSopenharmony_ci	*_ofs = ofs;
324d4afb5ceSopenharmony_ci
325d4afb5ceSopenharmony_ci	return 0;
326d4afb5ceSopenharmony_ci
327d4afb5ceSopenharmony_cibail:
328d4afb5ceSopenharmony_ci	lwsl_info("%s: bail %d\n", __func__, line);
329d4afb5ceSopenharmony_ci
330d4afb5ceSopenharmony_ci	return 1;
331d4afb5ceSopenharmony_ci}
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_cistatic int
334d4afb5ceSopenharmony_ciac_record(struct lws_fts_file *jtf, struct lwsac **results_head,
335d4afb5ceSopenharmony_ci	  const char *needle, int pos, struct wac *s, int sp,
336d4afb5ceSopenharmony_ci	  uint32_t instances, uint32_t agg_instances, uint32_t children,
337d4afb5ceSopenharmony_ci	  struct lws_fts_result_autocomplete ***ppac)
338d4afb5ceSopenharmony_ci{
339d4afb5ceSopenharmony_ci	struct lws_fts_result_autocomplete *ac;
340d4afb5ceSopenharmony_ci	int n, m;
341d4afb5ceSopenharmony_ci	char *p;
342d4afb5ceSopenharmony_ci
343d4afb5ceSopenharmony_ci	if (!instances && !agg_instances)
344d4afb5ceSopenharmony_ci		return 1;
345d4afb5ceSopenharmony_ci
346d4afb5ceSopenharmony_ci	m = pos;
347d4afb5ceSopenharmony_ci	for (n = 1; n <= sp; n++)
348d4afb5ceSopenharmony_ci		m += s[n].ch[s[n].child - 1].name_length;
349d4afb5ceSopenharmony_ci
350d4afb5ceSopenharmony_ci	ac = lwsac_use(results_head, sizeof(*ac) + (unsigned int)m + 1, 0);
351d4afb5ceSopenharmony_ci	if (!ac)
352d4afb5ceSopenharmony_ci		return -1;
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	p = (char *)(ac + 1);
355d4afb5ceSopenharmony_ci
356d4afb5ceSopenharmony_ci	**ppac = ac;
357d4afb5ceSopenharmony_ci	ac->next = NULL;
358d4afb5ceSopenharmony_ci	*ppac = &ac->next;
359d4afb5ceSopenharmony_ci	ac->instances = (int)instances;
360d4afb5ceSopenharmony_ci	ac->agg_instances = (int)agg_instances;
361d4afb5ceSopenharmony_ci	ac->ac_length = m;
362d4afb5ceSopenharmony_ci	ac->has_children = !!children;
363d4afb5ceSopenharmony_ci	ac->elided = 0;
364d4afb5ceSopenharmony_ci
365d4afb5ceSopenharmony_ci	memcpy(p, needle, (size_t)pos);
366d4afb5ceSopenharmony_ci	p += pos;
367d4afb5ceSopenharmony_ci
368d4afb5ceSopenharmony_ci	for (n = 1; n <= sp; n++) {
369d4afb5ceSopenharmony_ci		int w = s[n].child - 1;
370d4afb5ceSopenharmony_ci
371d4afb5ceSopenharmony_ci		memcpy(p, s[n].ch[w].name, (size_t)s[n].ch[w].name_length);
372d4afb5ceSopenharmony_ci		p += s[n].ch[w].name_length;
373d4afb5ceSopenharmony_ci	}
374d4afb5ceSopenharmony_ci	p = (char *)(ac + 1);
375d4afb5ceSopenharmony_ci	p[m] = '\0';
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci	/*
378d4afb5ceSopenharmony_ci	 * deduct this child's instance weight from his antecdents to track
379d4afb5ceSopenharmony_ci	 * relative path attractiveness dynamically, after we already used its
380d4afb5ceSopenharmony_ci	 * best results (children are sorted best-first)
381d4afb5ceSopenharmony_ci	 */
382d4afb5ceSopenharmony_ci	for (n = sp; n >= 0; n--) {
383d4afb5ceSopenharmony_ci		s[n].ch[s[n].child - 1].child_agg -= (int)instances;
384d4afb5ceSopenharmony_ci		s[n].agg -= (int)instances;
385d4afb5ceSopenharmony_ci	}
386d4afb5ceSopenharmony_ci
387d4afb5ceSopenharmony_ci	return 0;
388d4afb5ceSopenharmony_ci}
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_cistruct lws_fts_result *
391d4afb5ceSopenharmony_cilws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp)
392d4afb5ceSopenharmony_ci{
393d4afb5ceSopenharmony_ci	uint32_t children, instances, co, sl, agg, slt, chunk,
394d4afb5ceSopenharmony_ci		 fileofs_tif_start, desc, agg_instances;
395d4afb5ceSopenharmony_ci	int pos = 0, n, m, nl, bp, base = 0, ra, palm, budget, sp, ofd = -1;
396d4afb5ceSopenharmony_ci	unsigned long long tf = (unsigned long long)lws_now_usecs();
397d4afb5ceSopenharmony_ci	struct lws_fts_result_autocomplete **pac = NULL;
398d4afb5ceSopenharmony_ci	char stasis, nac = 0, credible, needle[32];
399d4afb5ceSopenharmony_ci	struct lws_fts_result_filepath *fp;
400d4afb5ceSopenharmony_ci	struct lws_fts_result *result;
401d4afb5ceSopenharmony_ci	unsigned char buf[4096];
402d4afb5ceSopenharmony_ci	off_t o, child_ofs;
403d4afb5ceSopenharmony_ci	struct wac s[128];
404d4afb5ceSopenharmony_ci
405d4afb5ceSopenharmony_ci	ftsp->results_head = NULL;
406d4afb5ceSopenharmony_ci
407d4afb5ceSopenharmony_ci	if (!ftsp->needle)
408d4afb5ceSopenharmony_ci		return NULL;
409d4afb5ceSopenharmony_ci
410d4afb5ceSopenharmony_ci	nl = (int)strlen(ftsp->needle);
411d4afb5ceSopenharmony_ci	if ((size_t)nl > sizeof(needle) - 2)
412d4afb5ceSopenharmony_ci		return NULL;
413d4afb5ceSopenharmony_ci
414d4afb5ceSopenharmony_ci	result = lwsac_use(&ftsp->results_head, sizeof(*result), 0);
415d4afb5ceSopenharmony_ci	if (!result)
416d4afb5ceSopenharmony_ci		return NULL;
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci	/* start with no results... */
419d4afb5ceSopenharmony_ci
420d4afb5ceSopenharmony_ci	result->autocomplete_head = NULL;
421d4afb5ceSopenharmony_ci	pac = &result->autocomplete_head;
422d4afb5ceSopenharmony_ci	result->filepath_head = NULL;
423d4afb5ceSopenharmony_ci	result->duration_ms = 0;
424d4afb5ceSopenharmony_ci	result->effective_flags = ftsp->flags;
425d4afb5ceSopenharmony_ci
426d4afb5ceSopenharmony_ci	palm = 0;
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci	for (n = 0; n < nl; n++)
429d4afb5ceSopenharmony_ci		needle[n] = (char)tolower(ftsp->needle[n]);
430d4afb5ceSopenharmony_ci	needle[nl] = '\0';
431d4afb5ceSopenharmony_ci
432d4afb5ceSopenharmony_ci	o = (off_t)jtf->root;
433d4afb5ceSopenharmony_ci	do {
434d4afb5ceSopenharmony_ci		bp = 0;
435d4afb5ceSopenharmony_ci		base = 0;
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci		grab(o, sizeof(buf));
438d4afb5ceSopenharmony_ci
439d4afb5ceSopenharmony_ci		child_ofs = o + bp;
440d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &fileofs_tif_start);
441d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &children);
442d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &instances);
443d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &agg_instances);
444d4afb5ceSopenharmony_ci		palm = pos;
445d4afb5ceSopenharmony_ci
446d4afb5ceSopenharmony_ci		/* the children follow here */
447d4afb5ceSopenharmony_ci
448d4afb5ceSopenharmony_ci		if (pos == nl) {
449d4afb5ceSopenharmony_ci
450d4afb5ceSopenharmony_ci			nac = 0;
451d4afb5ceSopenharmony_ci			if (!fileofs_tif_start)
452d4afb5ceSopenharmony_ci				/*
453d4afb5ceSopenharmony_ci				 * we matched, but there are no instances of
454d4afb5ceSopenharmony_ci				 * this, it's actually an intermediate
455d4afb5ceSopenharmony_ci				 */
456d4afb5ceSopenharmony_ci
457d4afb5ceSopenharmony_ci				goto autocomp;
458d4afb5ceSopenharmony_ci
459d4afb5ceSopenharmony_ci			/* we leave with bp positioned at the instance list */
460d4afb5ceSopenharmony_ci
461d4afb5ceSopenharmony_ci			o = (off_t)fileofs_tif_start;
462d4afb5ceSopenharmony_ci			grab(o, sizeof(buf));
463d4afb5ceSopenharmony_ci			break;
464d4afb5ceSopenharmony_ci		}
465d4afb5ceSopenharmony_ci
466d4afb5ceSopenharmony_ci		if (ra - bp < 1024) {
467d4afb5ceSopenharmony_ci
468d4afb5ceSopenharmony_ci			/*
469d4afb5ceSopenharmony_ci			 * We don't have enough.  So reload the buffer starting
470d4afb5ceSopenharmony_ci			 * at where we got to.
471d4afb5ceSopenharmony_ci			 */
472d4afb5ceSopenharmony_ci
473d4afb5ceSopenharmony_ci			base += bp;
474d4afb5ceSopenharmony_ci			grab(o + base, sizeof(buf));
475d4afb5ceSopenharmony_ci		}
476d4afb5ceSopenharmony_ci
477d4afb5ceSopenharmony_ci		/* gets set if any child COULD match needle if it went on */
478d4afb5ceSopenharmony_ci
479d4afb5ceSopenharmony_ci		credible = 0;
480d4afb5ceSopenharmony_ci		for (n = 0; (uint32_t)n < children; n++) {
481d4afb5ceSopenharmony_ci			uint32_t inst;
482d4afb5ceSopenharmony_ci
483d4afb5ceSopenharmony_ci			bp += rq32(&buf[bp], &co);
484d4afb5ceSopenharmony_ci			bp += rq32(&buf[bp], &inst);
485d4afb5ceSopenharmony_ci			bp += rq32(&buf[bp], &agg);
486d4afb5ceSopenharmony_ci			bp += rq32(&buf[bp], &desc);
487d4afb5ceSopenharmony_ci			bp += rq32(&buf[bp], &sl);
488d4afb5ceSopenharmony_ci
489d4afb5ceSopenharmony_ci			if (sl > (uint32_t)(nl - pos)) {
490d4afb5ceSopenharmony_ci
491d4afb5ceSopenharmony_ci				/*
492d4afb5ceSopenharmony_ci				 * it can't be a match because it's longer than
493d4afb5ceSopenharmony_ci				 * our needle string (but that leaves it as a
494d4afb5ceSopenharmony_ci				 * perfectly fine autocomplete candidate)
495d4afb5ceSopenharmony_ci				 */
496d4afb5ceSopenharmony_ci				size_t g = (size_t)(nl - pos);
497d4afb5ceSopenharmony_ci
498d4afb5ceSopenharmony_ci				/*
499d4afb5ceSopenharmony_ci				 * "credible" means at least one child matches
500d4afb5ceSopenharmony_ci				 * all the chars in needle up to as many as it
501d4afb5ceSopenharmony_ci				 * has.  If not "credible" this path cannot
502d4afb5ceSopenharmony_ci				 * match.
503d4afb5ceSopenharmony_ci				 */
504d4afb5ceSopenharmony_ci				if (!strncmp((char *)&buf[bp], &needle[pos], g))
505d4afb5ceSopenharmony_ci					credible = 1;
506d4afb5ceSopenharmony_ci				else
507d4afb5ceSopenharmony_ci					/*
508d4afb5ceSopenharmony_ci					 * deflate the parent agg using the
509d4afb5ceSopenharmony_ci					 * knowledge this child is not on the
510d4afb5ceSopenharmony_ci					 * path shown by the remainder of needle
511d4afb5ceSopenharmony_ci					 */
512d4afb5ceSopenharmony_ci					agg_instances -= agg;
513d4afb5ceSopenharmony_ci
514d4afb5ceSopenharmony_ci				nac = 0;
515d4afb5ceSopenharmony_ci				bp += (int)sl;
516d4afb5ceSopenharmony_ci				slt = 0;
517d4afb5ceSopenharmony_ci				pos = palm;
518d4afb5ceSopenharmony_ci				goto ensure;
519d4afb5ceSopenharmony_ci			}
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci			/* the comparison string potentially has huge length */
522d4afb5ceSopenharmony_ci
523d4afb5ceSopenharmony_ci			slt = sl;
524d4afb5ceSopenharmony_ci			while (slt) {
525d4afb5ceSopenharmony_ci
526d4afb5ceSopenharmony_ci				/*
527d4afb5ceSopenharmony_ci				 * the strategy is to compare whatever we have
528d4afb5ceSopenharmony_ci				 * lying around, then bring in more if it didn't
529d4afb5ceSopenharmony_ci				 * fail to match yet.  That way we don't bring
530d4afb5ceSopenharmony_ci				 * in anything we could already have known was
531d4afb5ceSopenharmony_ci				 * not needed due to a match fail.
532d4afb5ceSopenharmony_ci				 */
533d4afb5ceSopenharmony_ci
534d4afb5ceSopenharmony_ci				chunk = (uint32_t)(ra - bp);
535d4afb5ceSopenharmony_ci				if (chunk > slt)
536d4afb5ceSopenharmony_ci					chunk = slt;
537d4afb5ceSopenharmony_ci
538d4afb5ceSopenharmony_ci				if ((chunk == 1 && needle[pos] != buf[bp]) ||
539d4afb5ceSopenharmony_ci				    (chunk != 1 &&
540d4afb5ceSopenharmony_ci				     memcmp(&needle[pos], &buf[bp], chunk))) {
541d4afb5ceSopenharmony_ci
542d4afb5ceSopenharmony_ci					/*
543d4afb5ceSopenharmony_ci					 * it doesn't match... so nothing can
544d4afb5ceSopenharmony_ci					 * autocomplete this...
545d4afb5ceSopenharmony_ci					 */
546d4afb5ceSopenharmony_ci					bp += (int)slt;
547d4afb5ceSopenharmony_ci					slt = 0;
548d4afb5ceSopenharmony_ci					nac = 1;
549d4afb5ceSopenharmony_ci					goto ensure;
550d4afb5ceSopenharmony_ci				}
551d4afb5ceSopenharmony_ci
552d4afb5ceSopenharmony_ci				slt -= chunk;
553d4afb5ceSopenharmony_ci				pos += (int)chunk;
554d4afb5ceSopenharmony_ci				bp += (int)chunk;
555d4afb5ceSopenharmony_ci
556d4afb5ceSopenharmony_ci				/* so far, it matches */
557d4afb5ceSopenharmony_ci
558d4afb5ceSopenharmony_ci				if (!slt) {
559d4afb5ceSopenharmony_ci					/* we matched the whole thing */
560d4afb5ceSopenharmony_ci					o = (int32_t)co;
561d4afb5ceSopenharmony_ci					if (!co)
562d4afb5ceSopenharmony_ci						goto bail;
563d4afb5ceSopenharmony_ci					n = (int)children;
564d4afb5ceSopenharmony_ci					credible = 1;
565d4afb5ceSopenharmony_ci				}
566d4afb5ceSopenharmony_ci
567d4afb5ceSopenharmony_ciensure:
568d4afb5ceSopenharmony_ci				/*
569d4afb5ceSopenharmony_ci				 * do we have at least buf more to match, or the
570d4afb5ceSopenharmony_ci				 * remainder of the string, whichever is less?
571d4afb5ceSopenharmony_ci				 *
572d4afb5ceSopenharmony_ci				 * bp may exceed sizeof(buf) on no match path
573d4afb5ceSopenharmony_ci				 */
574d4afb5ceSopenharmony_ci				chunk = sizeof(buf);
575d4afb5ceSopenharmony_ci				if (slt < chunk)
576d4afb5ceSopenharmony_ci					chunk = slt;
577d4afb5ceSopenharmony_ci
578d4afb5ceSopenharmony_ci				if (ra - bp >= (int)chunk)
579d4afb5ceSopenharmony_ci					continue;
580d4afb5ceSopenharmony_ci
581d4afb5ceSopenharmony_ci				/*
582d4afb5ceSopenharmony_ci				 * We don't have enough.  So reload buf starting
583d4afb5ceSopenharmony_ci				 * at where we got to.
584d4afb5ceSopenharmony_ci				 */
585d4afb5ceSopenharmony_ci				base += bp;
586d4afb5ceSopenharmony_ci				grab(o + base, sizeof(buf));
587d4afb5ceSopenharmony_ci
588d4afb5ceSopenharmony_ci			} /* while we are still comparing */
589d4afb5ceSopenharmony_ci
590d4afb5ceSopenharmony_ci		} /* for each child */
591d4afb5ceSopenharmony_ci
592d4afb5ceSopenharmony_ci		if ((uint32_t)n == children) {
593d4afb5ceSopenharmony_ci			if (!credible)
594d4afb5ceSopenharmony_ci				goto bail;
595d4afb5ceSopenharmony_ci
596d4afb5ceSopenharmony_ci			nac = 0;
597d4afb5ceSopenharmony_ci			goto autocomp;
598d4afb5ceSopenharmony_ci		}
599d4afb5ceSopenharmony_ci	} while(1);
600d4afb5ceSopenharmony_ci
601d4afb5ceSopenharmony_ci	result->duration_ms = (int)(((uint64_t)lws_now_usecs() - tf) / 1000);
602d4afb5ceSopenharmony_ci
603d4afb5ceSopenharmony_ci	if (!instances && !children)
604d4afb5ceSopenharmony_ci		return result;
605d4afb5ceSopenharmony_ci
606d4afb5ceSopenharmony_ci	/* the match list may easily exceed one read buffer load ... */
607d4afb5ceSopenharmony_ci
608d4afb5ceSopenharmony_ci	o += bp;
609d4afb5ceSopenharmony_ci
610d4afb5ceSopenharmony_ci	/*
611d4afb5ceSopenharmony_ci	 * Only do the file match list if it was requested in the search flags
612d4afb5ceSopenharmony_ci	 */
613d4afb5ceSopenharmony_ci
614d4afb5ceSopenharmony_ci	if (!(ftsp->flags & LWSFTS_F_QUERY_FILES))
615d4afb5ceSopenharmony_ci		goto autocomp;
616d4afb5ceSopenharmony_ci
617d4afb5ceSopenharmony_ci	do {
618d4afb5ceSopenharmony_ci		uint32_t fi, tot, line, ro, ofs_linetable, lines, fplen,
619d4afb5ceSopenharmony_ci			*u, _o;
620d4afb5ceSopenharmony_ci		struct lwsac *lt_head = NULL;
621d4afb5ceSopenharmony_ci		struct linetable *ltst;
622d4afb5ceSopenharmony_ci		char path[256], *pp;
623d4afb5ceSopenharmony_ci		int footprint;
624d4afb5ceSopenharmony_ci		off_t fo;
625d4afb5ceSopenharmony_ci
626d4afb5ceSopenharmony_ci		ofd = -1;
627d4afb5ceSopenharmony_ci		grab(o, sizeof(buf));
628d4afb5ceSopenharmony_ci
629d4afb5ceSopenharmony_ci		ro = (uint32_t)o;
630d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &_o);
631d4afb5ceSopenharmony_ci		o = (off_t)_o;
632d4afb5ceSopenharmony_ci
633d4afb5ceSopenharmony_ci		assert(!o || o > TRIE_FILE_HDR_SIZE);
634d4afb5ceSopenharmony_ci
635d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &fi);
636d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &tot);
637d4afb5ceSopenharmony_ci
638d4afb5ceSopenharmony_ci		if (lws_fts_filepath(jtf, (int)fi, path, sizeof(path) - 1,
639d4afb5ceSopenharmony_ci				     &ofs_linetable, &lines)) {
640d4afb5ceSopenharmony_ci			lwsl_err("can't get filepath index %d\n", fi);
641d4afb5ceSopenharmony_ci			goto bail;
642d4afb5ceSopenharmony_ci		}
643d4afb5ceSopenharmony_ci
644d4afb5ceSopenharmony_ci		if (ftsp->only_filepath && strcmp(path, ftsp->only_filepath))
645d4afb5ceSopenharmony_ci			continue;
646d4afb5ceSopenharmony_ci
647d4afb5ceSopenharmony_ci		ltst = lws_fts_cache_chunktable(jtf, ofs_linetable, &lt_head);
648d4afb5ceSopenharmony_ci		if (!ltst)
649d4afb5ceSopenharmony_ci			goto bail;
650d4afb5ceSopenharmony_ci
651d4afb5ceSopenharmony_ci		if (ftsp->flags & LWSFTS_F_QUERY_QUOTE_LINE) {
652d4afb5ceSopenharmony_ci			ofd = open(path, O_RDONLY);
653d4afb5ceSopenharmony_ci			if (ofd < 0) {
654d4afb5ceSopenharmony_ci				lwsac_free(&lt_head);
655d4afb5ceSopenharmony_ci				goto bail;
656d4afb5ceSopenharmony_ci			}
657d4afb5ceSopenharmony_ci		}
658d4afb5ceSopenharmony_ci
659d4afb5ceSopenharmony_ci		fplen = (uint32_t)strlen(path);
660d4afb5ceSopenharmony_ci		footprint = (int)(sizeof(*fp) + fplen + 1);
661d4afb5ceSopenharmony_ci		if (ftsp->flags & LWSFTS_F_QUERY_FILE_LINES) {
662d4afb5ceSopenharmony_ci			/* line number and offset in file */
663d4afb5ceSopenharmony_ci			footprint += (int)(2 * sizeof(uint32_t) * tot);
664d4afb5ceSopenharmony_ci
665d4afb5ceSopenharmony_ci			if (ftsp->flags & LWSFTS_F_QUERY_QUOTE_LINE)
666d4afb5ceSopenharmony_ci				/* pointer to quote string */
667d4afb5ceSopenharmony_ci				footprint += (int)(sizeof(void *) * tot);
668d4afb5ceSopenharmony_ci		}
669d4afb5ceSopenharmony_ci
670d4afb5ceSopenharmony_ci		fp = lwsac_use(&ftsp->results_head, (unsigned int)footprint, 0);
671d4afb5ceSopenharmony_ci		if (!fp) {
672d4afb5ceSopenharmony_ci			lwsac_free(&lt_head);
673d4afb5ceSopenharmony_ci			goto bail;
674d4afb5ceSopenharmony_ci		}
675d4afb5ceSopenharmony_ci
676d4afb5ceSopenharmony_ci		fp->filepath_length = (int)fplen;
677d4afb5ceSopenharmony_ci		fp->lines_in_file = (int)lines;
678d4afb5ceSopenharmony_ci		fp->matches = (int)tot;
679d4afb5ceSopenharmony_ci		fp->matches_length = footprint - (int)sizeof(*fp) - (int)(fplen + 1);
680d4afb5ceSopenharmony_ci		fp->next = result->filepath_head;
681d4afb5ceSopenharmony_ci		result->filepath_head = fp;
682d4afb5ceSopenharmony_ci
683d4afb5ceSopenharmony_ci		/* line table first so it can be aligned */
684d4afb5ceSopenharmony_ci
685d4afb5ceSopenharmony_ci		u = (uint32_t*)(fp + 1);
686d4afb5ceSopenharmony_ci
687d4afb5ceSopenharmony_ci		if (ftsp->flags & LWSFTS_F_QUERY_FILE_LINES) {
688d4afb5ceSopenharmony_ci
689d4afb5ceSopenharmony_ci			/* for each line number */
690d4afb5ceSopenharmony_ci
691d4afb5ceSopenharmony_ci			for (n = 0; (uint32_t)n < tot; n++) {
692d4afb5ceSopenharmony_ci
693d4afb5ceSopenharmony_ci				unsigned char lbuf[256], *p;
694d4afb5ceSopenharmony_ci				char ebuf[384];
695d4afb5ceSopenharmony_ci				const char **v;
696d4afb5ceSopenharmony_ci				int m;
697d4afb5ceSopenharmony_ci
698d4afb5ceSopenharmony_ci				if ((ra - bp) < 8) {
699d4afb5ceSopenharmony_ci					base += bp;
700d4afb5ceSopenharmony_ci					grab((int32_t)ro + base, sizeof(buf));
701d4afb5ceSopenharmony_ci				}
702d4afb5ceSopenharmony_ci
703d4afb5ceSopenharmony_ci				bp += rq32(&buf[bp], &line);
704d4afb5ceSopenharmony_ci				*u++ = line;
705d4afb5ceSopenharmony_ci
706d4afb5ceSopenharmony_ci				if (lws_fts_getfileoffset(jtf, ltst, (int)line, &fo))
707d4afb5ceSopenharmony_ci					continue;
708d4afb5ceSopenharmony_ci
709d4afb5ceSopenharmony_ci				*u++ = (uint32_t)fo;
710d4afb5ceSopenharmony_ci
711d4afb5ceSopenharmony_ci				if (!(ftsp->flags & LWSFTS_F_QUERY_QUOTE_LINE))
712d4afb5ceSopenharmony_ci					continue;
713d4afb5ceSopenharmony_ci
714d4afb5ceSopenharmony_ci				if (lseek(ofd, fo, SEEK_SET) < 0)
715d4afb5ceSopenharmony_ci					continue;
716d4afb5ceSopenharmony_ci
717d4afb5ceSopenharmony_ci				m = (int)read(ofd, lbuf, sizeof(lbuf) - 1);
718d4afb5ceSopenharmony_ci				if (m < 0)
719d4afb5ceSopenharmony_ci					continue;
720d4afb5ceSopenharmony_ci				lbuf[sizeof(lbuf) - 1] = '\0';
721d4afb5ceSopenharmony_ci
722d4afb5ceSopenharmony_ci				p = (unsigned char *)strchr((char *)lbuf, '\n');
723d4afb5ceSopenharmony_ci				if (p)
724d4afb5ceSopenharmony_ci					m = lws_ptr_diff(p, lbuf);
725d4afb5ceSopenharmony_ci				lbuf[m] = '\0';
726d4afb5ceSopenharmony_ci				p = (unsigned char *)strchr((char *)lbuf, '\r');
727d4afb5ceSopenharmony_ci				if (p)
728d4afb5ceSopenharmony_ci					m = lws_ptr_diff(p, lbuf);
729d4afb5ceSopenharmony_ci				lbuf[m] = '\0';
730d4afb5ceSopenharmony_ci
731d4afb5ceSopenharmony_ci				lws_json_purify(ebuf, (const char *)lbuf,
732d4afb5ceSopenharmony_ci						sizeof(ebuf) - 1, NULL);
733d4afb5ceSopenharmony_ci				m = (int)strlen(ebuf);
734d4afb5ceSopenharmony_ci
735d4afb5ceSopenharmony_ci				p = lwsac_use(&ftsp->results_head, (unsigned int)m + 1, 0);
736d4afb5ceSopenharmony_ci				if (!p) {
737d4afb5ceSopenharmony_ci					lwsac_free(&lt_head);
738d4afb5ceSopenharmony_ci					goto bail;
739d4afb5ceSopenharmony_ci				}
740d4afb5ceSopenharmony_ci
741d4afb5ceSopenharmony_ci				memcpy(p, ebuf, (unsigned int)m);
742d4afb5ceSopenharmony_ci				p[m] = '\0';
743d4afb5ceSopenharmony_ci				v = (const char **)u;
744d4afb5ceSopenharmony_ci				*v = (const char *)p;
745d4afb5ceSopenharmony_ci				u += sizeof(const char *) / sizeof(uint32_t);
746d4afb5ceSopenharmony_ci			}
747d4afb5ceSopenharmony_ci		}
748d4afb5ceSopenharmony_ci
749d4afb5ceSopenharmony_ci		pp = ((char *)&fp[1]) + fp->matches_length;
750d4afb5ceSopenharmony_ci		memcpy(pp, path, fplen);
751d4afb5ceSopenharmony_ci		pp[fplen] = '\0';
752d4afb5ceSopenharmony_ci
753d4afb5ceSopenharmony_ci		if (ofd >= 0) {
754d4afb5ceSopenharmony_ci			close(ofd);
755d4afb5ceSopenharmony_ci			ofd = -1;
756d4afb5ceSopenharmony_ci		}
757d4afb5ceSopenharmony_ci
758d4afb5ceSopenharmony_ci		lwsac_free(&lt_head);
759d4afb5ceSopenharmony_ci
760d4afb5ceSopenharmony_ci		if (ftsp->only_filepath)
761d4afb5ceSopenharmony_ci			break;
762d4afb5ceSopenharmony_ci
763d4afb5ceSopenharmony_ci	} while (o);
764d4afb5ceSopenharmony_ci
765d4afb5ceSopenharmony_ci	/* sort the instance file list by results density */
766d4afb5ceSopenharmony_ci
767d4afb5ceSopenharmony_ci	do {
768d4afb5ceSopenharmony_ci		struct lws_fts_result_filepath **prf, *rf1, *rf2;
769d4afb5ceSopenharmony_ci
770d4afb5ceSopenharmony_ci		stasis = 1;
771d4afb5ceSopenharmony_ci
772d4afb5ceSopenharmony_ci		/* bubble sort keeps going until nothing changed */
773d4afb5ceSopenharmony_ci
774d4afb5ceSopenharmony_ci		prf = &result->filepath_head;
775d4afb5ceSopenharmony_ci		while (*prf) {
776d4afb5ceSopenharmony_ci
777d4afb5ceSopenharmony_ci			rf1 = *prf;
778d4afb5ceSopenharmony_ci			rf2 = rf1->next;
779d4afb5ceSopenharmony_ci
780d4afb5ceSopenharmony_ci			if (rf2 && rf1->lines_in_file && rf2->lines_in_file &&
781d4afb5ceSopenharmony_ci			    ((rf1->matches * 1000) / rf1->lines_in_file) <
782d4afb5ceSopenharmony_ci			    ((rf2->matches * 1000) / rf2->lines_in_file)) {
783d4afb5ceSopenharmony_ci				stasis = 0;
784d4afb5ceSopenharmony_ci
785d4afb5ceSopenharmony_ci				*prf = rf2;
786d4afb5ceSopenharmony_ci				rf1->next = rf2->next;
787d4afb5ceSopenharmony_ci				rf2->next = rf1;
788d4afb5ceSopenharmony_ci			}
789d4afb5ceSopenharmony_ci
790d4afb5ceSopenharmony_ci			prf = &(*prf)->next;
791d4afb5ceSopenharmony_ci		}
792d4afb5ceSopenharmony_ci
793d4afb5ceSopenharmony_ci	} while (!stasis);
794d4afb5ceSopenharmony_ci
795d4afb5ceSopenharmony_ciautocomp:
796d4afb5ceSopenharmony_ci
797d4afb5ceSopenharmony_ci	if (!(ftsp->flags & LWSFTS_F_QUERY_AUTOCOMPLETE) || nac)
798d4afb5ceSopenharmony_ci		return result;
799d4afb5ceSopenharmony_ci
800d4afb5ceSopenharmony_ci	/*
801d4afb5ceSopenharmony_ci	 * autocomplete (ie, the descendent paths that yield the most hits)
802d4afb5ceSopenharmony_ci	 *
803d4afb5ceSopenharmony_ci	 * We actually need to spider the earliest terminal descendents from
804d4afb5ceSopenharmony_ci	 * the child we definitely got past, and present the first n terminal
805d4afb5ceSopenharmony_ci	 * strings.  The descendents are already sorted in order of highest
806d4afb5ceSopenharmony_ci	 * aggregated hits in their descendents first, so simply collecting n
807d4afb5ceSopenharmony_ci	 * earliest leaf children is enough.
808d4afb5ceSopenharmony_ci	 *
809d4afb5ceSopenharmony_ci	 * The leaf children may be quite deep down in a stack however.  So we
810d4afb5ceSopenharmony_ci	 * have to go through all the walking motions collecting and retaining
811d4afb5ceSopenharmony_ci	 * child into for when we come back up the walk.
812d4afb5ceSopenharmony_ci	 *
813d4afb5ceSopenharmony_ci	 * We can completely ignore file instances for this, we just need the
814d4afb5ceSopenharmony_ci	 * earliest children.  And we can restrict how many children we stash
815d4afb5ceSopenharmony_ci	 * in each stack level to eg, 5.
816d4afb5ceSopenharmony_ci	 *
817d4afb5ceSopenharmony_ci	 * child_ofs comes in pointing at the start of the trie entry that is
818d4afb5ceSopenharmony_ci	 * to be the starting point for making suggestions.
819d4afb5ceSopenharmony_ci	 */
820d4afb5ceSopenharmony_ci
821d4afb5ceSopenharmony_ci	budget = ftsp->max_autocomplete;
822d4afb5ceSopenharmony_ci	base = 0;
823d4afb5ceSopenharmony_ci	bp = 0;
824d4afb5ceSopenharmony_ci	pac = &result->autocomplete_head;
825d4afb5ceSopenharmony_ci	sp = 0;
826d4afb5ceSopenharmony_ci	if (pos > (int)sizeof(s[sp].ch[0].name) - 1)
827d4afb5ceSopenharmony_ci		pos = (int)sizeof(s[sp].ch[0].name) - 1;
828d4afb5ceSopenharmony_ci
829d4afb5ceSopenharmony_ci	memset(&s[sp], 0, sizeof(s[sp]));
830d4afb5ceSopenharmony_ci
831d4afb5ceSopenharmony_ci	s[sp].child = 1;
832d4afb5ceSopenharmony_ci	s[sp].tifs = fileofs_tif_start;
833d4afb5ceSopenharmony_ci	s[sp].self = (jg2_file_offset)child_ofs;
834d4afb5ceSopenharmony_ci	s[sp].ch[0].effpos = pos;
835d4afb5ceSopenharmony_ci
836d4afb5ceSopenharmony_ci	if (pos == nl)
837d4afb5ceSopenharmony_ci		n = ac_record(jtf, &ftsp->results_head, needle, pos, s, 0,
838d4afb5ceSopenharmony_ci			      instances, agg_instances, children, &pac);
839d4afb5ceSopenharmony_ci
840d4afb5ceSopenharmony_ci	while (sp >= 0 && budget) {
841d4afb5ceSopenharmony_ci		int nobump = 0;
842d4afb5ceSopenharmony_ci		struct ch *tch = &s[sp].ch[s[sp].child - 1];
843d4afb5ceSopenharmony_ci
844d4afb5ceSopenharmony_ci		grab(child_ofs, sizeof(buf));
845d4afb5ceSopenharmony_ci
846d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &fileofs_tif_start);
847d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &children);
848d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &instances);
849d4afb5ceSopenharmony_ci		bp += rq32(&buf[bp], &agg_instances);
850d4afb5ceSopenharmony_ci
851d4afb5ceSopenharmony_ci		if (sp > 0 && s[sp - 1].done_children &&
852d4afb5ceSopenharmony_ci		    tch->effpos + tch->name_length >= nl &&
853d4afb5ceSopenharmony_ci		    tch->inst && fileofs_tif_start) {
854d4afb5ceSopenharmony_ci			n = ac_record(jtf, &ftsp->results_head, needle, pos, s,
855d4afb5ceSopenharmony_ci				      sp, (uint32_t)tch->inst, (uint32_t)tch->child_agg,
856d4afb5ceSopenharmony_ci				      (uint32_t)tch->descendents, &pac);
857d4afb5ceSopenharmony_ci			if (n < 0)
858d4afb5ceSopenharmony_ci				goto bail;
859d4afb5ceSopenharmony_ci			if (!n)
860d4afb5ceSopenharmony_ci				if (--budget == 0)
861d4afb5ceSopenharmony_ci					break;
862d4afb5ceSopenharmony_ci		}
863d4afb5ceSopenharmony_ci
864d4afb5ceSopenharmony_ci		if (!s[sp].done_children && children) {
865d4afb5ceSopenharmony_ci			s[sp].done_children = 1;
866d4afb5ceSopenharmony_ci			sp++;
867d4afb5ceSopenharmony_ci			memset(&s[sp], 0, sizeof(s[sp]));
868d4afb5ceSopenharmony_ci			s[sp].tifs = fileofs_tif_start;
869d4afb5ceSopenharmony_ci			s[sp].self = (jg2_file_offset)child_ofs;
870d4afb5ceSopenharmony_ci
871d4afb5ceSopenharmony_ci			for (n = 0; n < (int)children && s[sp].child_count <
872d4afb5ceSopenharmony_ci					    (int)LWS_ARRAY_SIZE(s[0].ch); n++) {
873d4afb5ceSopenharmony_ci				uint32_t slen, cho, agg, inst;
874d4afb5ceSopenharmony_ci				int i = s[sp].child_count;
875d4afb5ceSopenharmony_ci				struct ch *ch = &s[sp].ch[i];
876d4afb5ceSopenharmony_ci				size_t max;
877d4afb5ceSopenharmony_ci
878d4afb5ceSopenharmony_ci				bp += rq32(&buf[bp], &cho);
879d4afb5ceSopenharmony_ci				bp += rq32(&buf[bp], &inst);
880d4afb5ceSopenharmony_ci				bp += rq32(&buf[bp], &agg);
881d4afb5ceSopenharmony_ci				bp += rq32(&buf[bp], &desc);
882d4afb5ceSopenharmony_ci				bp += rq32(&buf[bp], &slen);
883d4afb5ceSopenharmony_ci
884d4afb5ceSopenharmony_ci				max = slen;
885d4afb5ceSopenharmony_ci				if (max > sizeof(ch->name) - 1)
886d4afb5ceSopenharmony_ci					max = sizeof(ch->name) - 1;
887d4afb5ceSopenharmony_ci
888d4afb5ceSopenharmony_ci				strncpy(ch->name, (char *)&buf[bp], max);
889d4afb5ceSopenharmony_ci				bp += (int)slen;
890d4afb5ceSopenharmony_ci
891d4afb5ceSopenharmony_ci				ch->name_length = (int)max;
892d4afb5ceSopenharmony_ci				ch->name[sizeof(ch->name) - 1] = '\0';
893d4afb5ceSopenharmony_ci				ch->inst = (int)inst;
894d4afb5ceSopenharmony_ci				ch->effpos =
895d4afb5ceSopenharmony_ci				       s[sp - 1].ch[s[sp - 1].child - 1].effpos;
896d4afb5ceSopenharmony_ci
897d4afb5ceSopenharmony_ci				ch->child_agg = (int)agg;
898d4afb5ceSopenharmony_ci				ch->descendents = (int)desc;
899d4afb5ceSopenharmony_ci
900d4afb5ceSopenharmony_ci				/*
901d4afb5ceSopenharmony_ci				 * if we have more needle chars than we matched
902d4afb5ceSopenharmony_ci				 * to get this far, we can only allow potential
903d4afb5ceSopenharmony_ci				 * matches that are consistent with the
904d4afb5ceSopenharmony_ci				 * additional unmatched character(s)...
905d4afb5ceSopenharmony_ci				 */
906d4afb5ceSopenharmony_ci
907d4afb5ceSopenharmony_ci				m = nl - ch->effpos;
908d4afb5ceSopenharmony_ci				if (m > ch->name_length)
909d4afb5ceSopenharmony_ci					m = ch->name_length;
910d4afb5ceSopenharmony_ci
911d4afb5ceSopenharmony_ci				if (m > 0 &&
912d4afb5ceSopenharmony_ci				    strncmp(&needle[ch->effpos], ch->name, (unsigned int)m))
913d4afb5ceSopenharmony_ci					continue;
914d4afb5ceSopenharmony_ci
915d4afb5ceSopenharmony_ci				ch->effpos += m;
916d4afb5ceSopenharmony_ci				s[sp].ch[s[sp].child_count++].ofs = cho;
917d4afb5ceSopenharmony_ci			}
918d4afb5ceSopenharmony_ci
919d4afb5ceSopenharmony_ci		}
920d4afb5ceSopenharmony_ci
921d4afb5ceSopenharmony_ci		while (sp >= 0 && s[sp].child >= s[sp].child_count) {
922d4afb5ceSopenharmony_ci			s[sp].done_children = 0;
923d4afb5ceSopenharmony_ci			sp--;
924d4afb5ceSopenharmony_ci		}
925d4afb5ceSopenharmony_ci
926d4afb5ceSopenharmony_ci		/*
927d4afb5ceSopenharmony_ci		 * Compare parent remaining agg vs parent's next siblings' still
928d4afb5ceSopenharmony_ci		 * intact original agg... if the next sibling has more, abandon
929d4afb5ceSopenharmony_ci		 * the parent path and go with the sibling... this keeps the
930d4afb5ceSopenharmony_ci		 * autocomplete results related to popularity.
931d4afb5ceSopenharmony_ci		 */
932d4afb5ceSopenharmony_ci
933d4afb5ceSopenharmony_ci		nobump = 0;
934d4afb5ceSopenharmony_ci		n = sp - 1;
935d4afb5ceSopenharmony_ci		while (n >= 0) {
936d4afb5ceSopenharmony_ci			struct lws_fts_result_autocomplete *ac =
937d4afb5ceSopenharmony_ci				(struct lws_fts_result_autocomplete *)pac;
938d4afb5ceSopenharmony_ci
939d4afb5ceSopenharmony_ci			if (s[n].child < s[n].child_count &&
940d4afb5ceSopenharmony_ci			    s[n].ch[s[n].child - 1].child_agg <
941d4afb5ceSopenharmony_ci			    	    s[n].ch[s[n].child].child_agg) {
942d4afb5ceSopenharmony_ci
943d4afb5ceSopenharmony_ci				if (pac)
944d4afb5ceSopenharmony_ci					/*
945d4afb5ceSopenharmony_ci					 * mark the autocomplete result that
946d4afb5ceSopenharmony_ci					 * there were more children down his
947d4afb5ceSopenharmony_ci					 * path that we skipped in these results
948d4afb5ceSopenharmony_ci					 */
949d4afb5ceSopenharmony_ci					ac->elided = 1;
950d4afb5ceSopenharmony_ci
951d4afb5ceSopenharmony_ci				for (m = n; m < sp + 1; m++)
952d4afb5ceSopenharmony_ci					s[m].done_children = 0;
953d4afb5ceSopenharmony_ci				sp = n;
954d4afb5ceSopenharmony_ci				child_ofs = (off_t)s[sp].ch[s[sp].child++].ofs;
955d4afb5ceSopenharmony_ci				nobump = 1;
956d4afb5ceSopenharmony_ci			}
957d4afb5ceSopenharmony_ci
958d4afb5ceSopenharmony_ci			n--;
959d4afb5ceSopenharmony_ci		}
960d4afb5ceSopenharmony_ci
961d4afb5ceSopenharmony_ci		if (nobump || sp < 0)
962d4afb5ceSopenharmony_ci			continue;
963d4afb5ceSopenharmony_ci
964d4afb5ceSopenharmony_ci		child_ofs = (off_t)s[sp].ch[s[sp].child++].ofs;
965d4afb5ceSopenharmony_ci	}
966d4afb5ceSopenharmony_ci
967d4afb5ceSopenharmony_ci	/* let's do a final sort into agg order */
968d4afb5ceSopenharmony_ci
969d4afb5ceSopenharmony_ci	do {
970d4afb5ceSopenharmony_ci		struct lws_fts_result_autocomplete *ac1, *ac2;
971d4afb5ceSopenharmony_ci
972d4afb5ceSopenharmony_ci		stasis = 1;
973d4afb5ceSopenharmony_ci
974d4afb5ceSopenharmony_ci		/* bubble sort keeps going until nothing changed */
975d4afb5ceSopenharmony_ci
976d4afb5ceSopenharmony_ci		pac = &result->autocomplete_head;
977d4afb5ceSopenharmony_ci		while (*pac) {
978d4afb5ceSopenharmony_ci
979d4afb5ceSopenharmony_ci			ac1 = *pac;
980d4afb5ceSopenharmony_ci			ac2 = ac1->next;
981d4afb5ceSopenharmony_ci
982d4afb5ceSopenharmony_ci			if (ac2 && ac1->instances < ac2->instances) {
983d4afb5ceSopenharmony_ci				stasis = 0;
984d4afb5ceSopenharmony_ci
985d4afb5ceSopenharmony_ci				*pac = ac2;
986d4afb5ceSopenharmony_ci				ac1->next = ac2->next;
987d4afb5ceSopenharmony_ci				ac2->next = ac1;
988d4afb5ceSopenharmony_ci			}
989d4afb5ceSopenharmony_ci
990d4afb5ceSopenharmony_ci			pac = &(*pac)->next;
991d4afb5ceSopenharmony_ci		}
992d4afb5ceSopenharmony_ci
993d4afb5ceSopenharmony_ci	} while (!stasis);
994d4afb5ceSopenharmony_ci
995d4afb5ceSopenharmony_ci	return result;
996d4afb5ceSopenharmony_ci
997d4afb5ceSopenharmony_cibail:
998d4afb5ceSopenharmony_ci	if (ofd >= 0)
999d4afb5ceSopenharmony_ci		close(ofd);
1000d4afb5ceSopenharmony_ci
1001d4afb5ceSopenharmony_ci	lwsl_info("%s: search ended up at bail\n", __func__);
1002d4afb5ceSopenharmony_ci
1003d4afb5ceSopenharmony_ci	return result;
1004d4afb5ceSopenharmony_ci}
1005