Merge pull request #3587 from techee/unused_remove
[geany-mirror.git] / ctags / main / mini-geany.c
blob8dc324e305d098de919524fd1f40283418d01c77
1 /*
2 * Copyright (c) 2019, Jiri Techet
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * Provides a simple application using ctags as a library and using the same
8 * set of ctags functions as the Geany editor
9 */
11 #include "general.h" /* must always come first */
13 #include "types.h"
14 #include "routines.h"
15 #include "mio.h"
16 #include "error_p.h"
17 #include "writer_p.h"
18 #include "parse_p.h"
19 #include "options_p.h"
20 #include "trashbox_p.h"
21 #include "field_p.h"
22 #include "xtag_p.h"
23 #include "entry_p.h"
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
29 static int writeEntry (tagWriter *writer, MIO * mio, const tagEntryInfo *const tag, void *clientData);
30 static void rescanFailed (tagWriter *writer, unsigned long validTagNum, void *clientData);
32 /* we need to be able to provide a custom writer using which we collect the tags */
33 tagWriter customWriter = {
34 .writeEntry = writeEntry,
35 .writePtagEntry = NULL,
36 .preWriteEntry = NULL,
37 .postWriteEntry = NULL,
38 .rescanFailedEntry = rescanFailed,
39 .treatFieldAsFixed = NULL,
40 .defaultFileName = "tags_file_which_should_never_appear_anywhere",
41 .private = NULL,
45 /* we need to be able to provide an error printer which doesn't crash Geany on error */
46 static bool nofatalErrorPrinter (const errorSelection selection,
47 const char *const format,
48 va_list ap, void *data CTAGS_ATTR_UNUSED)
50 fprintf (stderr, "%s: ", (selection & WARNING) ? "Warning: " : "Error");
51 vfprintf (stderr, format, ap);
52 if (selection & PERROR)
53 #ifdef HAVE_STRERROR
54 fprintf (stderr, " : %s", strerror (errno));
55 #else
56 perror (" ");
57 #endif
58 fputs ("\n", stderr);
60 return false;
64 /* we need to be able to enable all kinds for all languages (some are disabled by default) */
65 static void enableAllLangKinds()
67 unsigned int lang;
69 for (lang = 0; lang < countParsers(); lang++)
71 unsigned int kindNum = countLanguageKinds(lang);
72 unsigned int kind;
74 for (kind = 0; kind < kindNum; kind++)
76 kindDefinition *def = getLanguageKind(lang, kind);
77 enableKind(def, true);
83 /* we need to be able to initialize ctags like in main() but skipping some things */
84 static void ctagsInit(void)
86 initDefaultTrashBox ();
88 setErrorPrinter (nofatalErrorPrinter, NULL);
89 setTagWriter (WRITER_CUSTOM, &customWriter);
91 checkRegex ();
92 initFieldObjects ();
93 initXtagObjects ();
95 initializeParsing ();
96 initOptions ();
98 /* make sure all parsers are initialized */
99 initializeParser (LANG_AUTO);
101 /* change default value which is false */
102 enableXtag(XTAG_TAGS_GENERATED_BY_GUEST_PARSERS, true);
103 enableXtag(XTAG_REFERENCE_TAGS, true);
105 /* some kinds we are interested in are disabled by default */
106 enableAllLangKinds();
110 /* we need to be able to get a name of a given language */
111 static const char *ctagsGetLangName(int lang)
113 return getLanguageName(lang);
117 /* we need to be able to get an int representing a given language */
118 static int ctagsGetNamedLang(const char *name)
120 return getNamedLanguage(name, 0);
124 /* we need to be able to get kind letters provided by a given language */
125 static const char *ctagsGetLangKinds(int lang)
127 unsigned int kindNum = countLanguageKinds(lang);
128 static char kinds[257];
129 unsigned int i;
131 for (i = 0; i < kindNum; i++)
132 kinds[i] = getLanguageKind(lang, i)->letter;
133 kinds[i] = '\0';
135 return kinds;
139 /* we need to be able to get kind name from a kind letter for a given language */
140 static const char *ctagsGetKindName(char kind, int lang)
142 kindDefinition *def = getLanguageKindForLetter (lang, kind);
143 return def ? def->name : "unknown";
147 /* we need to be able to get kind letter from a kind name for a given language */
148 static char ctagsGetKindFromName(const char *name, int lang)
150 kindDefinition *def = getLanguageKindForName (lang, name);
151 return def ? def->letter : '-';
155 /* we need to be able to get kind letter from a kind index */
156 static char ctagsGetKindFromIndex(int index, int lang)
158 return getLanguageKind(lang, index)->letter;
162 /* we need to be able to get the number of parsers */
163 static unsigned int ctagsGetLangCount(void)
165 return countParsers();
168 /*******************************************************************************
169 * So let's just use what we have for our great client...
170 ******************************************************************************/
172 /* our internal tag representation - this is all the tag information we use in Geany */
173 typedef struct {
174 char *name;
175 char *signature;
176 char *scopeName;
177 char *inheritance;
178 char *varType;
179 char *access;
180 char *implementation;
181 char kindLetter;
182 bool isFileScope;
183 unsigned long lineNumber;
184 int lang;
185 } Tag;
188 static Tag *createTag(const tagEntryInfo *info)
190 Tag *tag = xCalloc(1, Tag);
191 if (info->name)
192 tag->name = eStrdup(info->name);
193 if (info->extensionFields.signature)
194 tag->signature = eStrdup(info->extensionFields.signature);
195 if (info->extensionFields.scopeName)
196 tag->scopeName = eStrdup(info->extensionFields.scopeName);
197 if (info->extensionFields.inheritance)
198 tag->inheritance = eStrdup(info->extensionFields.inheritance);
199 if (info->extensionFields.typeRef[1])
200 tag->varType = eStrdup(info->extensionFields.typeRef[1]);
201 if (info->extensionFields.access)
202 tag->access = eStrdup(info->extensionFields.access);
203 if (info->extensionFields.implementation)
204 tag->implementation = eStrdup(info->extensionFields.implementation);
205 tag->kindLetter = ctagsGetKindFromIndex(info->kindIndex, info->langType);
206 tag->isFileScope = info->isFileScope;
207 tag->lineNumber = info->lineNumber;
208 tag->lang = info->langType;
209 return tag;
213 static void destroyTag(Tag *tag)
215 if (tag->name)
216 eFree(tag->name);
217 if (tag->signature)
218 eFree(tag->signature);
219 if (tag->scopeName)
220 eFree(tag->scopeName);
221 if (tag->inheritance)
222 eFree(tag->inheritance);
223 if (tag->varType)
224 eFree(tag->varType);
225 if (tag->access)
226 eFree(tag->access);
227 if (tag->implementation)
228 eFree(tag->implementation);
229 eFree(tag);
233 /* callback from ctags informing us about a new tag */
234 static int writeEntry (tagWriter *writer, MIO *mio, const tagEntryInfo *const tag, void *clientData)
236 Tag *t;
238 /* apparently we have to call this to get the scope info - maybe we can
239 * specify some option during initialization so we don't have to cal this
240 * ?????? */
241 getTagScopeInformation((tagEntryInfo *)tag, NULL, NULL);
243 /* convert tags into our internal representation and store them into an array */
244 t = createTag(tag);
245 ptrArrayAdd((ptrArray *)clientData, t);
247 /* output length - we don't write anything to the MIO */
248 return 0;
252 /* scan has failed so we have invalid tags in our array - validTagNum should
253 * tell us the number of valid tags so remove all the extra tags and shrink the array */
254 static void rescanFailed (tagWriter *writer, unsigned long validTagNum, void *clientData)
256 ptrArray *tagArray = clientData;
257 int num = ptrArrayCount(tagArray);
259 if (num > validTagNum)
261 int i;
262 for (i = validTagNum; i < num; i++)
264 Tag *tag = ptrArrayLast(tagArray);
265 destroyTag(tag);
266 ptrArrayRemoveLast(tagArray);
272 /* do whatever we want to do with the tags */
273 static void processCollectedTags(ptrArray *tagArray)
275 int i;
276 int num = ptrArrayCount(tagArray);
278 for (i = 0; i < num; i++)
280 Tag *tag = ptrArrayItem(tagArray, i);
281 printf("%s\tline: %lu\tkind: %s\t lang: %s\n",
282 tag->name,
283 tag->lineNumber,
284 ctagsGetKindName(tag->kindLetter, tag->lang),
285 ctagsGetLangName(tag->lang));
288 /* prepare for the next parsing by clearing the tag array */
289 ptrArrayClear(tagArray);
293 extern int main (int argc, char **argv)
295 /* called once when Geany starts */
296 ctagsInit();
298 /* create empty tag array *
299 * this is where we store the collected tags
300 * NOTE: Geany doesn't use the ptrArray type - it is used just for the purpose of this demo */
301 ptrArray *tagArray = ptrArrayNew((ptrArrayDeleteFunc)destroyTag);
303 printf("This parser only parses C files - provide them as arguments on the "
304 "command line or get a hard-coded buffer parsed when no arguments "
305 "are provided\n\n");
306 if (argc == 1) /* parsing contents of a buffer */
308 char *program = "int foo() {}\n\n int bar() {}\n\n int main() {}\n";
309 int lang = ctagsGetNamedLang("C");
310 const char *kinds = ctagsGetLangKinds(lang);
311 int i;
313 printf("Number of all parsers is: %d\n", ctagsGetLangCount());
314 printf("We are parsing %s which provides the following kinds:\n",
315 ctagsGetLangName(lang));
316 for (i = 0; kinds[i] != '\0'; i++)
318 printf("%c: %s\n",
319 /* back and forth conversion - the same like just kinds[i] */
320 ctagsGetKindFromName(ctagsGetKindName(kinds[i], lang), lang),
321 ctagsGetKindName(kinds[i], lang));
324 printf("\nParsing buffer:\n");
325 /* we always specify the language by ourselves and don't use ctags detection */
326 parseRawBuffer("whatever", (unsigned char *)program, strlen(program), lang, tagArray);
328 processCollectedTags(tagArray);
330 else /* parsing contents of a file */
332 int i;
333 for (i = 1; i < argc; i++)
335 printf("\nParsing %s:\n", argv[i]);
336 /* parseRawBuffer() is called repeatadly during Geany execution */
337 parseRawBuffer(argv[i], NULL, 0, getNamedLanguage("C", 0), tagArray);
339 processCollectedTags(tagArray);
343 ptrArrayDelete(tagArray);
345 return 0;