lib/widget/input_complete.c: minor refactoring and optimization.
[midnight-commander.git] / src / editor / etags.c
blobf447fbf611e7698bfced1df8c24019e99429e3c5
1 /*
2 Editor C-code navigation via tags.
3 make TAGS file via command:
4 $ find . -type f -name "*.[ch]" | etags -l c --declarations -
6 or, if etags utility not installed:
7 $ find . -type f -name "*.[ch]" | ctags --c-kinds=+p --fields=+iaS --extra=+q -e -L-
9 Copyright (C) 2009, 2011
10 The Free Software Foundation, Inc.
12 Written by:
13 Ilia Maslakov <il.smind@gmail.com>, 2009
14 Slava Zanko <slavazanko@gmail.com>, 2009
16 This file is part of the Midnight Commander.
18 The Midnight Commander is free software: you can redistribute it
19 and/or modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation, either version 3 of the License,
21 or (at your option) any later version.
23 The Midnight Commander is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 #include <config.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <inttypes.h>
37 #include <string.h>
38 #include <ctype.h>
40 #include "lib/global.h"
41 #include "lib/util.h" /* canonicalize_pathname() */
43 #include "etags.h"
45 /*** global variables ****************************************************************************/
47 /*** file scope macro definitions ****************************************************************/
49 /*** file scope type declarations ****************************************************************/
51 /*** file scope variables ************************************************************************/
53 /*** file scope functions ************************************************************************/
54 /* --------------------------------------------------------------------------------------------- */
56 static gboolean
57 parse_define (char *buf, char **long_name, char **short_name, long *line)
59 /* *INDENT-OFF* */
60 enum
62 in_longname,
63 in_shortname,
64 in_shortname_first_char,
65 in_line, finish
66 } def_state = in_longname;
67 /* *INDENT-ON* */
69 static char longdef[LONG_DEF_LEN];
70 static char shortdef[SHORT_DEF_LEN];
71 static char linedef[LINE_DEF_LEN];
72 int nlong = 0;
73 int nshort = 0;
74 int nline = 0;
75 char c = *buf;
77 while (!(c == '\0' || c == '\n'))
79 switch (def_state)
81 case in_longname:
82 if (c == 0x01)
84 def_state = in_line;
86 else if (c == 0x7F)
88 def_state = in_shortname;
90 else
92 if (nlong < LONG_DEF_LEN - 1)
94 longdef[nlong++] = c;
97 break;
98 case in_shortname_first_char:
99 if (isdigit (c))
101 nshort = 0;
102 buf--;
103 def_state = in_line;
105 else if (c == 0x01)
107 def_state = in_line;
109 else
111 if (nshort < SHORT_DEF_LEN - 1)
113 shortdef[nshort++] = c;
114 def_state = in_shortname;
117 break;
118 case in_shortname:
119 if (c == 0x01)
121 def_state = in_line;
123 else if (c == '\n')
125 def_state = finish;
127 else
129 if (nshort < SHORT_DEF_LEN - 1)
131 shortdef[nshort++] = c;
134 break;
135 case in_line:
136 if (c == ',' || c == '\n')
138 def_state = finish;
140 else if (isdigit (c))
142 if (nline < LINE_DEF_LEN - 1)
144 linedef[nline++] = c;
147 break;
148 case finish:
149 longdef[nlong] = '\0';
150 shortdef[nshort] = '\0';
151 linedef[nline] = '\0';
152 *long_name = longdef;
153 *short_name = shortdef;
154 *line = atol (linedef);
155 return TRUE;
157 buf++;
158 c = *buf;
160 *long_name = NULL;
161 *short_name = NULL;
162 *line = 0;
163 return FALSE;
166 /* --------------------------------------------------------------------------------------------- */
167 /*** public functions ****************************************************************************/
168 /* --------------------------------------------------------------------------------------------- */
171 etags_set_definition_hash (const char *tagfile, const char *start_path,
172 const char *match_func, etags_hash_t * def_hash)
174 /* *INDENT-OFF* */
175 enum
177 start,
178 in_filename,
179 in_define
180 } state = start;
181 /* *INDENT-ON* */
183 FILE *f;
184 static char buf[BUF_LARGE];
186 char *chekedstr = NULL;
188 int num = 0; /* returned value */
189 int pos;
190 char *filename = NULL;
192 if (!match_func || !tagfile)
193 return 0;
195 /* open file with positions */
196 f = fopen (tagfile, "r");
197 if (f == NULL)
198 return 0;
200 while (fgets (buf, sizeof (buf), f))
202 switch (state)
204 case start:
205 if (buf[0] == 0x0C)
207 state = in_filename;
209 break;
210 case in_filename:
211 pos = strcspn (buf, ",");
212 g_free (filename);
213 filename = g_malloc (pos + 2);
214 g_strlcpy (filename, (char *) buf, pos + 1);
215 state = in_define;
216 break;
217 case in_define:
218 if (buf[0] == 0x0C)
220 state = in_filename;
221 break;
223 /* check if the filename matches the define pos */
224 chekedstr = strstr (buf, match_func);
225 if (chekedstr)
227 char *longname = NULL;
228 char *shortname = NULL;
229 long line = 0;
231 parse_define (chekedstr, &longname, &shortname, &line);
232 if (num < MAX_DEFINITIONS - 1)
234 def_hash[num].filename_len = strlen (filename);
235 def_hash[num].fullpath =
236 mc_build_filename (start_path, filename, (char *) NULL);
238 canonicalize_pathname (def_hash[num].fullpath);
239 def_hash[num].filename = g_strdup (filename);
240 if (shortname)
242 def_hash[num].short_define = g_strdup (shortname);
244 else
246 def_hash[num].short_define = g_strdup (longname);
248 def_hash[num].line = line;
249 num++;
252 break;
256 g_free (filename);
257 fclose (f);
258 return num;
261 /* --------------------------------------------------------------------------------------------- */