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 = <->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, <_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(<_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(<_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(<_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(<_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