comparison src/tag.c @ 27986:c724906134a3 v8.2.4518

patch 8.2.4518: the binary tag search feature is always enabled Commit: https://github.com/vim/vim/commit/655b734ee858e90dd8d28549b7704a71b25d30e7 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Sun Mar 6 14:27:10 2022 +0000 patch 8.2.4518: the binary tag search feature is always enabled Problem: The binary tag search feature is always enabled. Solution: Remove the #ifdefs. Add a few more tests. (Yegappan Lakshmanan, closes #9893)
author Bram Moolenaar <Bram@vim.org>
date Sun, 06 Mar 2022 15:30:06 +0100
parents 495418c6cac8
children d59552ad3f36
comparison
equal deleted inserted replaced
27985:719dc5b9fc6e 27986:c724906134a3
1268 } 1268 }
1269 if (tagstackidx == tagstacklen) // idx at top of stack 1269 if (tagstackidx == tagstacklen) // idx at top of stack
1270 msg_puts("\n>"); 1270 msg_puts("\n>");
1271 } 1271 }
1272 1272
1273 #ifdef FEAT_TAG_BINS
1274 /* 1273 /*
1275 * Compare two strings, for length "len", ignoring case the ASCII way. 1274 * Compare two strings, for length "len", ignoring case the ASCII way.
1276 * return 0 for match, < 0 for smaller, > 0 for bigger 1275 * return 0 for match, < 0 for smaller, > 0 for bigger
1277 * Make sure case is folded to uppercase in comparison (like for 'sort -f') 1276 * Make sure case is folded to uppercase in comparison (like for 'sort -f')
1278 */ 1277 */
1292 ++s2; 1291 ++s2;
1293 --len; 1292 --len;
1294 } 1293 }
1295 return 0; // strings match 1294 return 0; // strings match
1296 } 1295 }
1297 #endif
1298 1296
1299 /* 1297 /*
1300 * Structure to hold info about the tag pattern being used. 1298 * Structure to hold info about the tag pattern being used.
1301 */ 1299 */
1302 typedef struct 1300 typedef struct
1590 int is_txt; // flag of file extension 1588 int is_txt; // flag of file extension
1591 #endif 1589 #endif
1592 int did_open; // did open a tag file 1590 int did_open; // did open a tag file
1593 int mincount; // MAXCOL: find all matches 1591 int mincount; // MAXCOL: find all matches
1594 // other: minimal number of matches 1592 // other: minimal number of matches
1595 #ifdef FEAT_TAG_BINS
1596 int linear; // do a linear search 1593 int linear; // do a linear search
1597 #endif
1598 char_u *lbuf; // line buffer 1594 char_u *lbuf; // line buffer
1599 int lbuf_size; // length of lbuf 1595 int lbuf_size; // length of lbuf
1600 #ifdef FEAT_EMACS_TAGS 1596 #ifdef FEAT_EMACS_TAGS
1601 char_u *ebuf; // additional buffer for etag fname 1597 char_u *ebuf; // additional buffer for etag fname
1602 #endif 1598 #endif
1958 if (STRNCMP(st->lbuf, "!_TAG_", 6) != 0) 1954 if (STRNCMP(st->lbuf, "!_TAG_", 6) != 0)
1959 // Non-header item before the header, e.g. "!" itself. 1955 // Non-header item before the header, e.g. "!" itself.
1960 return FALSE; 1956 return FALSE;
1961 1957
1962 // Read header line. 1958 // Read header line.
1963 #ifdef FEAT_TAG_BINS
1964 if (STRNCMP(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) 1959 if (STRNCMP(st->lbuf, "!_TAG_FILE_SORTED\t", 18) == 0)
1965 *sorted_file = st->lbuf[18]; 1960 *sorted_file = st->lbuf[18];
1966 #endif
1967 if (STRNCMP(st->lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) 1961 if (STRNCMP(st->lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0)
1968 { 1962 {
1969 // Prepare to convert every line from the specified 1963 // Prepare to convert every line from the specified
1970 // encoding to 'encoding'. 1964 // encoding to 'encoding'.
1971 for (p = st->lbuf + 20; *p > ' ' && *p < 127; ++p) 1965 for (p = st->lbuf + 20; *p > ' ' && *p < 127; ++p)
2262 int i; 2256 int i;
2263 #ifdef FEAT_MULTI_LANG 2257 #ifdef FEAT_MULTI_LANG
2264 int help_pri = 0; 2258 int help_pri = 0;
2265 char_u help_lang[3] = ""; // lang of current tags file 2259 char_u help_lang[3] = ""; // lang of current tags file
2266 #endif 2260 #endif
2267 #ifdef FEAT_TAG_BINS
2268 int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value 2261 int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value
2269 off_T filesize; 2262 off_T filesize;
2270 int tagcmp; 2263 int tagcmp;
2271 off_T offset; 2264 off_T offset;
2272 #endif
2273 enum 2265 enum
2274 { 2266 {
2275 TS_START, // at start of file 2267 TS_START, // at start of file
2276 TS_LINEAR // linear searching forward, till EOF 2268 TS_LINEAR, // linear searching forward, till EOF
2277 #ifdef FEAT_TAG_BINS 2269 TS_BINARY, // binary searching
2278 , TS_BINARY, // binary searching
2279 TS_SKIP_BACK, // skipping backwards 2270 TS_SKIP_BACK, // skipping backwards
2280 TS_STEP_FORWARD // stepping forwards 2271 TS_STEP_FORWARD // stepping forwards
2281 #endif
2282 } state; // Current search state 2272 } state; // Current search state
2283 #ifdef FEAT_TAG_BINS
2284 struct tag_search_info // Binary search file offsets 2273 struct tag_search_info // Binary search file offsets
2285 { 2274 {
2286 off_T low_offset; // offset for first char of first line that 2275 off_T low_offset; // offset for first char of first line that
2287 // could match 2276 // could match
2288 off_T high_offset; // offset of char after last line that could 2277 off_T high_offset; // offset of char after last line that could
2291 off_T curr_offset_used; // curr_offset used when skipping back 2280 off_T curr_offset_used; // curr_offset used when skipping back
2292 off_T match_offset; // Where the binary search found a tag 2281 off_T match_offset; // Where the binary search found a tag
2293 int low_char; // first char at low_offset 2282 int low_char; // first char at low_offset
2294 int high_char; // first char at high_offset 2283 int high_char; // first char at high_offset
2295 } search_info; 2284 } search_info;
2296 #endif
2297 2285
2298 int cmplen; 2286 int cmplen;
2299 int match; // matches 2287 int match; // matches
2300 int match_no_ic = 0;// matches with rm_ic == FALSE 2288 int match_no_ic = 0;// matches with rm_ic == FALSE
2301 int match_re; // match with regexp 2289 int match_re; // match with regexp
2303 2291
2304 int is_etag; // current file is emaces style 2292 int is_etag; // current file is emaces style
2305 2293
2306 hash_T hash = 0; 2294 hash_T hash = 0;
2307 2295
2308 #ifdef FEAT_TAG_BINS
2309 int sort_error = FALSE; // tags file not sorted 2296 int sort_error = FALSE; // tags file not sorted
2310 int sortic = FALSE; // tag file sorted in nocase 2297 int sortic = FALSE; // tag file sorted in nocase
2311 int noic = (flags & TAG_NOIC); 2298 int noic = (flags & TAG_NOIC);
2312 #endif
2313 int line_error = FALSE; // syntax error 2299 int line_error = FALSE; // syntax error
2314 int has_re = (flags & TAG_REGEXP); // regexp used 2300 int has_re = (flags & TAG_REGEXP); // regexp used
2315 #ifdef FEAT_CSCOPE 2301 #ifdef FEAT_CSCOPE
2316 int use_cscope = (flags & TAG_CSCOPE); 2302 int use_cscope = (flags & TAG_CSCOPE);
2317 #endif 2303 #endif
2318 vimconv_T vimconv; 2304 vimconv_T vimconv;
2319 2305
2320 vimconv.vc_type = CONV_NONE; 2306 vimconv.vc_type = CONV_NONE;
2321 2307
2322 #ifdef FEAT_TAG_BINS
2323 // This is only to avoid a compiler warning for using search_info 2308 // This is only to avoid a compiler warning for using search_info
2324 // uninitialised. 2309 // uninitialised.
2325 CLEAR_FIELD(search_info); 2310 CLEAR_FIELD(search_info);
2326 #endif
2327 2311
2328 // A file that doesn't exist is silently ignored. Only when not a 2312 // A file that doesn't exist is silently ignored. Only when not a
2329 // single file is found, an error message is given (further on). 2313 // single file is found, an error message is given (further on).
2330 #ifdef FEAT_CSCOPE 2314 #ifdef FEAT_CSCOPE
2331 if (use_cscope) 2315 if (use_cscope)
2357 is_etag = 0; // default is: not emacs style 2341 is_etag = 0; // default is: not emacs style
2358 2342
2359 // Read and parse the lines in the file one by one 2343 // Read and parse the lines in the file one by one
2360 for (;;) 2344 for (;;)
2361 { 2345 {
2362 #ifdef FEAT_TAG_BINS
2363 // check for CTRL-C typed, more often when jumping around 2346 // check for CTRL-C typed, more often when jumping around
2364 if (state == TS_BINARY || state == TS_SKIP_BACK) 2347 if (state == TS_BINARY || state == TS_SKIP_BACK)
2365 line_breakcheck(); 2348 line_breakcheck();
2366 else 2349 else
2367 #endif
2368 fast_breakcheck(); 2350 fast_breakcheck();
2369 if ((flags & TAG_INS_COMP)) // Double brackets for gcc 2351 if ((flags & TAG_INS_COMP)) // Double brackets for gcc
2370 ins_compl_check_keys(30, FALSE); 2352 ins_compl_check_keys(30, FALSE);
2371 if (got_int || ins_compl_interrupted()) 2353 if (got_int || ins_compl_interrupted())
2372 { 2354 {
2380 st->stop_searching = TRUE; 2362 st->stop_searching = TRUE;
2381 break; 2363 break;
2382 } 2364 }
2383 if (st->get_searchpat) 2365 if (st->get_searchpat)
2384 goto line_read_in; 2366 goto line_read_in;
2385 #ifdef FEAT_TAG_BINS
2386 // For binary search: compute the next offset to use. 2367 // For binary search: compute the next offset to use.
2387 if (state == TS_BINARY) 2368 if (state == TS_BINARY)
2388 { 2369 {
2389 offset = search_info.low_offset + ((search_info.high_offset 2370 offset = search_info.low_offset + ((search_info.high_offset
2390 - search_info.low_offset) / 2); 2371 - search_info.low_offset) / 2);
2447 2428
2448 /* 2429 /*
2449 * Not jumping around in the file: Read the next line. 2430 * Not jumping around in the file: Read the next line.
2450 */ 2431 */
2451 else 2432 else
2452 #endif
2453 { 2433 {
2454 // skip empty and blank lines 2434 // skip empty and blank lines
2455 do 2435 do
2456 { 2436 {
2457 #ifdef FEAT_CSCOPE 2437 #ifdef FEAT_CSCOPE
2458 if (use_cscope) 2438 if (use_cscope)
2459 eof = cs_fgets(st->lbuf, st->lbuf_size); 2439 eof = cs_fgets(st->lbuf, st->lbuf_size);
2460 else 2440 else
2461 #endif 2441 #endif
2462 { 2442 {
2463 #ifdef FEAT_TAG_BINS
2464 search_info.curr_offset = vim_ftell(fp); 2443 search_info.curr_offset = vim_ftell(fp);
2465 #endif
2466 eof = vim_fgets(st->lbuf, st->lbuf_size, fp); 2444 eof = vim_fgets(st->lbuf, st->lbuf_size, fp);
2467 } 2445 }
2468 } while (!eof && vim_isblankline(st->lbuf)); 2446 } while (!eof && vim_isblankline(st->lbuf));
2469 2447
2470 if (eof) 2448 if (eof)
2523 goto parse_line; 2501 goto parse_line;
2524 } 2502 }
2525 2503
2526 // Headers ends. 2504 // Headers ends.
2527 2505
2528 #ifdef FEAT_TAG_BINS
2529 /* 2506 /*
2530 * When there is no tag head, or ignoring case, need to do a 2507 * When there is no tag head, or ignoring case, need to do a
2531 * linear search. 2508 * linear search.
2532 * When no "!_TAG_" is found, default to binary search. If 2509 * When no "!_TAG_" is found, default to binary search. If
2533 * the tag file isn't sorted, the second loop will find it. 2510 * the tag file isn't sorted, the second loop will find it.
2559 // Binary search won't work for ignoring case, use linear 2536 // Binary search won't work for ignoring case, use linear
2560 // search. 2537 // search.
2561 st->linear = TRUE; 2538 st->linear = TRUE;
2562 state = TS_LINEAR; 2539 state = TS_LINEAR;
2563 } 2540 }
2564 #else 2541
2565 state = TS_LINEAR;
2566 #endif
2567
2568 #ifdef FEAT_TAG_BINS
2569 // When starting a binary search, get the size of the file and 2542 // When starting a binary search, get the size of the file and
2570 // compute the first offset. 2543 // compute the first offset.
2571 if (state == TS_BINARY) 2544 if (state == TS_BINARY)
2572 { 2545 {
2573 if (vim_fseek(fp, 0L, SEEK_END) != 0) 2546 if (vim_fseek(fp, 0L, SEEK_END) != 0)
2589 search_info.curr_offset = 0; 2562 search_info.curr_offset = 0;
2590 search_info.high_char = 0xff; 2563 search_info.high_char = 0xff;
2591 } 2564 }
2592 continue; 2565 continue;
2593 } 2566 }
2594 #endif
2595 } 2567 }
2596 2568
2597 parse_line: 2569 parse_line:
2598 // When the line is too long the NUL will not be in the 2570 // When the line is too long the NUL will not be in the
2599 // last-but-one byte (see vim_fgets()). 2571 // last-but-one byte (see vim_fgets()).
2613 if (fp != NULL) 2585 if (fp != NULL)
2614 fclose(fp); 2586 fclose(fp);
2615 return FAIL; 2587 return FAIL;
2616 } 2588 }
2617 2589
2618 #ifdef FEAT_TAG_BINS
2619 if (state == TS_STEP_FORWARD) 2590 if (state == TS_STEP_FORWARD)
2620 // Seek to the same position to read the same line again 2591 // Seek to the same position to read the same line again
2621 vim_fseek(fp, search_info.curr_offset, SEEK_SET); 2592 vim_fseek(fp, search_info.curr_offset, SEEK_SET);
2622 // this will try the same thing again, make sure the offset is 2593 // this will try the same thing again, make sure the offset is
2623 // different 2594 // different
2624 search_info.curr_offset = 0; 2595 search_info.curr_offset = 0;
2625 #endif
2626 continue; 2596 continue;
2627 } 2597 }
2628 2598
2629 /* 2599 /*
2630 * Figure out where the different strings are in this line. 2600 * Figure out where the different strings are in this line.
2657 if (has_re && st->orgpat.headlen < cmplen) 2627 if (has_re && st->orgpat.headlen < cmplen)
2658 cmplen = st->orgpat.headlen; 2628 cmplen = st->orgpat.headlen;
2659 else if (state == TS_LINEAR && st->orgpat.headlen != cmplen) 2629 else if (state == TS_LINEAR && st->orgpat.headlen != cmplen)
2660 continue; 2630 continue;
2661 2631
2662 #ifdef FEAT_TAG_BINS
2663 if (state == TS_BINARY) 2632 if (state == TS_BINARY)
2664 { 2633 {
2665 /* 2634 /*
2666 * Simplistic check for unsorted tags file. 2635 * Simplistic check for unsorted tags file.
2667 */ 2636 */
2748 else 2717 else
2749 continue; // before first match 2718 continue; // before first match
2750 } 2719 }
2751 } 2720 }
2752 else 2721 else
2753 #endif
2754 // skip this match if it can't match 2722 // skip this match if it can't match
2755 if (MB_STRNICMP(tagp.tagname, st->orgpat.head, cmplen) != 0) 2723 if (MB_STRNICMP(tagp.tagname, st->orgpat.head, cmplen) != 0)
2756 continue; 2724 continue;
2757 2725
2758 /* 2726 /*
2872 emacs_tags_incstack_free(); 2840 emacs_tags_incstack_free();
2873 #endif 2841 #endif
2874 if (vimconv.vc_type != CONV_NONE) 2842 if (vimconv.vc_type != CONV_NONE)
2875 convert_setup(&vimconv, NULL, NULL); 2843 convert_setup(&vimconv, NULL, NULL);
2876 2844
2877 #ifdef FEAT_TAG_BINS
2878 tag_file_sorted = NUL; 2845 tag_file_sorted = NUL;
2879 if (sort_error) 2846 if (sort_error)
2880 { 2847 {
2881 semsg(_(e_tags_file_not_sorted_str), st->tag_fname); 2848 semsg(_(e_tags_file_not_sorted_str), st->tag_fname);
2882 sort_error = FALSE; 2849 sort_error = FALSE;
2883 } 2850 }
2884 #endif
2885 2851
2886 /* 2852 /*
2887 * Stop searching if sufficient tags have been found. 2853 * Stop searching if sufficient tags have been found.
2888 */ 2854 */
2889 if (st->match_count >= st->mincount) 2855 if (st->match_count >= st->mincount)
2981 { 2947 {
2982 findtags_state_T st; 2948 findtags_state_T st;
2983 tagname_T tn; // info for get_tagfname() 2949 tagname_T tn; // info for get_tagfname()
2984 int first_file; // trying first tag file 2950 int first_file; // trying first tag file
2985 int retval = FAIL; // return value 2951 int retval = FAIL; // return value
2986 #ifdef FEAT_TAG_BINS
2987 int round; 2952 int round;
2988 #endif
2989 2953
2990 int save_emsg_off; 2954 int save_emsg_off;
2991 2955
2992 int help_save; 2956 int help_save;
2993 #ifdef FEAT_MULTI_LANG 2957 #ifdef FEAT_MULTI_LANG
2994 int i; 2958 int i;
2995 char_u *saved_pat = NULL; // copy of pat[] 2959 char_u *saved_pat = NULL; // copy of pat[]
2996 #endif 2960 #endif
2997 2961
2998 #ifdef FEAT_TAG_BINS
2999 int findall = (mincount == MAXCOL || mincount == TAG_MANY); 2962 int findall = (mincount == MAXCOL || mincount == TAG_MANY);
3000 // find all matching tags 2963 // find all matching tags
3001 #endif
3002 int has_re = (flags & TAG_REGEXP); // regexp used 2964 int has_re = (flags & TAG_REGEXP); // regexp used
3003 int noic = (flags & TAG_NOIC); 2965 int noic = (flags & TAG_NOIC);
3004 #ifdef FEAT_CSCOPE 2966 #ifdef FEAT_CSCOPE
3005 int use_cscope = (flags & TAG_CSCOPE); 2967 int use_cscope = (flags & TAG_CSCOPE);
3006 #endif 2968 #endif
3099 * string to look for, ignore case right away to avoid going though the 3061 * string to look for, ignore case right away to avoid going though the
3100 * tags files twice. 3062 * tags files twice.
3101 * When the tag file is case-fold sorted, it is either one or the other. 3063 * When the tag file is case-fold sorted, it is either one or the other.
3102 * Only ignore case when TAG_NOIC not used or 'ignorecase' set. 3064 * Only ignore case when TAG_NOIC not used or 'ignorecase' set.
3103 */ 3065 */
3104 #ifdef FEAT_TAG_BINS
3105 st.orgpat.regmatch.rm_ic = ((p_ic || !noic) 3066 st.orgpat.regmatch.rm_ic = ((p_ic || !noic)
3106 && (findall || st.orgpat.headlen == 0 || !p_tbs)); 3067 && (findall || st.orgpat.headlen == 0 || !p_tbs));
3107 for (round = 1; round <= 2; ++round) 3068 for (round = 1; round <= 2; ++round)
3108 { 3069 {
3109 st.linear = (st.orgpat.headlen == 0 || !p_tbs || round == 2); 3070 st.linear = (st.orgpat.headlen == 0 || !p_tbs || round == 2);
3110 #else
3111 st.orgpat.regmatch.rm_ic = (p_ic || !noic);
3112 #endif
3113 3071
3114 /* 3072 /*
3115 * Try tag file names from tags option one by one. 3073 * Try tag file names from tags option one by one.
3116 */ 3074 */
3117 for (first_file = TRUE; 3075 for (first_file = TRUE;
3137 #ifdef FEAT_CSCOPE 3095 #ifdef FEAT_CSCOPE
3138 if (!use_cscope) 3096 if (!use_cscope)
3139 #endif 3097 #endif
3140 tagname_free(&tn); 3098 tagname_free(&tn);
3141 3099
3142 #ifdef FEAT_TAG_BINS
3143 // stop searching when already did a linear search, or when TAG_NOIC 3100 // stop searching when already did a linear search, or when TAG_NOIC
3144 // used, and 'ignorecase' not set or already did case-ignore search 3101 // used, and 'ignorecase' not set or already did case-ignore search
3145 if (st.stop_searching || st.linear || (!p_ic && noic) || 3102 if (st.stop_searching || st.linear || (!p_ic && noic) ||
3146 st.orgpat.regmatch.rm_ic) 3103 st.orgpat.regmatch.rm_ic)
3147 break; 3104 break;
3151 # endif 3108 # endif
3152 3109
3153 // try another time while ignoring case 3110 // try another time while ignoring case
3154 st.orgpat.regmatch.rm_ic = TRUE; 3111 st.orgpat.regmatch.rm_ic = TRUE;
3155 } 3112 }
3156 #endif
3157 3113
3158 if (!st.stop_searching) 3114 if (!st.stop_searching)
3159 { 3115 {
3160 if (!st.did_open && verbose) // never opened any tags file 3116 if (!st.did_open && verbose) // never opened any tags file
3161 emsg(_(e_no_tags_file)); 3117 emsg(_(e_no_tags_file));