ctags.rb 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -0
- data/Rakefile +23 -0
- data/ctags.rb.gemspec +23 -0
- data/ext/.gitignore +3 -0
- data/ext/extconf.rb +15 -0
- data/ext/vendor/exuberant-ctags/.gitignore +6 -0
- data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
- data/ext/vendor/exuberant-ctags/COPYING +340 -0
- data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
- data/ext/vendor/exuberant-ctags/FAQ +371 -0
- data/ext/vendor/exuberant-ctags/INSTALL +215 -0
- data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
- data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
- data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
- data/ext/vendor/exuberant-ctags/NEWS +871 -0
- data/ext/vendor/exuberant-ctags/README +73 -0
- data/ext/vendor/exuberant-ctags/ant.c +42 -0
- data/ext/vendor/exuberant-ctags/argproc.c +505 -0
- data/ext/vendor/exuberant-ctags/args.c +274 -0
- data/ext/vendor/exuberant-ctags/args.h +63 -0
- data/ext/vendor/exuberant-ctags/asm.c +387 -0
- data/ext/vendor/exuberant-ctags/asp.c +328 -0
- data/ext/vendor/exuberant-ctags/awk.c +81 -0
- data/ext/vendor/exuberant-ctags/basic.c +203 -0
- data/ext/vendor/exuberant-ctags/beta.c +321 -0
- data/ext/vendor/exuberant-ctags/c.c +2932 -0
- data/ext/vendor/exuberant-ctags/cobol.c +50 -0
- data/ext/vendor/exuberant-ctags/config.h.in +277 -0
- data/ext/vendor/exuberant-ctags/configure +7704 -0
- data/ext/vendor/exuberant-ctags/configure.ac +532 -0
- data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
- data/ext/vendor/exuberant-ctags/ctags.h +28 -0
- data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
- data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
- data/ext/vendor/exuberant-ctags/debug.c +113 -0
- data/ext/vendor/exuberant-ctags/debug.h +70 -0
- data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
- data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
- data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
- data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
- data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
- data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
- data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
- data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
- data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
- data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
- data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
- data/ext/vendor/exuberant-ctags/entry.c +847 -0
- data/ext/vendor/exuberant-ctags/entry.h +103 -0
- data/ext/vendor/exuberant-ctags/erlang.c +189 -0
- data/ext/vendor/exuberant-ctags/flex.c +2243 -0
- data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
- data/ext/vendor/exuberant-ctags/general.h +127 -0
- data/ext/vendor/exuberant-ctags/get.c +669 -0
- data/ext/vendor/exuberant-ctags/get.h +50 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
- data/ext/vendor/exuberant-ctags/html.c +49 -0
- data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
- data/ext/vendor/exuberant-ctags/keyword.c +258 -0
- data/ext/vendor/exuberant-ctags/keyword.h +34 -0
- data/ext/vendor/exuberant-ctags/lisp.c +139 -0
- data/ext/vendor/exuberant-ctags/lregex.c +704 -0
- data/ext/vendor/exuberant-ctags/lua.c +133 -0
- data/ext/vendor/exuberant-ctags/mac.c +273 -0
- data/ext/vendor/exuberant-ctags/magic.diff +21 -0
- data/ext/vendor/exuberant-ctags/main.c +584 -0
- data/ext/vendor/exuberant-ctags/main.h +32 -0
- data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
- data/ext/vendor/exuberant-ctags/make.c +217 -0
- data/ext/vendor/exuberant-ctags/matlab.c +44 -0
- data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
- data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
- data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
- data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
- data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
- data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
- data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
- data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
- data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
- data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
- data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
- data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.h +155 -0
- data/ext/vendor/exuberant-ctags/parse.c +677 -0
- data/ext/vendor/exuberant-ctags/parse.h +129 -0
- data/ext/vendor/exuberant-ctags/parsers.h +63 -0
- data/ext/vendor/exuberant-ctags/pascal.c +267 -0
- data/ext/vendor/exuberant-ctags/perl.c +382 -0
- data/ext/vendor/exuberant-ctags/php.c +237 -0
- data/ext/vendor/exuberant-ctags/python.c +771 -0
- data/ext/vendor/exuberant-ctags/qdos.c +106 -0
- data/ext/vendor/exuberant-ctags/read.c +569 -0
- data/ext/vendor/exuberant-ctags/read.h +116 -0
- data/ext/vendor/exuberant-ctags/readtags.c +959 -0
- data/ext/vendor/exuberant-ctags/readtags.h +252 -0
- data/ext/vendor/exuberant-ctags/rexx.c +39 -0
- data/ext/vendor/exuberant-ctags/routines.c +891 -0
- data/ext/vendor/exuberant-ctags/routines.h +134 -0
- data/ext/vendor/exuberant-ctags/ruby.c +408 -0
- data/ext/vendor/exuberant-ctags/scheme.c +111 -0
- data/ext/vendor/exuberant-ctags/sh.c +115 -0
- data/ext/vendor/exuberant-ctags/slang.c +41 -0
- data/ext/vendor/exuberant-ctags/sml.c +212 -0
- data/ext/vendor/exuberant-ctags/sort.c +230 -0
- data/ext/vendor/exuberant-ctags/sort.h +32 -0
- data/ext/vendor/exuberant-ctags/source.mak +122 -0
- data/ext/vendor/exuberant-ctags/sql.c +2112 -0
- data/ext/vendor/exuberant-ctags/strlist.c +281 -0
- data/ext/vendor/exuberant-ctags/strlist.h +54 -0
- data/ext/vendor/exuberant-ctags/tcl.c +116 -0
- data/ext/vendor/exuberant-ctags/tex.c +524 -0
- data/ext/vendor/exuberant-ctags/verilog.c +340 -0
- data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
- data/ext/vendor/exuberant-ctags/vim.c +636 -0
- data/ext/vendor/exuberant-ctags/vstring.c +232 -0
- data/ext/vendor/exuberant-ctags/vstring.h +85 -0
- data/ext/vendor/exuberant-ctags/yacc.c +40 -0
- data/lib/ctags/exuberant.rb +45 -0
- data/lib/ctags/version.rb +3 -0
- data/lib/ctags.rb +6 -0
- data/test/test_ctags.rb +24 -0
- metadata +233 -0
|
@@ -0,0 +1,959 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* $Id: readtags.c 592 2007-07-31 03:30:41Z dhiebert $
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 1996-2003, Darren Hiebert
|
|
5
|
+
*
|
|
6
|
+
* This source code is released into the public domain.
|
|
7
|
+
*
|
|
8
|
+
* This module contains functions for reading tag files.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* INCLUDE FILES
|
|
13
|
+
*/
|
|
14
|
+
#include <stdlib.h>
|
|
15
|
+
#include <string.h>
|
|
16
|
+
#include <ctype.h>
|
|
17
|
+
#include <stdio.h>
|
|
18
|
+
#include <errno.h>
|
|
19
|
+
#include <sys/types.h> /* to declare off_t */
|
|
20
|
+
|
|
21
|
+
#include "readtags.h"
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* MACROS
|
|
25
|
+
*/
|
|
26
|
+
#define TAB '\t'
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* DATA DECLARATIONS
|
|
31
|
+
*/
|
|
32
|
+
typedef struct {
|
|
33
|
+
size_t size;
|
|
34
|
+
char *buffer;
|
|
35
|
+
} vstring;
|
|
36
|
+
|
|
37
|
+
/* Information about current tag file */
|
|
38
|
+
struct sTagFile {
|
|
39
|
+
/* has the file been opened and this structure initialized? */
|
|
40
|
+
short initialized;
|
|
41
|
+
/* format of tag file */
|
|
42
|
+
short format;
|
|
43
|
+
/* how is the tag file sorted? */
|
|
44
|
+
sortType sortMethod;
|
|
45
|
+
/* pointer to file structure */
|
|
46
|
+
FILE* fp;
|
|
47
|
+
/* file position of first character of `line' */
|
|
48
|
+
off_t pos;
|
|
49
|
+
/* size of tag file in seekable positions */
|
|
50
|
+
off_t size;
|
|
51
|
+
/* last line read */
|
|
52
|
+
vstring line;
|
|
53
|
+
/* name of tag in last line read */
|
|
54
|
+
vstring name;
|
|
55
|
+
/* defines tag search state */
|
|
56
|
+
struct {
|
|
57
|
+
/* file position of last match for tag */
|
|
58
|
+
off_t pos;
|
|
59
|
+
/* name of tag last searched for */
|
|
60
|
+
char *name;
|
|
61
|
+
/* length of name for partial matches */
|
|
62
|
+
size_t nameLength;
|
|
63
|
+
/* peforming partial match */
|
|
64
|
+
short partial;
|
|
65
|
+
/* ignoring case */
|
|
66
|
+
short ignorecase;
|
|
67
|
+
} search;
|
|
68
|
+
/* miscellaneous extension fields */
|
|
69
|
+
struct {
|
|
70
|
+
/* number of entries in `list' */
|
|
71
|
+
unsigned short max;
|
|
72
|
+
/* list of key value pairs */
|
|
73
|
+
tagExtensionField *list;
|
|
74
|
+
} fields;
|
|
75
|
+
/* buffers to be freed at close */
|
|
76
|
+
struct {
|
|
77
|
+
/* name of program author */
|
|
78
|
+
char *author;
|
|
79
|
+
/* name of program */
|
|
80
|
+
char *name;
|
|
81
|
+
/* URL of distribution */
|
|
82
|
+
char *url;
|
|
83
|
+
/* program version */
|
|
84
|
+
char *version;
|
|
85
|
+
} program;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
* DATA DEFINITIONS
|
|
90
|
+
*/
|
|
91
|
+
const char *const EmptyString = "";
|
|
92
|
+
const char *const PseudoTagPrefix = "!_";
|
|
93
|
+
|
|
94
|
+
/*
|
|
95
|
+
* FUNCTION DEFINITIONS
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* Compare two strings, ignoring case.
|
|
100
|
+
* Return 0 for match, < 0 for smaller, > 0 for bigger
|
|
101
|
+
* Make sure case is folded to uppercase in comparison (like for 'sort -f')
|
|
102
|
+
* This makes a difference when one of the chars lies between upper and lower
|
|
103
|
+
* ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !)
|
|
104
|
+
*/
|
|
105
|
+
static int struppercmp (const char *s1, const char *s2)
|
|
106
|
+
{
|
|
107
|
+
int result;
|
|
108
|
+
do
|
|
109
|
+
{
|
|
110
|
+
result = toupper ((int) *s1) - toupper ((int) *s2);
|
|
111
|
+
} while (result == 0 && *s1++ != '\0' && *s2++ != '\0');
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static int strnuppercmp (const char *s1, const char *s2, size_t n)
|
|
116
|
+
{
|
|
117
|
+
int result;
|
|
118
|
+
do
|
|
119
|
+
{
|
|
120
|
+
result = toupper ((int) *s1) - toupper ((int) *s2);
|
|
121
|
+
} while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0');
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static int growString (vstring *s)
|
|
126
|
+
{
|
|
127
|
+
int result = 0;
|
|
128
|
+
size_t newLength;
|
|
129
|
+
char *newLine;
|
|
130
|
+
if (s->size == 0)
|
|
131
|
+
{
|
|
132
|
+
newLength = 128;
|
|
133
|
+
newLine = (char*) malloc (newLength);
|
|
134
|
+
*newLine = '\0';
|
|
135
|
+
}
|
|
136
|
+
else
|
|
137
|
+
{
|
|
138
|
+
newLength = 2 * s->size;
|
|
139
|
+
newLine = (char*) realloc (s->buffer, newLength);
|
|
140
|
+
}
|
|
141
|
+
if (newLine == NULL)
|
|
142
|
+
perror ("string too large");
|
|
143
|
+
else
|
|
144
|
+
{
|
|
145
|
+
s->buffer = newLine;
|
|
146
|
+
s->size = newLength;
|
|
147
|
+
result = 1;
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Copy name of tag out of tag line */
|
|
153
|
+
static void copyName (tagFile *const file)
|
|
154
|
+
{
|
|
155
|
+
size_t length;
|
|
156
|
+
const char *end = strchr (file->line.buffer, '\t');
|
|
157
|
+
if (end == NULL)
|
|
158
|
+
{
|
|
159
|
+
end = strchr (file->line.buffer, '\n');
|
|
160
|
+
if (end == NULL)
|
|
161
|
+
end = strchr (file->line.buffer, '\r');
|
|
162
|
+
}
|
|
163
|
+
if (end != NULL)
|
|
164
|
+
length = end - file->line.buffer;
|
|
165
|
+
else
|
|
166
|
+
length = strlen (file->line.buffer);
|
|
167
|
+
while (length >= file->name.size)
|
|
168
|
+
growString (&file->name);
|
|
169
|
+
strncpy (file->name.buffer, file->line.buffer, length);
|
|
170
|
+
file->name.buffer [length] = '\0';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static int readTagLineRaw (tagFile *const file)
|
|
174
|
+
{
|
|
175
|
+
int result = 1;
|
|
176
|
+
int reReadLine;
|
|
177
|
+
|
|
178
|
+
/* If reading the line places any character other than a null or a
|
|
179
|
+
* newline at the last character position in the buffer (one less than
|
|
180
|
+
* the buffer size), then we must resize the buffer and reattempt to read
|
|
181
|
+
* the line.
|
|
182
|
+
*/
|
|
183
|
+
do
|
|
184
|
+
{
|
|
185
|
+
char *const pLastChar = file->line.buffer + file->line.size - 2;
|
|
186
|
+
char *line;
|
|
187
|
+
|
|
188
|
+
file->pos = ftell (file->fp);
|
|
189
|
+
reReadLine = 0;
|
|
190
|
+
*pLastChar = '\0';
|
|
191
|
+
line = fgets (file->line.buffer, (int) file->line.size, file->fp);
|
|
192
|
+
if (line == NULL)
|
|
193
|
+
{
|
|
194
|
+
/* read error */
|
|
195
|
+
if (! feof (file->fp))
|
|
196
|
+
perror ("readTagLine");
|
|
197
|
+
result = 0;
|
|
198
|
+
}
|
|
199
|
+
else if (*pLastChar != '\0' &&
|
|
200
|
+
*pLastChar != '\n' && *pLastChar != '\r')
|
|
201
|
+
{
|
|
202
|
+
/* buffer overflow */
|
|
203
|
+
growString (&file->line);
|
|
204
|
+
fseek (file->fp, file->pos, SEEK_SET);
|
|
205
|
+
reReadLine = 1;
|
|
206
|
+
}
|
|
207
|
+
else
|
|
208
|
+
{
|
|
209
|
+
size_t i = strlen (file->line.buffer);
|
|
210
|
+
while (i > 0 &&
|
|
211
|
+
(file->line.buffer [i - 1] == '\n' || file->line.buffer [i - 1] == '\r'))
|
|
212
|
+
{
|
|
213
|
+
file->line.buffer [i - 1] = '\0';
|
|
214
|
+
--i;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} while (reReadLine && result);
|
|
218
|
+
if (result)
|
|
219
|
+
copyName (file);
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static int readTagLine (tagFile *const file)
|
|
224
|
+
{
|
|
225
|
+
int result;
|
|
226
|
+
do
|
|
227
|
+
{
|
|
228
|
+
result = readTagLineRaw (file);
|
|
229
|
+
} while (result && *file->name.buffer == '\0');
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static tagResult growFields (tagFile *const file)
|
|
234
|
+
{
|
|
235
|
+
tagResult result = TagFailure;
|
|
236
|
+
unsigned short newCount = (unsigned short) 2 * file->fields.max;
|
|
237
|
+
tagExtensionField *newFields = (tagExtensionField*)
|
|
238
|
+
realloc (file->fields.list, newCount * sizeof (tagExtensionField));
|
|
239
|
+
if (newFields == NULL)
|
|
240
|
+
perror ("too many extension fields");
|
|
241
|
+
else
|
|
242
|
+
{
|
|
243
|
+
file->fields.list = newFields;
|
|
244
|
+
file->fields.max = newCount;
|
|
245
|
+
result = TagSuccess;
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static void parseExtensionFields (tagFile *const file, tagEntry *const entry,
|
|
251
|
+
char *const string)
|
|
252
|
+
{
|
|
253
|
+
char *p = string;
|
|
254
|
+
while (p != NULL && *p != '\0')
|
|
255
|
+
{
|
|
256
|
+
while (*p == TAB)
|
|
257
|
+
*p++ = '\0';
|
|
258
|
+
if (*p != '\0')
|
|
259
|
+
{
|
|
260
|
+
char *colon;
|
|
261
|
+
char *field = p;
|
|
262
|
+
p = strchr (p, TAB);
|
|
263
|
+
if (p != NULL)
|
|
264
|
+
*p++ = '\0';
|
|
265
|
+
colon = strchr (field, ':');
|
|
266
|
+
if (colon == NULL)
|
|
267
|
+
entry->kind = field;
|
|
268
|
+
else
|
|
269
|
+
{
|
|
270
|
+
const char *key = field;
|
|
271
|
+
const char *value = colon + 1;
|
|
272
|
+
*colon = '\0';
|
|
273
|
+
if (strcmp (key, "kind") == 0)
|
|
274
|
+
entry->kind = value;
|
|
275
|
+
else if (strcmp (key, "file") == 0)
|
|
276
|
+
entry->fileScope = 1;
|
|
277
|
+
else if (strcmp (key, "line") == 0)
|
|
278
|
+
entry->address.lineNumber = atol (value);
|
|
279
|
+
else
|
|
280
|
+
{
|
|
281
|
+
if (entry->fields.count == file->fields.max)
|
|
282
|
+
growFields (file);
|
|
283
|
+
file->fields.list [entry->fields.count].key = key;
|
|
284
|
+
file->fields.list [entry->fields.count].value = value;
|
|
285
|
+
++entry->fields.count;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
static void parseTagLine (tagFile *file, tagEntry *const entry)
|
|
293
|
+
{
|
|
294
|
+
int i;
|
|
295
|
+
char *p = file->line.buffer;
|
|
296
|
+
char *tab = strchr (p, TAB);
|
|
297
|
+
|
|
298
|
+
entry->fields.list = NULL;
|
|
299
|
+
entry->fields.count = 0;
|
|
300
|
+
entry->kind = NULL;
|
|
301
|
+
entry->fileScope = 0;
|
|
302
|
+
|
|
303
|
+
entry->name = p;
|
|
304
|
+
if (tab != NULL)
|
|
305
|
+
{
|
|
306
|
+
*tab = '\0';
|
|
307
|
+
p = tab + 1;
|
|
308
|
+
entry->file = p;
|
|
309
|
+
tab = strchr (p, TAB);
|
|
310
|
+
if (tab != NULL)
|
|
311
|
+
{
|
|
312
|
+
int fieldsPresent;
|
|
313
|
+
*tab = '\0';
|
|
314
|
+
p = tab + 1;
|
|
315
|
+
if (*p == '/' || *p == '?')
|
|
316
|
+
{
|
|
317
|
+
/* parse pattern */
|
|
318
|
+
int delimiter = *(unsigned char*) p;
|
|
319
|
+
entry->address.lineNumber = 0;
|
|
320
|
+
entry->address.pattern = p;
|
|
321
|
+
do
|
|
322
|
+
{
|
|
323
|
+
p = strchr (p + 1, delimiter);
|
|
324
|
+
} while (p != NULL && *(p - 1) == '\\');
|
|
325
|
+
if (p == NULL)
|
|
326
|
+
{
|
|
327
|
+
/* invalid pattern */
|
|
328
|
+
}
|
|
329
|
+
else
|
|
330
|
+
++p;
|
|
331
|
+
}
|
|
332
|
+
else if (isdigit ((int) *(unsigned char*) p))
|
|
333
|
+
{
|
|
334
|
+
/* parse line number */
|
|
335
|
+
entry->address.pattern = p;
|
|
336
|
+
entry->address.lineNumber = atol (p);
|
|
337
|
+
while (isdigit ((int) *(unsigned char*) p))
|
|
338
|
+
++p;
|
|
339
|
+
}
|
|
340
|
+
else
|
|
341
|
+
{
|
|
342
|
+
/* invalid pattern */
|
|
343
|
+
}
|
|
344
|
+
fieldsPresent = (strncmp (p, ";\"", 2) == 0);
|
|
345
|
+
*p = '\0';
|
|
346
|
+
if (fieldsPresent)
|
|
347
|
+
parseExtensionFields (file, entry, p + 2);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (entry->fields.count > 0)
|
|
351
|
+
entry->fields.list = file->fields.list;
|
|
352
|
+
for (i = entry->fields.count ; i < file->fields.max ; ++i)
|
|
353
|
+
{
|
|
354
|
+
file->fields.list [i].key = NULL;
|
|
355
|
+
file->fields.list [i].value = NULL;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
static char *duplicate (const char *str)
|
|
360
|
+
{
|
|
361
|
+
char *result = NULL;
|
|
362
|
+
if (str != NULL)
|
|
363
|
+
{
|
|
364
|
+
result = strdup (str);
|
|
365
|
+
if (result == NULL)
|
|
366
|
+
perror (NULL);
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
static void readPseudoTags (tagFile *const file, tagFileInfo *const info)
|
|
372
|
+
{
|
|
373
|
+
fpos_t startOfLine;
|
|
374
|
+
const size_t prefixLength = strlen (PseudoTagPrefix);
|
|
375
|
+
if (info != NULL)
|
|
376
|
+
{
|
|
377
|
+
info->file.format = 1;
|
|
378
|
+
info->file.sort = TAG_UNSORTED;
|
|
379
|
+
info->program.author = NULL;
|
|
380
|
+
info->program.name = NULL;
|
|
381
|
+
info->program.url = NULL;
|
|
382
|
+
info->program.version = NULL;
|
|
383
|
+
}
|
|
384
|
+
while (1)
|
|
385
|
+
{
|
|
386
|
+
fgetpos (file->fp, &startOfLine);
|
|
387
|
+
if (! readTagLine (file))
|
|
388
|
+
break;
|
|
389
|
+
if (strncmp (file->line.buffer, PseudoTagPrefix, prefixLength) != 0)
|
|
390
|
+
break;
|
|
391
|
+
else
|
|
392
|
+
{
|
|
393
|
+
tagEntry entry;
|
|
394
|
+
const char *key, *value;
|
|
395
|
+
parseTagLine (file, &entry);
|
|
396
|
+
key = entry.name + prefixLength;
|
|
397
|
+
value = entry.file;
|
|
398
|
+
if (strcmp (key, "TAG_FILE_SORTED") == 0)
|
|
399
|
+
file->sortMethod = (sortType) atoi (value);
|
|
400
|
+
else if (strcmp (key, "TAG_FILE_FORMAT") == 0)
|
|
401
|
+
file->format = (short) atoi (value);
|
|
402
|
+
else if (strcmp (key, "TAG_PROGRAM_AUTHOR") == 0)
|
|
403
|
+
file->program.author = duplicate (value);
|
|
404
|
+
else if (strcmp (key, "TAG_PROGRAM_NAME") == 0)
|
|
405
|
+
file->program.name = duplicate (value);
|
|
406
|
+
else if (strcmp (key, "TAG_PROGRAM_URL") == 0)
|
|
407
|
+
file->program.url = duplicate (value);
|
|
408
|
+
else if (strcmp (key, "TAG_PROGRAM_VERSION") == 0)
|
|
409
|
+
file->program.version = duplicate (value);
|
|
410
|
+
if (info != NULL)
|
|
411
|
+
{
|
|
412
|
+
info->file.format = file->format;
|
|
413
|
+
info->file.sort = file->sortMethod;
|
|
414
|
+
info->program.author = file->program.author;
|
|
415
|
+
info->program.name = file->program.name;
|
|
416
|
+
info->program.url = file->program.url;
|
|
417
|
+
info->program.version = file->program.version;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
fsetpos (file->fp, &startOfLine);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
static void gotoFirstLogicalTag (tagFile *const file)
|
|
425
|
+
{
|
|
426
|
+
fpos_t startOfLine;
|
|
427
|
+
const size_t prefixLength = strlen (PseudoTagPrefix);
|
|
428
|
+
rewind (file->fp);
|
|
429
|
+
while (1)
|
|
430
|
+
{
|
|
431
|
+
fgetpos (file->fp, &startOfLine);
|
|
432
|
+
if (! readTagLine (file))
|
|
433
|
+
break;
|
|
434
|
+
if (strncmp (file->line.buffer, PseudoTagPrefix, prefixLength) != 0)
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
fsetpos (file->fp, &startOfLine);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
static tagFile *initialize (const char *const filePath, tagFileInfo *const info)
|
|
441
|
+
{
|
|
442
|
+
tagFile *result = (tagFile*) calloc ((size_t) 1, sizeof (tagFile));
|
|
443
|
+
if (result != NULL)
|
|
444
|
+
{
|
|
445
|
+
growString (&result->line);
|
|
446
|
+
growString (&result->name);
|
|
447
|
+
result->fields.max = 20;
|
|
448
|
+
result->fields.list = (tagExtensionField*) calloc (
|
|
449
|
+
result->fields.max, sizeof (tagExtensionField));
|
|
450
|
+
result->fp = fopen (filePath, "r");
|
|
451
|
+
if (result->fp == NULL)
|
|
452
|
+
{
|
|
453
|
+
free (result);
|
|
454
|
+
result = NULL;
|
|
455
|
+
info->status.error_number = errno;
|
|
456
|
+
}
|
|
457
|
+
else
|
|
458
|
+
{
|
|
459
|
+
fseek (result->fp, 0, SEEK_END);
|
|
460
|
+
result->size = ftell (result->fp);
|
|
461
|
+
rewind (result->fp);
|
|
462
|
+
readPseudoTags (result, info);
|
|
463
|
+
info->status.opened = 1;
|
|
464
|
+
result->initialized = 1;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return result;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
static void terminate (tagFile *const file)
|
|
471
|
+
{
|
|
472
|
+
fclose (file->fp);
|
|
473
|
+
|
|
474
|
+
free (file->line.buffer);
|
|
475
|
+
free (file->name.buffer);
|
|
476
|
+
free (file->fields.list);
|
|
477
|
+
|
|
478
|
+
if (file->program.author != NULL)
|
|
479
|
+
free (file->program.author);
|
|
480
|
+
if (file->program.name != NULL)
|
|
481
|
+
free (file->program.name);
|
|
482
|
+
if (file->program.url != NULL)
|
|
483
|
+
free (file->program.url);
|
|
484
|
+
if (file->program.version != NULL)
|
|
485
|
+
free (file->program.version);
|
|
486
|
+
if (file->search.name != NULL)
|
|
487
|
+
free (file->search.name);
|
|
488
|
+
|
|
489
|
+
memset (file, 0, sizeof (tagFile));
|
|
490
|
+
|
|
491
|
+
free (file);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
static tagResult readNext (tagFile *const file, tagEntry *const entry)
|
|
495
|
+
{
|
|
496
|
+
tagResult result;
|
|
497
|
+
if (file == NULL || ! file->initialized)
|
|
498
|
+
result = TagFailure;
|
|
499
|
+
else if (! readTagLine (file))
|
|
500
|
+
result = TagFailure;
|
|
501
|
+
else
|
|
502
|
+
{
|
|
503
|
+
if (entry != NULL)
|
|
504
|
+
parseTagLine (file, entry);
|
|
505
|
+
result = TagSuccess;
|
|
506
|
+
}
|
|
507
|
+
return result;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
static const char *readFieldValue (
|
|
511
|
+
const tagEntry *const entry, const char *const key)
|
|
512
|
+
{
|
|
513
|
+
const char *result = NULL;
|
|
514
|
+
int i;
|
|
515
|
+
if (strcmp (key, "kind") == 0)
|
|
516
|
+
result = entry->kind;
|
|
517
|
+
else if (strcmp (key, "file") == 0)
|
|
518
|
+
result = EmptyString;
|
|
519
|
+
else for (i = 0 ; i < entry->fields.count && result == NULL ; ++i)
|
|
520
|
+
if (strcmp (entry->fields.list [i].key, key) == 0)
|
|
521
|
+
result = entry->fields.list [i].value;
|
|
522
|
+
return result;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
static int readTagLineSeek (tagFile *const file, const off_t pos)
|
|
526
|
+
{
|
|
527
|
+
int result = 0;
|
|
528
|
+
if (fseek (file->fp, pos, SEEK_SET) == 0)
|
|
529
|
+
{
|
|
530
|
+
result = readTagLine (file); /* read probable partial line */
|
|
531
|
+
if (pos > 0 && result)
|
|
532
|
+
result = readTagLine (file); /* read complete line */
|
|
533
|
+
}
|
|
534
|
+
return result;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
static int nameComparison (tagFile *const file)
|
|
538
|
+
{
|
|
539
|
+
int result;
|
|
540
|
+
if (file->search.ignorecase)
|
|
541
|
+
{
|
|
542
|
+
if (file->search.partial)
|
|
543
|
+
result = strnuppercmp (file->search.name, file->name.buffer,
|
|
544
|
+
file->search.nameLength);
|
|
545
|
+
else
|
|
546
|
+
result = struppercmp (file->search.name, file->name.buffer);
|
|
547
|
+
}
|
|
548
|
+
else
|
|
549
|
+
{
|
|
550
|
+
if (file->search.partial)
|
|
551
|
+
result = strncmp (file->search.name, file->name.buffer,
|
|
552
|
+
file->search.nameLength);
|
|
553
|
+
else
|
|
554
|
+
result = strcmp (file->search.name, file->name.buffer);
|
|
555
|
+
}
|
|
556
|
+
return result;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
static void findFirstNonMatchBefore (tagFile *const file)
|
|
560
|
+
{
|
|
561
|
+
#define JUMP_BACK 512
|
|
562
|
+
int more_lines;
|
|
563
|
+
int comp;
|
|
564
|
+
off_t start = file->pos;
|
|
565
|
+
off_t pos = start;
|
|
566
|
+
do
|
|
567
|
+
{
|
|
568
|
+
if (pos < (off_t) JUMP_BACK)
|
|
569
|
+
pos = 0;
|
|
570
|
+
else
|
|
571
|
+
pos = pos - JUMP_BACK;
|
|
572
|
+
more_lines = readTagLineSeek (file, pos);
|
|
573
|
+
comp = nameComparison (file);
|
|
574
|
+
} while (more_lines && comp == 0 && pos > 0 && pos < start);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
static tagResult findFirstMatchBefore (tagFile *const file)
|
|
578
|
+
{
|
|
579
|
+
tagResult result = TagFailure;
|
|
580
|
+
int more_lines;
|
|
581
|
+
off_t start = file->pos;
|
|
582
|
+
findFirstNonMatchBefore (file);
|
|
583
|
+
do
|
|
584
|
+
{
|
|
585
|
+
more_lines = readTagLine (file);
|
|
586
|
+
if (nameComparison (file) == 0)
|
|
587
|
+
result = TagSuccess;
|
|
588
|
+
} while (more_lines && result != TagSuccess && file->pos < start);
|
|
589
|
+
return result;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
static tagResult findBinary (tagFile *const file)
|
|
593
|
+
{
|
|
594
|
+
tagResult result = TagFailure;
|
|
595
|
+
off_t lower_limit = 0;
|
|
596
|
+
off_t upper_limit = file->size;
|
|
597
|
+
off_t last_pos = 0;
|
|
598
|
+
off_t pos = upper_limit / 2;
|
|
599
|
+
while (result != TagSuccess)
|
|
600
|
+
{
|
|
601
|
+
if (! readTagLineSeek (file, pos))
|
|
602
|
+
{
|
|
603
|
+
/* in case we fell off end of file */
|
|
604
|
+
result = findFirstMatchBefore (file);
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
else if (pos == last_pos)
|
|
608
|
+
{
|
|
609
|
+
/* prevent infinite loop if we backed up to beginning of file */
|
|
610
|
+
break;
|
|
611
|
+
}
|
|
612
|
+
else
|
|
613
|
+
{
|
|
614
|
+
const int comp = nameComparison (file);
|
|
615
|
+
last_pos = pos;
|
|
616
|
+
if (comp < 0)
|
|
617
|
+
{
|
|
618
|
+
upper_limit = pos;
|
|
619
|
+
pos = lower_limit + ((upper_limit - lower_limit) / 2);
|
|
620
|
+
}
|
|
621
|
+
else if (comp > 0)
|
|
622
|
+
{
|
|
623
|
+
lower_limit = pos;
|
|
624
|
+
pos = lower_limit + ((upper_limit - lower_limit) / 2);
|
|
625
|
+
}
|
|
626
|
+
else if (pos == 0)
|
|
627
|
+
result = TagSuccess;
|
|
628
|
+
else
|
|
629
|
+
result = findFirstMatchBefore (file);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
static tagResult findSequential (tagFile *const file)
|
|
636
|
+
{
|
|
637
|
+
tagResult result = TagFailure;
|
|
638
|
+
if (file->initialized)
|
|
639
|
+
{
|
|
640
|
+
while (result == TagFailure && readTagLine (file))
|
|
641
|
+
{
|
|
642
|
+
if (nameComparison (file) == 0)
|
|
643
|
+
result = TagSuccess;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return result;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
static tagResult find (tagFile *const file, tagEntry *const entry,
|
|
650
|
+
const char *const name, const int options)
|
|
651
|
+
{
|
|
652
|
+
tagResult result;
|
|
653
|
+
if (file->search.name != NULL)
|
|
654
|
+
free (file->search.name);
|
|
655
|
+
file->search.name = duplicate (name);
|
|
656
|
+
file->search.nameLength = strlen (name);
|
|
657
|
+
file->search.partial = (options & TAG_PARTIALMATCH) != 0;
|
|
658
|
+
file->search.ignorecase = (options & TAG_IGNORECASE) != 0;
|
|
659
|
+
fseek (file->fp, 0, SEEK_END);
|
|
660
|
+
file->size = ftell (file->fp);
|
|
661
|
+
rewind (file->fp);
|
|
662
|
+
if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) ||
|
|
663
|
+
(file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase))
|
|
664
|
+
{
|
|
665
|
+
#ifdef DEBUG
|
|
666
|
+
printf ("<performing binary search>\n");
|
|
667
|
+
#endif
|
|
668
|
+
result = findBinary (file);
|
|
669
|
+
}
|
|
670
|
+
else
|
|
671
|
+
{
|
|
672
|
+
#ifdef DEBUG
|
|
673
|
+
printf ("<performing sequential search>\n");
|
|
674
|
+
#endif
|
|
675
|
+
result = findSequential (file);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (result != TagSuccess)
|
|
679
|
+
file->search.pos = file->size;
|
|
680
|
+
else
|
|
681
|
+
{
|
|
682
|
+
file->search.pos = file->pos;
|
|
683
|
+
if (entry != NULL)
|
|
684
|
+
parseTagLine (file, entry);
|
|
685
|
+
}
|
|
686
|
+
return result;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
static tagResult findNext (tagFile *const file, tagEntry *const entry)
|
|
690
|
+
{
|
|
691
|
+
tagResult result;
|
|
692
|
+
if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) ||
|
|
693
|
+
(file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase))
|
|
694
|
+
{
|
|
695
|
+
result = tagsNext (file, entry);
|
|
696
|
+
if (result == TagSuccess && nameComparison (file) != 0)
|
|
697
|
+
result = TagFailure;
|
|
698
|
+
}
|
|
699
|
+
else
|
|
700
|
+
{
|
|
701
|
+
result = findSequential (file);
|
|
702
|
+
if (result == TagSuccess && entry != NULL)
|
|
703
|
+
parseTagLine (file, entry);
|
|
704
|
+
}
|
|
705
|
+
return result;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/*
|
|
709
|
+
* EXTERNAL INTERFACE
|
|
710
|
+
*/
|
|
711
|
+
|
|
712
|
+
extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info)
|
|
713
|
+
{
|
|
714
|
+
return initialize (filePath, info);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
extern tagResult tagsSetSortType (tagFile *const file, const sortType type)
|
|
718
|
+
{
|
|
719
|
+
tagResult result = TagFailure;
|
|
720
|
+
if (file != NULL && file->initialized)
|
|
721
|
+
{
|
|
722
|
+
file->sortMethod = type;
|
|
723
|
+
result = TagSuccess;
|
|
724
|
+
}
|
|
725
|
+
return result;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry)
|
|
729
|
+
{
|
|
730
|
+
tagResult result = TagFailure;
|
|
731
|
+
if (file != NULL && file->initialized)
|
|
732
|
+
{
|
|
733
|
+
gotoFirstLogicalTag (file);
|
|
734
|
+
result = readNext (file, entry);
|
|
735
|
+
}
|
|
736
|
+
return result;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
extern tagResult tagsNext (tagFile *const file, tagEntry *const entry)
|
|
740
|
+
{
|
|
741
|
+
tagResult result = TagFailure;
|
|
742
|
+
if (file != NULL && file->initialized)
|
|
743
|
+
result = readNext (file, entry);
|
|
744
|
+
return result;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
extern const char *tagsField (const tagEntry *const entry, const char *const key)
|
|
748
|
+
{
|
|
749
|
+
const char *result = NULL;
|
|
750
|
+
if (entry != NULL)
|
|
751
|
+
result = readFieldValue (entry, key);
|
|
752
|
+
return result;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
extern tagResult tagsFind (tagFile *const file, tagEntry *const entry,
|
|
756
|
+
const char *const name, const int options)
|
|
757
|
+
{
|
|
758
|
+
tagResult result = TagFailure;
|
|
759
|
+
if (file != NULL && file->initialized)
|
|
760
|
+
result = find (file, entry, name, options);
|
|
761
|
+
return result;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry)
|
|
765
|
+
{
|
|
766
|
+
tagResult result = TagFailure;
|
|
767
|
+
if (file != NULL && file->initialized)
|
|
768
|
+
result = findNext (file, entry);
|
|
769
|
+
return result;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
extern tagResult tagsClose (tagFile *const file)
|
|
773
|
+
{
|
|
774
|
+
tagResult result = TagFailure;
|
|
775
|
+
if (file != NULL && file->initialized)
|
|
776
|
+
{
|
|
777
|
+
terminate (file);
|
|
778
|
+
result = TagSuccess;
|
|
779
|
+
}
|
|
780
|
+
return result;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/*
|
|
784
|
+
* TEST FRAMEWORK
|
|
785
|
+
*/
|
|
786
|
+
|
|
787
|
+
#ifdef READTAGS_MAIN
|
|
788
|
+
|
|
789
|
+
static const char *TagFileName = "tags";
|
|
790
|
+
static const char *ProgramName;
|
|
791
|
+
static int extensionFields;
|
|
792
|
+
static int SortOverride;
|
|
793
|
+
static sortType SortMethod;
|
|
794
|
+
|
|
795
|
+
static void printTag (const tagEntry *entry)
|
|
796
|
+
{
|
|
797
|
+
int i;
|
|
798
|
+
int first = 1;
|
|
799
|
+
const char* separator = ";\"";
|
|
800
|
+
const char* const empty = "";
|
|
801
|
+
/* "sep" returns a value only the first time it is evaluated */
|
|
802
|
+
#define sep (first ? (first = 0, separator) : empty)
|
|
803
|
+
printf ("%s\t%s\t%s",
|
|
804
|
+
entry->name, entry->file, entry->address.pattern);
|
|
805
|
+
if (extensionFields)
|
|
806
|
+
{
|
|
807
|
+
if (entry->kind != NULL && entry->kind [0] != '\0')
|
|
808
|
+
printf ("%s\tkind:%s", sep, entry->kind);
|
|
809
|
+
if (entry->fileScope)
|
|
810
|
+
printf ("%s\tfile:", sep);
|
|
811
|
+
#if 0
|
|
812
|
+
if (entry->address.lineNumber > 0)
|
|
813
|
+
printf ("%s\tline:%lu", sep, entry->address.lineNumber);
|
|
814
|
+
#endif
|
|
815
|
+
for (i = 0 ; i < entry->fields.count ; ++i)
|
|
816
|
+
printf ("%s\t%s:%s", sep, entry->fields.list [i].key,
|
|
817
|
+
entry->fields.list [i].value);
|
|
818
|
+
}
|
|
819
|
+
putchar ('\n');
|
|
820
|
+
#undef sep
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static void findTag (const char *const name, const int options)
|
|
824
|
+
{
|
|
825
|
+
tagFileInfo info;
|
|
826
|
+
tagEntry entry;
|
|
827
|
+
tagFile *const file = tagsOpen (TagFileName, &info);
|
|
828
|
+
if (file == NULL)
|
|
829
|
+
{
|
|
830
|
+
fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
|
|
831
|
+
ProgramName, strerror (info.status.error_number), name);
|
|
832
|
+
exit (1);
|
|
833
|
+
}
|
|
834
|
+
else
|
|
835
|
+
{
|
|
836
|
+
if (SortOverride)
|
|
837
|
+
tagsSetSortType (file, SortMethod);
|
|
838
|
+
if (tagsFind (file, &entry, name, options) == TagSuccess)
|
|
839
|
+
{
|
|
840
|
+
do
|
|
841
|
+
{
|
|
842
|
+
printTag (&entry);
|
|
843
|
+
} while (tagsFindNext (file, &entry) == TagSuccess);
|
|
844
|
+
}
|
|
845
|
+
tagsClose (file);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
static void listTags (void)
|
|
850
|
+
{
|
|
851
|
+
tagFileInfo info;
|
|
852
|
+
tagEntry entry;
|
|
853
|
+
tagFile *const file = tagsOpen (TagFileName, &info);
|
|
854
|
+
if (file == NULL)
|
|
855
|
+
{
|
|
856
|
+
fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
|
|
857
|
+
ProgramName, strerror (info.status.error_number), TagFileName);
|
|
858
|
+
exit (1);
|
|
859
|
+
}
|
|
860
|
+
else
|
|
861
|
+
{
|
|
862
|
+
while (tagsNext (file, &entry) == TagSuccess)
|
|
863
|
+
printTag (&entry);
|
|
864
|
+
tagsClose (file);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
const char *const Usage =
|
|
869
|
+
"Find tag file entries matching specified names.\n\n"
|
|
870
|
+
"Usage: %s [-ilp] [-s[0|1]] [-t file] [name(s)]\n\n"
|
|
871
|
+
"Options:\n"
|
|
872
|
+
" -e Include extension fields in output.\n"
|
|
873
|
+
" -i Perform case-insensitive matching.\n"
|
|
874
|
+
" -l List all tags.\n"
|
|
875
|
+
" -p Perform partial matching.\n"
|
|
876
|
+
" -s[0|1|2] Override sort detection of tag file.\n"
|
|
877
|
+
" -t file Use specified tag file (default: \"tags\").\n"
|
|
878
|
+
"Note that options are acted upon as encountered, so order is significant.\n";
|
|
879
|
+
|
|
880
|
+
extern int main (int argc, char **argv)
|
|
881
|
+
{
|
|
882
|
+
int options = 0;
|
|
883
|
+
int actionSupplied = 0;
|
|
884
|
+
int i;
|
|
885
|
+
ProgramName = argv [0];
|
|
886
|
+
if (argc == 1)
|
|
887
|
+
{
|
|
888
|
+
fprintf (stderr, Usage, ProgramName);
|
|
889
|
+
exit (1);
|
|
890
|
+
}
|
|
891
|
+
for (i = 1 ; i < argc ; ++i)
|
|
892
|
+
{
|
|
893
|
+
const char *const arg = argv [i];
|
|
894
|
+
if (arg [0] != '-')
|
|
895
|
+
{
|
|
896
|
+
findTag (arg, options);
|
|
897
|
+
actionSupplied = 1;
|
|
898
|
+
}
|
|
899
|
+
else
|
|
900
|
+
{
|
|
901
|
+
size_t j;
|
|
902
|
+
for (j = 1 ; arg [j] != '\0' ; ++j)
|
|
903
|
+
{
|
|
904
|
+
switch (arg [j])
|
|
905
|
+
{
|
|
906
|
+
case 'e': extensionFields = 1; break;
|
|
907
|
+
case 'i': options |= TAG_IGNORECASE; break;
|
|
908
|
+
case 'p': options |= TAG_PARTIALMATCH; break;
|
|
909
|
+
case 'l': listTags (); actionSupplied = 1; break;
|
|
910
|
+
|
|
911
|
+
case 't':
|
|
912
|
+
if (arg [j+1] != '\0')
|
|
913
|
+
{
|
|
914
|
+
TagFileName = arg + j + 1;
|
|
915
|
+
j += strlen (TagFileName);
|
|
916
|
+
}
|
|
917
|
+
else if (i + 1 < argc)
|
|
918
|
+
TagFileName = argv [++i];
|
|
919
|
+
else
|
|
920
|
+
{
|
|
921
|
+
fprintf (stderr, Usage, ProgramName);
|
|
922
|
+
exit (1);
|
|
923
|
+
}
|
|
924
|
+
break;
|
|
925
|
+
case 's':
|
|
926
|
+
SortOverride = 1;
|
|
927
|
+
++j;
|
|
928
|
+
if (arg [j] == '\0')
|
|
929
|
+
SortMethod = TAG_SORTED;
|
|
930
|
+
else if (strchr ("012", arg[j]) != NULL)
|
|
931
|
+
SortMethod = (sortType) (arg[j] - '0');
|
|
932
|
+
else
|
|
933
|
+
{
|
|
934
|
+
fprintf (stderr, Usage, ProgramName);
|
|
935
|
+
exit (1);
|
|
936
|
+
}
|
|
937
|
+
break;
|
|
938
|
+
default:
|
|
939
|
+
fprintf (stderr, "%s: unknown option: %c\n",
|
|
940
|
+
ProgramName, arg[j]);
|
|
941
|
+
exit (1);
|
|
942
|
+
break;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (! actionSupplied)
|
|
948
|
+
{
|
|
949
|
+
fprintf (stderr,
|
|
950
|
+
"%s: no action specified: specify tag name(s) or -l option\n",
|
|
951
|
+
ProgramName);
|
|
952
|
+
exit (1);
|
|
953
|
+
}
|
|
954
|
+
return 0;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
#endif
|
|
958
|
+
|
|
959
|
+
/* vi:set tabstop=4 shiftwidth=4: */
|