Mercurial > vim
comparison src/tag.c @ 28037:12a256140887 v8.2.4543
patch 8.2.4543: Coverity warning for refactored tag search code
Commit: https://github.com/vim/vim/commit/20fb28b1dcc092787e1a7b22dcfcfe1e46e29813
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Fri Mar 11 12:05:18 2022 +0000
patch 8.2.4543: Coverity warning for refactored tag search code
Problem: Coverity warning for refactored tag search code.
Solution: Avoid the warnings. Update comments. Add one more test case.
(Yegappan Lakshmanan, closes #9928)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 11 Mar 2022 13:15:04 +0100 |
parents | d59552ad3f36 |
children | 0362ab7c1a02 |
comparison
equal
deleted
inserted
replaced
28036:3167a59d5fc2 | 28037:12a256140887 |
---|---|
1661 // other: minimal number of matches | 1661 // other: minimal number of matches |
1662 int linear; // do a linear search | 1662 int linear; // do a linear search |
1663 char_u *lbuf; // line buffer | 1663 char_u *lbuf; // line buffer |
1664 int lbuf_size; // length of lbuf | 1664 int lbuf_size; // length of lbuf |
1665 #ifdef FEAT_EMACS_TAGS | 1665 #ifdef FEAT_EMACS_TAGS |
1666 int is_etag; // current file is emaces style | 1666 int is_etag; // current file is emacs style |
1667 char_u *ebuf; // additional buffer for etag fname | 1667 char_u *ebuf; // additional buffer for etag fname |
1668 #endif | 1668 #endif |
1669 int match_count; // number of matches found | 1669 int match_count; // number of matches found |
1670 garray_T ga_match[MT_COUNT]; // stores matches in sequence | 1670 garray_T ga_match[MT_COUNT]; // stores matches in sequence |
1671 hashtab_T ht_match[MT_COUNT]; // stores matches by key | 1671 hashtab_T ht_match[MT_COUNT]; // stores matches by key |
1672 int stop_searching; // stop when match found or error | 1672 int stop_searching; // stop when match found or error |
1673 } findtags_state_T; | 1673 } findtags_state_T; |
1674 | 1674 |
1675 /* | 1675 /* |
1676 * Initialize the state used by find_tags() | 1676 * Initialize the state used by find_tags(). |
1677 * Returns OK on success and FAIL on memory allocation failure. | |
1677 */ | 1678 */ |
1678 static int | 1679 static int |
1679 findtags_state_init( | 1680 findtags_state_init( |
1680 findtags_state_T *st, | 1681 findtags_state_T *st, |
1681 char_u *pat, | 1682 char_u *pat, |
1743 | 1744 |
1744 #ifdef FEAT_MULTI_LANG | 1745 #ifdef FEAT_MULTI_LANG |
1745 /* | 1746 /* |
1746 * Initialize the language and priority used for searching tags in a Vim help | 1747 * Initialize the language and priority used for searching tags in a Vim help |
1747 * file. | 1748 * file. |
1748 * Returns TRUE to process the help file and FALSE to skip the file. | 1749 * Returns TRUE to process the help file for tags and FALSE to skip the file. |
1749 */ | 1750 */ |
1750 static int | 1751 static int |
1751 findtags_in_help_init(findtags_state_T *st) | 1752 findtags_in_help_init(findtags_state_T *st) |
1752 { | 1753 { |
1753 int i; | 1754 int i; |
1760 { | 1761 { |
1761 // Prefer help tags according to 'helplang'. Put the two-letter | 1762 // Prefer help tags according to 'helplang'. Put the two-letter |
1762 // language name in help_lang[]. | 1763 // language name in help_lang[]. |
1763 i = (int)STRLEN(st->tag_fname); | 1764 i = (int)STRLEN(st->tag_fname); |
1764 if (i > 3 && st->tag_fname[i - 3] == '-') | 1765 if (i > 3 && st->tag_fname[i - 3] == '-') |
1765 STRCPY(st->help_lang, st->tag_fname + i - 2); | 1766 vim_strncpy(st->help_lang, st->tag_fname + i - 2, 2); |
1766 else | 1767 else |
1767 STRCPY(st->help_lang, "en"); | 1768 STRCPY(st->help_lang, "en"); |
1768 } | 1769 } |
1769 // When searching for a specific language skip tags files for other | 1770 // When searching for a specific language skip tags files for other |
1770 // languages. | 1771 // languages. |
1844 char_u *etag_fname; | 1845 char_u *etag_fname; |
1845 } incstack[INCSTACK_SIZE]; | 1846 } incstack[INCSTACK_SIZE]; |
1846 static int incstack_idx = 0; // index in incstack | 1847 static int incstack_idx = 0; // index in incstack |
1847 | 1848 |
1848 /* | 1849 /* |
1849 * Free the include tags file stack. | 1850 * Free the emacs include tags file stack. |
1850 */ | 1851 */ |
1851 static void | 1852 static void |
1852 emacs_tags_incstack_free(void) | 1853 emacs_tags_incstack_free(void) |
1853 { | 1854 { |
1854 while (incstack_idx) | 1855 while (incstack_idx) |
1861 } | 1862 } |
1862 | 1863 |
1863 /* | 1864 /* |
1864 * Emacs tags line with CTRL-L: New file name on next line. | 1865 * Emacs tags line with CTRL-L: New file name on next line. |
1865 * The file name is followed by a ','. Remember etag file name in ebuf. | 1866 * The file name is followed by a ','. Remember etag file name in ebuf. |
1866 * Returns a FILE pointer to the tags file. If another tags file is included, | 1867 * The FILE pointer to the tags file is stored in 'st->fp'. If another tags |
1867 * then returns a pointer to the new tags file. The old file pointer is saved | 1868 * file is included, then the FILE pointer to the new tags file is stored in |
1868 * in incstack. | 1869 * 'st->fp'. The old file pointer is saved in incstack. |
1869 */ | 1870 */ |
1870 static void | 1871 static void |
1871 emacs_tags_new_filename(findtags_state_T *st) | 1872 emacs_tags_new_filename(findtags_state_T *st) |
1872 { | 1873 { |
1873 char_u *p; | 1874 char_u *p; |
1916 // Can't open the included file, skip it and | 1917 // Can't open the included file, skip it and |
1917 // restore old value of "fp". | 1918 // restore old value of "fp". |
1918 st->fp = incstack[incstack_idx].fp; | 1919 st->fp = incstack[incstack_idx].fp; |
1919 vim_free(incstack[incstack_idx].etag_fname); | 1920 vim_free(incstack[incstack_idx].etag_fname); |
1920 } | 1921 } |
1921 | |
1922 return; | |
1923 } | 1922 } |
1924 | 1923 |
1925 /* | 1924 /* |
1926 * Reached the end of an emacs-style tags file. If this is an included tags | 1925 * Reached the end of an emacs-style tags file. If this is an included tags |
1927 * file, then pop it from the incstack and continue processing the parent tags | 1926 * file, then pop it from the incstack and continue processing the parent tags |
1928 * file. Otherwise, processed all the tags. | 1927 * file. Otherwise, processed all the tags. |
1929 * Returns TRUE if an included tags file is popped and processing should | 1928 * Returns TRUE if an included tags file is popped and processing should |
1930 * continue with the parent tags file. Otherwise returns FALSE. | 1929 * continue with the parent tags file. Returns FALSE to stop processing tags. |
1931 */ | 1930 */ |
1932 static int | 1931 static int |
1933 emacs_tags_file_eof(findtags_state_T *st) | 1932 emacs_tags_file_eof(findtags_state_T *st) |
1934 { | 1933 { |
1935 if (!incstack_idx) // reached end of file. stop processing. | 1934 if (!incstack_idx) // reached end of file. stop processing. |
1945 return TRUE; | 1944 return TRUE; |
1946 } | 1945 } |
1947 | 1946 |
1948 /* | 1947 /* |
1949 * Parse a line from an emacs-style tags file. | 1948 * Parse a line from an emacs-style tags file. |
1950 * Returns OK is the line is parsed successfully, otherwise FALSE. | 1949 * Returns OK if the line is parsed successfully, returns FAIL if the line is |
1950 * not terminated by a newline. | |
1951 */ | 1951 */ |
1952 static int | 1952 static int |
1953 emacs_tags_parse_line(char_u *lbuf, tagptrs_T *tagp) | 1953 emacs_tags_parse_line(char_u *lbuf, tagptrs_T *tagp) |
1954 { | 1954 { |
1955 char_u *p_7f; | 1955 char_u *p_7f; |
2165 int use_cscope = (st->flags & TAG_CSCOPE); | 2165 int use_cscope = (st->flags & TAG_CSCOPE); |
2166 #endif | 2166 #endif |
2167 int noic = (st->flags & TAG_NOIC); | 2167 int noic = (st->flags & TAG_NOIC); |
2168 off_T filesize; | 2168 off_T filesize; |
2169 | 2169 |
2170 // The header ends when the line sorts below "!_TAG_". When | 2170 // The header ends when the line sorts below "!_TAG_". When case is |
2171 // case is folded lower case letters sort before "_". | 2171 // folded lower case letters sort before "_". |
2172 if (STRNCMP(st->lbuf, "!_TAG_", 6) <= 0 | 2172 if (STRNCMP(st->lbuf, "!_TAG_", 6) <= 0 |
2173 || (st->lbuf[0] == '!' && ASCII_ISLOWER(st->lbuf[1]))) | 2173 || (st->lbuf[0] == '!' && ASCII_ISLOWER(st->lbuf[1]))) |
2174 return findtags_hdr_parse(st); | 2174 return findtags_hdr_parse(st); |
2175 | 2175 |
2176 // Headers ends. | 2176 // Headers ends. |
2239 } | 2239 } |
2240 | 2240 |
2241 /* | 2241 /* |
2242 * Parse a tag line read from a tags file. | 2242 * Parse a tag line read from a tags file. |
2243 * Returns OK if a tags line is successfully parsed. | 2243 * Returns OK if a tags line is successfully parsed. |
2244 * Returns FAIL if an error is encountered. | 2244 * Returns FAIL if a format error is encountered. |
2245 */ | 2245 */ |
2246 static int | 2246 static int |
2247 findtags_parse_line(findtags_state_T *st, tagptrs_T *tagpp) | 2247 findtags_parse_line(findtags_state_T *st, tagptrs_T *tagpp) |
2248 { | 2248 { |
2249 int status; | 2249 int status; |
2745 return OK; | 2745 return OK; |
2746 } | 2746 } |
2747 | 2747 |
2748 /* | 2748 /* |
2749 * Read and get all the tags from file st->tag_fname. | 2749 * Read and get all the tags from file st->tag_fname. |
2750 * Returns OK if all the tags are processed successfully and FAIL is a tag | 2750 * Sets 'st->stop_searching' to TRUE to stop searching for additional tags. |
2751 * format error is encountered. | 2751 */ |
2752 */ | 2752 static void |
2753 static int | |
2754 findtags_get_all_tags( | 2753 findtags_get_all_tags( |
2755 findtags_state_T *st, | 2754 findtags_state_T *st, |
2756 findtags_match_args_T *margs, | 2755 findtags_match_args_T *margs, |
2757 char_u *buf_ffname) | 2756 char_u *buf_ffname) |
2758 { | 2757 { |
2844 st->lbuf = alloc(st->lbuf_size); | 2843 st->lbuf = alloc(st->lbuf_size); |
2845 if (st->lbuf == NULL) | 2844 if (st->lbuf == NULL) |
2846 { | 2845 { |
2847 if (st->fp != NULL) | 2846 if (st->fp != NULL) |
2848 fclose(st->fp); | 2847 fclose(st->fp); |
2849 break; | 2848 st->fp = NULL; |
2849 st->stop_searching = TRUE; | |
2850 return; | |
2850 } | 2851 } |
2851 | 2852 |
2852 if (st->state == TS_STEP_FORWARD) | 2853 if (st->state == TS_STEP_FORWARD) |
2853 // Seek to the same position to read the same line again | 2854 // Seek to the same position to read the same line again |
2854 vim_fseek(st->fp, search_info.curr_offset, SEEK_SET); | 2855 vim_fseek(st->fp, search_info.curr_offset, SEEK_SET); |
2857 search_info.curr_offset = 0; | 2858 search_info.curr_offset = 0; |
2858 continue; | 2859 continue; |
2859 } | 2860 } |
2860 | 2861 |
2861 if (findtags_parse_line(st, &tagp) == FAIL) | 2862 if (findtags_parse_line(st, &tagp) == FAIL) |
2862 return FAIL; | 2863 { |
2864 semsg(_(e_format_error_in_tags_file_str), st->tag_fname); | |
2865 #ifdef FEAT_CSCOPE | |
2866 if (!use_cscope) | |
2867 #endif | |
2868 semsg(_("Before byte %ld"), (long)vim_ftell(st->fp)); | |
2869 st->stop_searching = TRUE; | |
2870 return; | |
2871 } | |
2863 | 2872 |
2864 retval = findtags_match_tag(st, &tagp, margs, &search_info); | 2873 retval = findtags_match_tag(st, &tagp, margs, &search_info); |
2865 if (retval == TAG_MATCH_NEXT) | 2874 if (retval == TAG_MATCH_NEXT) |
2866 continue; | 2875 continue; |
2867 if (retval == TAG_MATCH_STOP) | 2876 if (retval == TAG_MATCH_STOP) |
2873 if (findtags_add_match(st, &tagp, margs, buf_ffname, &hash) | 2882 if (findtags_add_match(st, &tagp, margs, buf_ffname, &hash) |
2874 == FAIL) | 2883 == FAIL) |
2875 break; | 2884 break; |
2876 } | 2885 } |
2877 } // forever | 2886 } // forever |
2878 | |
2879 return OK; | |
2880 } | 2887 } |
2881 | 2888 |
2882 /* | 2889 /* |
2883 * Search for tags matching 'st->orgpat.pat' in the 'st->tag_fname' tags file. | 2890 * Search for tags matching 'st->orgpat.pat' in the 'st->tag_fname' tags file. |
2884 * Information needed to search for the tags is in the 'st' state structure. | 2891 * Information needed to search for the tags is in the 'st' state structure. |
2885 * The matching tags are returned in 'st'. | 2892 * The matching tags are returned in 'st'. If an error is encountered, then |
2886 * Returns OK if successfully processed the file and FAIL on memory allocation | 2893 * 'st->stop_searching' is set to TRUE. |
2887 * failure. | 2894 */ |
2888 */ | 2895 static void |
2889 static int | |
2890 findtags_in_file(findtags_state_T *st, char_u *buf_ffname) | 2896 findtags_in_file(findtags_state_T *st, char_u *buf_ffname) |
2891 { | 2897 { |
2892 findtags_match_args_T margs; | 2898 findtags_match_args_T margs; |
2893 int line_error = FALSE; // syntax error | |
2894 #ifdef FEAT_CSCOPE | 2899 #ifdef FEAT_CSCOPE |
2895 int use_cscope = FALSE; | 2900 int use_cscope = FALSE; |
2896 #endif | 2901 #endif |
2897 | 2902 |
2898 st->vimconv.vc_type = CONV_NONE; | 2903 st->vimconv.vc_type = CONV_NONE; |
2911 { | 2916 { |
2912 #ifdef FEAT_MULTI_LANG | 2917 #ifdef FEAT_MULTI_LANG |
2913 if (curbuf->b_help) | 2918 if (curbuf->b_help) |
2914 { | 2919 { |
2915 if (!findtags_in_help_init(st)) | 2920 if (!findtags_in_help_init(st)) |
2916 return OK; | 2921 return; |
2917 } | 2922 } |
2918 #endif | 2923 #endif |
2919 | 2924 |
2920 st->fp = mch_fopen((char *)st->tag_fname, "r"); | 2925 st->fp = mch_fopen((char *)st->tag_fname, "r"); |
2921 if (st->fp == NULL) | 2926 if (st->fp == NULL) |
2922 return OK; | 2927 return; |
2923 | 2928 |
2924 if (p_verbose >= 5) | 2929 if (p_verbose >= 5) |
2925 { | 2930 { |
2926 verbose_enter(); | 2931 verbose_enter(); |
2927 smsg(_("Searching tags file %s"), st->tag_fname); | 2932 smsg(_("Searching tags file %s"), st->tag_fname); |
2934 #ifdef FEAT_EMACS_TAGS | 2939 #ifdef FEAT_EMACS_TAGS |
2935 st->is_etag = FALSE; // default is: not emacs style | 2940 st->is_etag = FALSE; // default is: not emacs style |
2936 #endif | 2941 #endif |
2937 | 2942 |
2938 // Read and parse the lines in the file one by one | 2943 // Read and parse the lines in the file one by one |
2939 if (findtags_get_all_tags(st, &margs, buf_ffname) == FAIL) | 2944 findtags_get_all_tags(st, &margs, buf_ffname); |
2940 line_error = TRUE; | |
2941 | |
2942 if (line_error) | |
2943 { | |
2944 semsg(_(e_format_error_in_tags_file_str), st->tag_fname); | |
2945 #ifdef FEAT_CSCOPE | |
2946 if (!use_cscope) | |
2947 #endif | |
2948 semsg(_("Before byte %ld"), (long)vim_ftell(st->fp)); | |
2949 st->stop_searching = TRUE; | |
2950 line_error = FALSE; | |
2951 } | |
2952 | 2945 |
2953 if (st->fp != NULL) | 2946 if (st->fp != NULL) |
2954 fclose(st->fp); | 2947 fclose(st->fp); |
2948 st->fp = NULL; | |
2955 #ifdef FEAT_EMACS_TAGS | 2949 #ifdef FEAT_EMACS_TAGS |
2956 emacs_tags_incstack_free(); | 2950 emacs_tags_incstack_free(); |
2957 #endif | 2951 #endif |
2958 if (st->vimconv.vc_type != CONV_NONE) | 2952 if (st->vimconv.vc_type != CONV_NONE) |
2959 convert_setup(&st->vimconv, NULL, NULL); | 2953 convert_setup(&st->vimconv, NULL, NULL); |
2962 semsg(_(e_tags_file_not_sorted_str), st->tag_fname); | 2956 semsg(_(e_tags_file_not_sorted_str), st->tag_fname); |
2963 | 2957 |
2964 // Stop searching if sufficient tags have been found. | 2958 // Stop searching if sufficient tags have been found. |
2965 if (st->match_count >= st->mincount) | 2959 if (st->match_count >= st->mincount) |
2966 st->stop_searching = TRUE; | 2960 st->stop_searching = TRUE; |
2967 | |
2968 return OK; | |
2969 } | 2961 } |
2970 | 2962 |
2971 /* | 2963 /* |
2972 * Copy the tags found by find_tags() to 'matchesp'. | 2964 * Copy the tags found by find_tags() to 'matchesp'. |
2973 * Returns the number of matches copied. | 2965 * Returns the number of matches copied. |
3186 use_cscope || | 3178 use_cscope || |
3187 #endif | 3179 #endif |
3188 get_tagfname(&tn, first_file, st.tag_fname) == OK; | 3180 get_tagfname(&tn, first_file, st.tag_fname) == OK; |
3189 first_file = FALSE) | 3181 first_file = FALSE) |
3190 { | 3182 { |
3191 if (findtags_in_file(&st, buf_ffname) == FAIL) | 3183 findtags_in_file(&st, buf_ffname); |
3192 goto findtag_end; | |
3193 if (st.stop_searching | 3184 if (st.stop_searching |
3194 #ifdef FEAT_CSCOPE | 3185 #ifdef FEAT_CSCOPE |
3195 || use_cscope | 3186 || use_cscope |
3196 #endif | 3187 #endif |
3197 ) | 3188 ) |