forked from bloovis/microemacs.mirror
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcscope.c
More file actions
285 lines (252 loc) · 6.75 KB
/
cscope.c
File metadata and controls
285 lines (252 loc) · 6.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*
Copyright (C) 2008 Mark Alexander
This file is part of MicroEMACS, a small text editor.
MicroEMACS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "def.h"
/* Uncomment this line to build test program. */
/* #define TEST 1 */
/*
* Local variables.
*/
static FILE *cscope_input;
static FILE *cscope_output;
/*
* Ignore the prompt characters from cscope.
*/
static void
ignore_prompt (void)
{
if (fgetc (cscope_input) != '>' || fgetc (cscope_input) != '>' ||
fgetc (cscope_input) != ' ')
{
#if TEST
printf ("bad prompt from cscope!\n");
#endif
}
}
/*
* Initiate a search to cscope, return the number of matches. The
* 'searchfield' parameter says which field of of the cscope entry screen
* on which to enter the string ('0' is "Find this C symbol", '6' is
* "Find this egrep pattern", etc.).
*/
static int
cscope_search (char search_field, const char *search_string)
{
int nlines, result;
char buf[64];
/* Ignore the ">> " prompt, which should be waiting for us already. */
ignore_prompt ();
/* Issue the command Nsearchstring, where N is the field number.
*/
fputc (search_field, cscope_output);
fputs (search_string, cscope_output);
fputc ('\n', cscope_output);
fflush (cscope_output);
#if TEST
printf ("sent command '0%s'\n", search_string);
#endif
/* Read the first line, which is of the format 'cscope: n lines',
and parse the 'n'. */
if (fgets (buf, sizeof (buf), cscope_input) == NULL)
return 0;
#if TEST
printf ("result of query: '%s'\n", buf);
#endif
result = sscanf (buf, "cscope: %d lines", &nlines);
return result == 1 ? nlines : 0;
}
/*
* Read the next match from the previously initiated search.
* Return the file to 'filename', the name of the function containing
* the string to 'where', and the line number to 'line_number'.
* FIXME: we should do length-checking on the buffers.
*/
static void
next_match (char *filename, char *where, int *line_number)
{
char buf[1024];
#if TEST
int ret;
#endif
if (fgets (buf, sizeof (buf), cscope_input) == NULL)
return;
#if TEST
printf ("read line: '%s'\n", buf);
ret =
#endif
sscanf (buf, "%s %s %d", filename, where, line_number);
#if TEST
printf ("sscanf returned %d\n", ret);
#endif
}
/*
* Open a two-way pipe to the cscope program.
*
* If noupdatecscope is TRUE, pass the -d option so that cscope will not
* try to update to update the cross reference. This is useful
* when using cscope databases generated by other programs, such
* as starscope (Ruby).
*/
static int
open_cscope (void)
{
const char *args[5];
args[0] = "cscope";
args[1] = "-l";
args[2] = "-k";
if (noupdatecscope)
{
args[3] = "-d";
args[4] = NULL;
}
else
args[3] = NULL;
return openpipe ("cscope", args, &cscope_input, &cscope_output);
}
/*
* Issue a cscope search in the specified entry field for the string,
* read back the resulting matches, and store them in the tags list.
*/
static int
prepcscope (char field, const char *string, int delete)
{
int n;
char filename[1024];
char where[1024];
int line;
tagfile * f;
int exact;
/* Open a pipe to cscope if not already done.
*/
if (cscope_input == NULL)
if (open_cscope () == FALSE)
{
eprintf ("Unable to open a pipe to cscope");
return FALSE;
}
/* If delete flag is TRUE, free up any existing tags from a previous search.
*/
if (delete)
freetags (FALSE, 1, KRANDOM);
/* Initiate a search to cscope, get back the number of matches.
*/
n = cscope_search (field, string);
/* Add each of the matches to the tag list.
*/
while (n-- > 0)
{
/* Get the result of the next match.
*/
next_match (filename, where, &line);
/* Create a file entry for this file if not already in the list.
*/
f = findtagfile (filename);
if (f == NULL)
{
eprintf ("Unable to create file structure");
return FALSE;
}
/* If the search string is the same as the name of the function where this
* reference was found, this must be the definition of the function,
* so put the tag at the head of the list instead of the end.
*/
exact = strcmp (where, string) == 0;
/* Add a tag entry to the list.
*/
if (addtagref (string, f, line, 0L, exact) == NULL)
{
eprintf ("Unable to create tag structure");
return FALSE;
}
}
return TRUE;
}
/*
* Prepare for scanning through the tags for the given C symbol.
* This function is a callback called by searchtag (in tags.c)
* just before it starts searching through the tag list.
*/
static int
prepref (const char *string)
{
return prepcscope ('1', string, TRUE) && prepcscope ('0', string, FALSE);
}
/*
* Search for a cscope reference. All of the work involved in searching
* the tag list is done in searchtag (tags.c), but the actual creation
* of the tag list is done in prepref above.
*/
int
findcscope (int f, int n, int k)
{
return searchtag (f, n, prepref, "ref");
}
/*
* Search for the next cscope reference.
*/
int
nextcscope (int f, int n, int k)
{
return searchtag (1, n, prepref, "ref");
}
/*
* Prepare for scanning through the egrep searches for the given string.
* This function is a callback called by searchtag (in tags.c)
* just before it starts searching through the tag list.
*/
static int
prepgrep (const char *string)
{
return prepcscope ('6', string, TRUE);
}
/*
* Search for an egrep reference. All of the work involved in searching
* the tag list is done in searchtag (tags.c), but the actual creation
* of the tag list is done in prepgrep above.
*/
int
findgrep (int f, int n, int k)
{
return searchtag (f, n, prepgrep, "grep");
}
/*
* test program
*/
#if TEST
int
main (int argc, char *argv[])
{
int i;
char filename[1024];
char where[1024];
int line;
if (open_cscope () == FALSE)
{
printf ("unable to open pipe to cscope\n");
return 1;
}
for (i = 1; i < argc; i++)
{
const char *search_string = argv[i];
int n = cscope_search (search_string);
printf ("%d matches for %s:\n", n, search_string);
while (n-- > 0)
{
next_match (filename, where, &line);
printf ("%s:%d in %s\n", filename, line, where);
}
}
return 0;
}
#endif