Merge branch '1904_spec_bump_epoch'
[midnight-commander.git] / edit / etags.c
blob4fb045a1282a2b982296ba257faae606be2aad24
1 /* editor C-code navigation via tags.
2 make TAGS file via command:
3 $ find . -type f -name "*.[ch]" | etags -l c --declarations -
5 or, if etags utility not installed:
6 $ find . -type f -name "*.[ch]" | ctags --c-kinds=+p --fields=+iaS --extra=+q -e -L-
8 Copyright (C) 2009 Free Software Foundation, Inc.
10 Authors:
11 Ilia Maslakov <il.smind@gmail.com>, 2009
12 Slava Zanko <slavazanko@gmail.com>, 2009
15 This file is part of the Midnight Commander.
17 The Midnight Commander is free software; you can redistribute it
18 and/or modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation; either version 2 of the
20 License, or (at your option) any later version.
22 The Midnight Commander is distributed in the hope that it will be
23 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
24 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
30 MA 02110-1301, USA.
33 #include <config.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <inttypes.h>
38 #include <string.h>
39 #include <ctype.h>
41 #include "../src/global.h"
42 #include "../src/util.h" /* canonicalize_pathname() */
43 #include "../edit/etags.h"
45 /*** file scope functions **********************************************/
47 static gboolean parse_define(char *buf, char **long_name, char **short_name, long *line)
49 enum {in_longname, in_shortname, in_shortname_first_char, in_line, finish} def_state = in_longname;
51 static char longdef[LONG_DEF_LEN];
52 static char shortdef[SHORT_DEF_LEN];
53 static char linedef[LINE_DEF_LEN];
54 int nlong = 0;
55 int nshort = 0;
56 int nline = 0;
57 char c = *buf;
59 while ( !(c =='\0' || c =='\n') ) {
60 switch ( def_state ) {
61 case in_longname:
62 if ( c == 0x01 ) {
63 def_state = in_line;
64 } else if ( c == 0x7F ) {
65 def_state = in_shortname;
66 } else {
67 if ( nlong < LONG_DEF_LEN - 1 ) {
68 longdef[nlong++] = c;
71 break;
72 case in_shortname_first_char:
73 if ( isdigit(c) ) {
74 nshort = 0;
75 buf--;
76 def_state = in_line;
77 } else if ( c == 0x01 ) {
78 def_state = in_line;
79 } else {
80 if ( nshort < SHORT_DEF_LEN - 1 ) {
81 shortdef[nshort++] = c;
82 def_state = in_shortname;
85 break;
86 case in_shortname:
87 if ( c == 0x01 ) {
88 def_state = in_line;
89 } else if ( c == '\n' ) {
90 def_state = finish;
91 } else {
92 if ( nshort < SHORT_DEF_LEN - 1 ) {
93 shortdef[nshort++] = c;
96 break;
97 case in_line:
98 if ( c == ',' || c == '\n') {
99 def_state = finish;
100 } else if ( isdigit(c) ) {
101 if ( nline < LINE_DEF_LEN - 1 ) {
102 linedef[nline++] = c;
105 break;
106 case finish:
107 longdef[nlong] = '\0';
108 shortdef[nshort] = '\0';
109 linedef[nline] = '\0';
110 *long_name = g_strdup (longdef);
111 *short_name = g_strdup (shortdef);
112 *line = atol (linedef);
113 return TRUE;
114 break;
116 buf++;
117 c = *buf;
119 *long_name = NULL;
120 *short_name = NULL;
121 *line = 0;
122 return FALSE;
125 /*** public functions **************************************************/
127 int etags_set_definition_hash(const char *tagfile, const char *start_path,
128 const char *match_func,
129 etags_hash_t *def_hash)
131 enum {start, in_filename, in_define} state = start;
133 FILE *f;
134 static char buf[BUF_LARGE];
136 char *longname = NULL;
137 char *shortname = NULL;
138 long line;
140 char *chekedstr = NULL;
142 int num = 0; /* returned value */
143 int pos;
144 char *filename = NULL;
146 if ( !match_func || !tagfile )
147 return 0;
149 /* open file with positions */
150 f = fopen (tagfile, "r");
151 if (f == NULL)
152 return 0;
154 while (fgets (buf, sizeof (buf), f)) {
156 switch ( state ) {
157 case start:
158 if ( buf[0] == 0x0C ) {
159 state = in_filename;
161 break;
162 case in_filename:
163 pos = strcspn(buf, ",");
164 g_free(filename);
165 filename = g_malloc (pos + 2);
166 g_strlcpy(filename, (char *)buf, pos + 1);
167 state = in_define;
168 break;
169 case in_define:
170 if ( buf[0] == 0x0C ) {
171 state = in_filename;
172 break;
174 /* check if the filename matches the define pos */
175 chekedstr = strstr (buf, match_func);
176 if ( chekedstr ) {
177 parse_define (chekedstr, &longname, &shortname, &line);
178 if ( num < MAX_DEFINITIONS - 1 ) {
179 def_hash[num].filename_len = strlen (filename);
180 def_hash[num].fullpath = g_build_filename ( start_path, filename, (char *) NULL);
182 canonicalize_pathname (def_hash[num].fullpath);
183 def_hash[num].filename = g_strdup (filename);
184 if ( shortname ) {
185 def_hash[num].short_define = g_strdup (shortname);
186 } else {
187 def_hash[num].short_define = g_strdup (longname);
189 def_hash[num].line = line;
190 g_free(shortname);
191 g_free(longname);
192 num++;
195 break;
199 g_free(filename);
200 fclose (f);
201 return num;