1d4c6f1e6SMasatake YAMATO /*
2d4c6f1e6SMasatake YAMATO * Copyright (c) 1996-2003, Darren Hiebert
3d4c6f1e6SMasatake YAMATO *
4d4c6f1e6SMasatake YAMATO * Author: Darren Hiebert <dhiebert@users.sourceforge.net>
5d4c6f1e6SMasatake YAMATO * http://ctags.sourceforge.net
6d4c6f1e6SMasatake YAMATO *
7d4c6f1e6SMasatake YAMATO * This source code is released for free distribution under the terms of the
80ce38835Sviccuad * GNU General Public License version 2 or (at your option) any later version.
90ce38835Sviccuad * It is provided on an as-is basis and no responsibility is accepted for its
100ce38835Sviccuad * failure to perform as expected.
11d4c6f1e6SMasatake YAMATO *
12d4c6f1e6SMasatake YAMATO * This is a reimplementation of the ctags (1) program. It is an attempt to
13d4c6f1e6SMasatake YAMATO * provide a fully featured ctags program which is free of the limitations
14d4c6f1e6SMasatake YAMATO * which most (all?) others are subject to.
15d4c6f1e6SMasatake YAMATO *
16d4c6f1e6SMasatake YAMATO * This module contains the start-up code and routines to determine the list
17d4c6f1e6SMasatake YAMATO * of files to parsed for tags.
18d4c6f1e6SMasatake YAMATO */
19d4c6f1e6SMasatake YAMATO
20d4c6f1e6SMasatake YAMATO /*
21d4c6f1e6SMasatake YAMATO * INCLUDE FILES
22d4c6f1e6SMasatake YAMATO */
23d4c6f1e6SMasatake YAMATO #include "general.h" /* must always come first */
24d4c6f1e6SMasatake YAMATO
25d4c6f1e6SMasatake YAMATO #if HAVE_DECL___ENVIRON
26d4c6f1e6SMasatake YAMATO #include <unistd.h>
27d4c6f1e6SMasatake YAMATO #elif HAVE_DECL__NSGETENVIRON
28d4c6f1e6SMasatake YAMATO #include <crt_externs.h>
29d4c6f1e6SMasatake YAMATO #endif
30d4c6f1e6SMasatake YAMATO
31d75f1db8SK.Takata #include <stdlib.h>
32d4c6f1e6SMasatake YAMATO #include <string.h>
33d75f1db8SK.Takata #include <time.h>
34d4c6f1e6SMasatake YAMATO
35d4c6f1e6SMasatake YAMATO /* To provide directory searching for recursion feature.
36d4c6f1e6SMasatake YAMATO */
37d4c6f1e6SMasatake YAMATO
38d4c6f1e6SMasatake YAMATO #ifdef HAVE_DIRENT_H
39d4c6f1e6SMasatake YAMATO # ifdef HAVE_SYS_TYPES_H
40d4c6f1e6SMasatake YAMATO # include <sys/types.h> /* required by dirent.h */
41d4c6f1e6SMasatake YAMATO # endif
42d4c6f1e6SMasatake YAMATO # include <dirent.h> /* to declare opendir() */
43d4c6f1e6SMasatake YAMATO #endif
44d4c6f1e6SMasatake YAMATO #ifdef HAVE_DIRECT_H
45d4c6f1e6SMasatake YAMATO # include <direct.h> /* to _getcwd() */
46d4c6f1e6SMasatake YAMATO #endif
47d4c6f1e6SMasatake YAMATO #ifdef HAVE_IO_H
48d4c6f1e6SMasatake YAMATO # include <io.h> /* to declare _findfirst() */
49d4c6f1e6SMasatake YAMATO #endif
50d4c6f1e6SMasatake YAMATO
51d4c6f1e6SMasatake YAMATO
522050d074SAman Gupta #include "ctags.h"
53d4c6f1e6SMasatake YAMATO #include "debug.h"
548cbf052bSMasatake YAMATO #include "entry_p.h"
557e412a04SMasatake YAMATO #include "error_p.h"
56c08c70d0SMasatake YAMATO #include "field_p.h"
5724448fceSMasatake YAMATO #include "keyword_p.h"
58e45c3e90SMasatake YAMATO #include "main_p.h"
5921996d92SMasatake YAMATO #include "options_p.h"
60e8386a4eSMasatake YAMATO #include "optscript.h"
610d502ef0SMasatake YAMATO #include "parse_p.h"
62b5df137eSMasatake YAMATO #include "read_p.h"
6329e40fb6SMasatake YAMATO #include "routines_p.h"
64df2449f1SMasatake YAMATO #include "stats_p.h"
65d33423e3SSzymon Tomasz Stefanek #include "trace.h"
66869a1bbcSMasatake YAMATO #include "trashbox_p.h"
67285b4dfeSMasatake YAMATO #include "writer_p.h"
68e2a3289bSMasatake YAMATO #include "xtag_p.h"
69d4c6f1e6SMasatake YAMATO
702050d074SAman Gupta #ifdef HAVE_JANSSON
7121996d92SMasatake YAMATO #include "interactive_p.h"
722050d074SAman Gupta #include <jansson.h>
732050d074SAman Gupta #include <errno.h>
742050d074SAman Gupta #endif
752050d074SAman Gupta
76d4c6f1e6SMasatake YAMATO /*
77d4c6f1e6SMasatake YAMATO * DATA DEFINITIONS
78d4c6f1e6SMasatake YAMATO */
79a0870c64SMasatake YAMATO static mainLoopFunc mainLoop;
80a0870c64SMasatake YAMATO static void *mainData;
81d4c6f1e6SMasatake YAMATO
82d4c6f1e6SMasatake YAMATO /*
83d4c6f1e6SMasatake YAMATO * FUNCTION PROTOTYPES
84d4c6f1e6SMasatake YAMATO */
85ce990805SThomas Braun static bool createTagsForEntry (const char *const entryName);
86d4c6f1e6SMasatake YAMATO
87d4c6f1e6SMasatake YAMATO /*
88d4c6f1e6SMasatake YAMATO * FUNCTION DEFINITIONS
89d4c6f1e6SMasatake YAMATO */
90d4c6f1e6SMasatake YAMATO
91e225a827SJiří Techet #if defined (HAVE_OPENDIR) && (defined (HAVE_DIRENT_H) || defined (_MSC_VER))
recurseUsingOpendir(const char * const dirName)92ce990805SThomas Braun static bool recurseUsingOpendir (const char *const dirName)
93d4c6f1e6SMasatake YAMATO {
94ce990805SThomas Braun bool resize = false;
95d4c6f1e6SMasatake YAMATO DIR *const dir = opendir (dirName);
96d4c6f1e6SMasatake YAMATO if (dir == NULL)
97d4c6f1e6SMasatake YAMATO error (WARNING | PERROR, "cannot recurse into directory \"%s\"", dirName);
98d4c6f1e6SMasatake YAMATO else
99d4c6f1e6SMasatake YAMATO {
100d4c6f1e6SMasatake YAMATO struct dirent *entry;
101d4c6f1e6SMasatake YAMATO while ((entry = readdir (dir)) != NULL)
102d4c6f1e6SMasatake YAMATO {
103d4c6f1e6SMasatake YAMATO if (strcmp (entry->d_name, ".") != 0 &&
104d4c6f1e6SMasatake YAMATO strcmp (entry->d_name, "..") != 0)
105d4c6f1e6SMasatake YAMATO {
106d4c6f1e6SMasatake YAMATO char *filePath;
107ce990805SThomas Braun bool free_p = false;
108d4c6f1e6SMasatake YAMATO if (strcmp (dirName, ".") == 0)
109d4c6f1e6SMasatake YAMATO filePath = entry->d_name;
110d4c6f1e6SMasatake YAMATO else
111d4c6f1e6SMasatake YAMATO {
112d4c6f1e6SMasatake YAMATO filePath = combinePathAndFile (dirName, entry->d_name);
113ce990805SThomas Braun free_p = true;
114d4c6f1e6SMasatake YAMATO }
115d4c6f1e6SMasatake YAMATO resize |= createTagsForEntry (filePath);
116d4c6f1e6SMasatake YAMATO if (free_p)
117d4c6f1e6SMasatake YAMATO eFree (filePath);
118d4c6f1e6SMasatake YAMATO }
119d4c6f1e6SMasatake YAMATO }
120d4c6f1e6SMasatake YAMATO closedir (dir);
121d4c6f1e6SMasatake YAMATO }
122d4c6f1e6SMasatake YAMATO return resize;
123d4c6f1e6SMasatake YAMATO }
124*eed4431bSK.Takata #endif
125d4c6f1e6SMasatake YAMATO
126*eed4431bSK.Takata #ifdef HAVE__FINDFIRST
127d4c6f1e6SMasatake YAMATO
createTagsForWildcardEntry(const char * const pattern,const size_t dirLength,const char * const entryName)128ce990805SThomas Braun static bool createTagsForWildcardEntry (
129d4c6f1e6SMasatake YAMATO const char *const pattern, const size_t dirLength,
130d4c6f1e6SMasatake YAMATO const char *const entryName)
131d4c6f1e6SMasatake YAMATO {
132ce990805SThomas Braun bool resize = false;
133d4c6f1e6SMasatake YAMATO /* we must not recurse into the directories "." or ".." */
134d4c6f1e6SMasatake YAMATO if (strcmp (entryName, ".") != 0 && strcmp (entryName, "..") != 0)
135d4c6f1e6SMasatake YAMATO {
136d4c6f1e6SMasatake YAMATO vString *const filePath = vStringNew ();
137d4c6f1e6SMasatake YAMATO vStringNCopyS (filePath, pattern, dirLength);
138d4c6f1e6SMasatake YAMATO vStringCatS (filePath, entryName);
139d4c6f1e6SMasatake YAMATO resize = createTagsForEntry (vStringValue (filePath));
140d4c6f1e6SMasatake YAMATO vStringDelete (filePath);
141d4c6f1e6SMasatake YAMATO }
142d4c6f1e6SMasatake YAMATO return resize;
143d4c6f1e6SMasatake YAMATO }
144d4c6f1e6SMasatake YAMATO
createTagsForWildcardUsingFindfirst(const char * const pattern)145ce990805SThomas Braun static bool createTagsForWildcardUsingFindfirst (const char *const pattern)
146d4c6f1e6SMasatake YAMATO {
147ce990805SThomas Braun bool resize = false;
148d4c6f1e6SMasatake YAMATO const size_t dirLength = baseFilename (pattern) - pattern;
149d4c6f1e6SMasatake YAMATO struct _finddata_t fileInfo;
150*eed4431bSK.Takata intptr_t hFile = _findfirst (pattern, &fileInfo);
151d4c6f1e6SMasatake YAMATO if (hFile != -1L)
152d4c6f1e6SMasatake YAMATO {
153d4c6f1e6SMasatake YAMATO do
154d4c6f1e6SMasatake YAMATO {
155d4c6f1e6SMasatake YAMATO const char *const entry = (const char *) fileInfo.name;
156d4c6f1e6SMasatake YAMATO resize |= createTagsForWildcardEntry (pattern, dirLength, entry);
157d4c6f1e6SMasatake YAMATO } while (_findnext (hFile, &fileInfo) == 0);
158d4c6f1e6SMasatake YAMATO _findclose (hFile);
159d4c6f1e6SMasatake YAMATO }
160d4c6f1e6SMasatake YAMATO return resize;
161d4c6f1e6SMasatake YAMATO }
162d4c6f1e6SMasatake YAMATO
163d4c6f1e6SMasatake YAMATO #endif
164d4c6f1e6SMasatake YAMATO
165078b8008SSzymon Tomasz Stefanek
recurseIntoDirectory(const char * const dirName)166ce990805SThomas Braun static bool recurseIntoDirectory (const char *const dirName)
167d4c6f1e6SMasatake YAMATO {
168078b8008SSzymon Tomasz Stefanek static unsigned int recursionDepth = 0;
169078b8008SSzymon Tomasz Stefanek
170078b8008SSzymon Tomasz Stefanek recursionDepth++;
171078b8008SSzymon Tomasz Stefanek
172ce990805SThomas Braun bool resize = false;
173d4c6f1e6SMasatake YAMATO if (isRecursiveLink (dirName))
174d4c6f1e6SMasatake YAMATO verbose ("ignoring \"%s\" (recursive link)\n", dirName);
175d4c6f1e6SMasatake YAMATO else if (! Option.recurse)
176d4c6f1e6SMasatake YAMATO verbose ("ignoring \"%s\" (directory)\n", dirName);
177078b8008SSzymon Tomasz Stefanek else if(recursionDepth > Option.maxRecursionDepth)
178078b8008SSzymon Tomasz Stefanek verbose ("not descending in directory \"%s\" (depth %u > %u)\n",
179078b8008SSzymon Tomasz Stefanek dirName, recursionDepth, Option.maxRecursionDepth);
180d4c6f1e6SMasatake YAMATO else
181d4c6f1e6SMasatake YAMATO {
182d4c6f1e6SMasatake YAMATO verbose ("RECURSING into directory \"%s\"\n", dirName);
183e225a827SJiří Techet #if defined (HAVE_OPENDIR) && (defined (HAVE_DIRENT_H) || defined (_MSC_VER))
184d4c6f1e6SMasatake YAMATO resize = recurseUsingOpendir (dirName);
18582b817f7SK.Takata #elif defined (HAVE__FINDFIRST)
186d4c6f1e6SMasatake YAMATO {
187d4c6f1e6SMasatake YAMATO vString *const pattern = vStringNew ();
188d4c6f1e6SMasatake YAMATO vStringCopyS (pattern, dirName);
189d4c6f1e6SMasatake YAMATO vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
190d4c6f1e6SMasatake YAMATO vStringCatS (pattern, "*.*");
191d4c6f1e6SMasatake YAMATO resize = createTagsForWildcardUsingFindfirst (vStringValue (pattern));
192d4c6f1e6SMasatake YAMATO vStringDelete (pattern);
193d4c6f1e6SMasatake YAMATO }
194d4c6f1e6SMasatake YAMATO #endif
195d4c6f1e6SMasatake YAMATO }
196078b8008SSzymon Tomasz Stefanek
197078b8008SSzymon Tomasz Stefanek recursionDepth--;
198078b8008SSzymon Tomasz Stefanek
199d4c6f1e6SMasatake YAMATO return resize;
200d4c6f1e6SMasatake YAMATO }
201d4c6f1e6SMasatake YAMATO
createTagsForEntry(const char * const entryName)202ce990805SThomas Braun static bool createTagsForEntry (const char *const entryName)
203d4c6f1e6SMasatake YAMATO {
204ce990805SThomas Braun bool resize = false;
205d4c6f1e6SMasatake YAMATO fileStatus *status = eStat (entryName);
206d4c6f1e6SMasatake YAMATO
207d4c6f1e6SMasatake YAMATO Assert (entryName != NULL);
208ff29abd0SMasatake YAMATO if (isExcludedFile (entryName, true))
209ff29abd0SMasatake YAMATO verbose ("excluding \"%s\" (the early stage)\n", entryName);
210d4c6f1e6SMasatake YAMATO else if (status->isSymbolicLink && ! Option.followLinks)
211d4c6f1e6SMasatake YAMATO verbose ("ignoring \"%s\" (symbolic link)\n", entryName);
212d4c6f1e6SMasatake YAMATO else if (! status->exists)
213123deefaSMasatake YAMATO error (WARNING | PERROR, "cannot open input file \"%s\"", entryName);
214d4c6f1e6SMasatake YAMATO else if (status->isDirectory)
215d4c6f1e6SMasatake YAMATO resize = recurseIntoDirectory (entryName);
216d4c6f1e6SMasatake YAMATO else if (! status->isNormalFile)
217d4c6f1e6SMasatake YAMATO verbose ("ignoring \"%s\" (special file)\n", entryName);
218ff29abd0SMasatake YAMATO else if (isExcludedFile (entryName, false))
219ff29abd0SMasatake YAMATO verbose ("excluding \"%s\"\n", entryName);
220d4c6f1e6SMasatake YAMATO else
221d4c6f1e6SMasatake YAMATO resize = parseFile (entryName);
222d4c6f1e6SMasatake YAMATO
223d4c6f1e6SMasatake YAMATO eStatFree (status);
224d4c6f1e6SMasatake YAMATO return resize;
225d4c6f1e6SMasatake YAMATO }
226d4c6f1e6SMasatake YAMATO
227d4c6f1e6SMasatake YAMATO #ifdef MANUAL_GLOBBING
228d4c6f1e6SMasatake YAMATO
createTagsForWildcardArg(const char * const arg)229ce990805SThomas Braun static bool createTagsForWildcardArg (const char *const arg)
230d4c6f1e6SMasatake YAMATO {
231ce990805SThomas Braun bool resize = false;
232d4c6f1e6SMasatake YAMATO vString *const pattern = vStringNewInit (arg);
233d4c6f1e6SMasatake YAMATO char *patternS = vStringValue (pattern);
234d4c6f1e6SMasatake YAMATO
23582b817f7SK.Takata #if defined (HAVE__FINDFIRST)
236d4c6f1e6SMasatake YAMATO /* We must transform the "." and ".." forms into something that can
23782b817f7SK.Takata * be expanded by the _findfirst function.
238d4c6f1e6SMasatake YAMATO */
239d4c6f1e6SMasatake YAMATO if (Option.recurse &&
240d4c6f1e6SMasatake YAMATO (strcmp (patternS, ".") == 0 || strcmp (patternS, "..") == 0))
241d4c6f1e6SMasatake YAMATO {
242d4c6f1e6SMasatake YAMATO vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
243d4c6f1e6SMasatake YAMATO vStringCatS (pattern, "*.*");
244d4c6f1e6SMasatake YAMATO }
245d4c6f1e6SMasatake YAMATO resize |= createTagsForWildcardUsingFindfirst (patternS);
246d4c6f1e6SMasatake YAMATO #endif
247d4c6f1e6SMasatake YAMATO vStringDelete (pattern);
248d4c6f1e6SMasatake YAMATO return resize;
249d4c6f1e6SMasatake YAMATO }
250d4c6f1e6SMasatake YAMATO
251d4c6f1e6SMasatake YAMATO #endif
252d4c6f1e6SMasatake YAMATO
createTagsForArgs(cookedArgs * const args)253ce990805SThomas Braun static bool createTagsForArgs (cookedArgs *const args)
254d4c6f1e6SMasatake YAMATO {
255ce990805SThomas Braun bool resize = false;
256d4c6f1e6SMasatake YAMATO
257d4c6f1e6SMasatake YAMATO /* Generate tags for each argument on the command line.
258d4c6f1e6SMasatake YAMATO */
259d4c6f1e6SMasatake YAMATO while (! cArgOff (args))
260d4c6f1e6SMasatake YAMATO {
261d4c6f1e6SMasatake YAMATO const char *const arg = cArgItem (args);
262d4c6f1e6SMasatake YAMATO
263d4c6f1e6SMasatake YAMATO #ifdef MANUAL_GLOBBING
264d4c6f1e6SMasatake YAMATO resize |= createTagsForWildcardArg (arg);
265d4c6f1e6SMasatake YAMATO #else
266d4c6f1e6SMasatake YAMATO resize |= createTagsForEntry (arg);
267d4c6f1e6SMasatake YAMATO #endif
268d4c6f1e6SMasatake YAMATO cArgForth (args);
269d4afb66eSMasatake YAMATO parseCmdlineOptions (args);
270d4c6f1e6SMasatake YAMATO }
271d4c6f1e6SMasatake YAMATO return resize;
272d4c6f1e6SMasatake YAMATO }
273d4c6f1e6SMasatake YAMATO
274d4c6f1e6SMasatake YAMATO /* Read from an opened file a list of file names for which to generate tags.
275d4c6f1e6SMasatake YAMATO */
createTagsFromFileInput(FILE * const fp,const bool filter)276ce990805SThomas Braun static bool createTagsFromFileInput (FILE *const fp, const bool filter)
277d4c6f1e6SMasatake YAMATO {
278ce990805SThomas Braun bool resize = false;
279d4c6f1e6SMasatake YAMATO if (fp != NULL)
280d4c6f1e6SMasatake YAMATO {
281d4c6f1e6SMasatake YAMATO cookedArgs *args = cArgNewFromLineFile (fp);
282d4afb66eSMasatake YAMATO parseCmdlineOptions (args);
283d4c6f1e6SMasatake YAMATO while (! cArgOff (args))
284d4c6f1e6SMasatake YAMATO {
285d4c6f1e6SMasatake YAMATO resize |= createTagsForEntry (cArgItem (args));
286d4c6f1e6SMasatake YAMATO if (filter)
287d4c6f1e6SMasatake YAMATO {
288d4c6f1e6SMasatake YAMATO if (Option.filterTerminator != NULL)
289d4c6f1e6SMasatake YAMATO fputs (Option.filterTerminator, stdout);
290d4c6f1e6SMasatake YAMATO fflush (stdout);
291d4c6f1e6SMasatake YAMATO }
292d4c6f1e6SMasatake YAMATO cArgForth (args);
293d4afb66eSMasatake YAMATO parseCmdlineOptions (args);
294d4c6f1e6SMasatake YAMATO }
295d4c6f1e6SMasatake YAMATO cArgDelete (args);
296d4c6f1e6SMasatake YAMATO }
297d4c6f1e6SMasatake YAMATO return resize;
298d4c6f1e6SMasatake YAMATO }
299d4c6f1e6SMasatake YAMATO
300d4c6f1e6SMasatake YAMATO /* Read from a named file a list of file names for which to generate tags.
301d4c6f1e6SMasatake YAMATO */
createTagsFromListFile(const char * const fileName)302ce990805SThomas Braun static bool createTagsFromListFile (const char *const fileName)
303d4c6f1e6SMasatake YAMATO {
304ce990805SThomas Braun bool resize;
305d4c6f1e6SMasatake YAMATO Assert (fileName != NULL);
306d4c6f1e6SMasatake YAMATO if (strcmp (fileName, "-") == 0)
307ce990805SThomas Braun resize = createTagsFromFileInput (stdin, false);
308d4c6f1e6SMasatake YAMATO else
309d4c6f1e6SMasatake YAMATO {
310d4c6f1e6SMasatake YAMATO FILE *const fp = fopen (fileName, "r");
311d4c6f1e6SMasatake YAMATO if (fp == NULL)
312d4c6f1e6SMasatake YAMATO error (FATAL | PERROR, "cannot open list file \"%s\"", fileName);
313ce990805SThomas Braun resize = createTagsFromFileInput (fp, false);
314d4c6f1e6SMasatake YAMATO fclose (fp);
315d4c6f1e6SMasatake YAMATO }
316d4c6f1e6SMasatake YAMATO return resize;
317d4c6f1e6SMasatake YAMATO }
318d4c6f1e6SMasatake YAMATO
etagsInclude(void)319ce990805SThomas Braun static bool etagsInclude (void)
320d4c6f1e6SMasatake YAMATO {
321ce990805SThomas Braun return (bool)(Option.etags && Option.etagsInclude != NULL);
322d4c6f1e6SMasatake YAMATO }
323d4c6f1e6SMasatake YAMATO
setMainLoop(mainLoopFunc func,void * data)324a0870c64SMasatake YAMATO extern void setMainLoop (mainLoopFunc func, void *data)
325a0870c64SMasatake YAMATO {
326a0870c64SMasatake YAMATO mainLoop = func;
327a0870c64SMasatake YAMATO mainData = data;
328a0870c64SMasatake YAMATO }
329a0870c64SMasatake YAMATO
runMainLoop(cookedArgs * args)330a0870c64SMasatake YAMATO static void runMainLoop (cookedArgs *args)
331a0870c64SMasatake YAMATO {
332a0870c64SMasatake YAMATO (* mainLoop) (args, mainData);
333a0870c64SMasatake YAMATO }
334a0870c64SMasatake YAMATO
batchMakeTags(cookedArgs * args,void * user CTAGS_ATTR_UNUSED)3358ccb7ee9SJiří Techet static void batchMakeTags (cookedArgs *args, void *user CTAGS_ATTR_UNUSED)
336d4c6f1e6SMasatake YAMATO {
337d4c6f1e6SMasatake YAMATO clock_t timeStamps [3];
338ce990805SThomas Braun bool resize = false;
339ce990805SThomas Braun bool files = (bool)(! cArgOff (args) || Option.fileList != NULL
340d4c6f1e6SMasatake YAMATO || Option.filter);
341d4c6f1e6SMasatake YAMATO
342d4c6f1e6SMasatake YAMATO if (! files)
343d4c6f1e6SMasatake YAMATO {
344d4c6f1e6SMasatake YAMATO if (filesRequired ())
345d4c6f1e6SMasatake YAMATO error (FATAL, "No files specified. Try \"%s --help\".",
346d4c6f1e6SMasatake YAMATO getExecutableName ());
347d4c6f1e6SMasatake YAMATO else if (! Option.recurse && ! etagsInclude ())
348d4c6f1e6SMasatake YAMATO return;
349d4c6f1e6SMasatake YAMATO }
350d4c6f1e6SMasatake YAMATO
351d4c6f1e6SMasatake YAMATO #define timeStamp(n) timeStamps[(n)]=(Option.printTotals ? clock():(clock_t)0)
352d4c6f1e6SMasatake YAMATO if ((! Option.filter) && (! Option.printLanguage))
353d4c6f1e6SMasatake YAMATO openTagFile ();
354d4c6f1e6SMasatake YAMATO
355d4c6f1e6SMasatake YAMATO timeStamp (0);
356d4c6f1e6SMasatake YAMATO
357d4c6f1e6SMasatake YAMATO if (! cArgOff (args))
358d4c6f1e6SMasatake YAMATO {
359d4c6f1e6SMasatake YAMATO verbose ("Reading command line arguments\n");
360d4c6f1e6SMasatake YAMATO resize = createTagsForArgs (args);
361d4c6f1e6SMasatake YAMATO }
362d4c6f1e6SMasatake YAMATO if (Option.fileList != NULL)
363d4c6f1e6SMasatake YAMATO {
364d4c6f1e6SMasatake YAMATO verbose ("Reading list file\n");
365ce990805SThomas Braun resize = (bool) (createTagsFromListFile (Option.fileList) || resize);
366d4c6f1e6SMasatake YAMATO }
367d4c6f1e6SMasatake YAMATO if (Option.filter)
368d4c6f1e6SMasatake YAMATO {
369d4c6f1e6SMasatake YAMATO verbose ("Reading filter input\n");
370ce990805SThomas Braun resize = (bool) (createTagsFromFileInput (stdin, true) || resize);
371d4c6f1e6SMasatake YAMATO }
372d4c6f1e6SMasatake YAMATO if (! files && Option.recurse)
373d4c6f1e6SMasatake YAMATO resize = recurseIntoDirectory (".");
374d4c6f1e6SMasatake YAMATO
375d4c6f1e6SMasatake YAMATO timeStamp (1);
376d4c6f1e6SMasatake YAMATO
377d4c6f1e6SMasatake YAMATO if ((! Option.filter) && (!Option.printLanguage))
378d4c6f1e6SMasatake YAMATO closeTagFile (resize);
379d4c6f1e6SMasatake YAMATO
380d4c6f1e6SMasatake YAMATO timeStamp (2);
381d4c6f1e6SMasatake YAMATO
382d4c6f1e6SMasatake YAMATO if (Option.printTotals)
383a9c91f4dSMasatake YAMATO {
384df2449f1SMasatake YAMATO printTotals (timeStamps, Option.append, Option.sorted);
385a9c91f4dSMasatake YAMATO if (Option.printTotals > 1)
386a9c91f4dSMasatake YAMATO for (unsigned int i = 0; i < countParsers(); i++)
387a9c91f4dSMasatake YAMATO printParserStatisticsIfUsed (i);
388a9c91f4dSMasatake YAMATO }
389a9c91f4dSMasatake YAMATO
390d4c6f1e6SMasatake YAMATO #undef timeStamp
391d4c6f1e6SMasatake YAMATO }
392d4c6f1e6SMasatake YAMATO
3932050d074SAman Gupta #ifdef HAVE_JANSSON
interactiveLoop(cookedArgs * args CTAGS_ATTR_UNUSED,void * user)3943c130a08SMasatake YAMATO void interactiveLoop (cookedArgs *args CTAGS_ATTR_UNUSED, void *user)
3952050d074SAman Gupta {
396c59f2a21SMasatake YAMATO struct interactiveModeArgs *iargs = user;
397c59f2a21SMasatake YAMATO
398c59f2a21SMasatake YAMATO if (iargs->sandbox) {
399e7ed5190SHan-Wen Nienhuys /* As of jansson 2.6, the object hashing is seeded off
400e7ed5190SHan-Wen Nienhuys of /dev/urandom, so trigger the hash seeding
401e7ed5190SHan-Wen Nienhuys before installing the syscall filter.
402e7ed5190SHan-Wen Nienhuys */
403e7ed5190SHan-Wen Nienhuys json_t * tmp = json_object ();
404e7ed5190SHan-Wen Nienhuys json_decref (tmp);
405e7ed5190SHan-Wen Nienhuys
406e7ed5190SHan-Wen Nienhuys if (installSyscallFilter ()) {
407e7ed5190SHan-Wen Nienhuys error (FATAL, "install_syscall_filter failed");
408cbd4b79eSMasatake YAMATO /* The explicit exit call is needed because
409cbd4b79eSMasatake YAMATO "error (FATAL,..." just prints a message in
410cbd4b79eSMasatake YAMATO interactive mode. */
411cbd4b79eSMasatake YAMATO exit (1);
412e7ed5190SHan-Wen Nienhuys }
413e7ed5190SHan-Wen Nienhuys }
414e7ed5190SHan-Wen Nienhuys
4152050d074SAman Gupta char buffer[1024];
4162050d074SAman Gupta json_t *request;
4172050d074SAman Gupta
4182050d074SAman Gupta fputs ("{\"_type\": \"program\", \"name\": \"" PROGRAM_NAME "\", \"version\": \"" PROGRAM_VERSION "\"}\n", stdout);
4192050d074SAman Gupta fflush (stdout);
4202050d074SAman Gupta
4212050d074SAman Gupta while (fgets (buffer, sizeof(buffer), stdin))
4222050d074SAman Gupta {
4232050d074SAman Gupta if (buffer[0] == '\n')
4242050d074SAman Gupta continue;
4252050d074SAman Gupta
4262050d074SAman Gupta request = json_loads (buffer, JSON_DISABLE_EOF_CHECK, NULL);
4272050d074SAman Gupta if (! request)
4282050d074SAman Gupta {
4292050d074SAman Gupta error (FATAL, "invalid json");
4302050d074SAman Gupta goto next;
4312050d074SAman Gupta }
4322050d074SAman Gupta
4332050d074SAman Gupta json_t *command = json_object_get (request, "command");
4342050d074SAman Gupta if (! command)
4352050d074SAman Gupta {
4362050d074SAman Gupta error (FATAL, "command name not found");
4372050d074SAman Gupta goto next;
4382050d074SAman Gupta }
4392050d074SAman Gupta
4402050d074SAman Gupta if (!strcmp ("generate-tags", json_string_value (command)))
4412050d074SAman Gupta {
4422050d074SAman Gupta json_int_t size = -1;
4432050d074SAman Gupta const char *filename;
4442050d074SAman Gupta
4452050d074SAman Gupta if (json_unpack (request, "{ss}", "filename", &filename) == -1)
4462050d074SAman Gupta {
4472050d074SAman Gupta error (FATAL, "invalid generate-tags request");
4482050d074SAman Gupta goto next;
4492050d074SAman Gupta }
4502050d074SAman Gupta
4512050d074SAman Gupta json_unpack (request, "{sI}", "size", &size);
4522050d074SAman Gupta
4532050d074SAman Gupta openTagFile ();
4542050d074SAman Gupta if (size == -1)
4552050d074SAman Gupta { /* read from disk */
4565ffd2fcfSMasatake YAMATO if (iargs->sandbox) {
4575ffd2fcfSMasatake YAMATO error (FATAL,
4585ffd2fcfSMasatake YAMATO "invalid request in sandbox submode: reading file contents from a file is limited");
459d22e13efSMasatake YAMATO closeTagFile (false);
4605ffd2fcfSMasatake YAMATO goto next;
4615ffd2fcfSMasatake YAMATO }
4623c130a08SMasatake YAMATO
4632050d074SAman Gupta createTagsForEntry (filename);
4642050d074SAman Gupta }
4652050d074SAman Gupta else
4662050d074SAman Gupta { /* read nbytes from stream */
4672050d074SAman Gupta unsigned char *data = eMalloc (size);
4682050d074SAman Gupta size = fread (data, 1, size, stdin);
469a055e2beSMasatake YAMATO MIO *mio = mio_new_memory (data, size, eRealloc, eFreeNoNullCheck);
470eda0f17cSMasatake YAMATO parseFileWithMio (filename, mio, NULL);
471b978efd6SMasatake YAMATO mio_unref (mio);
4722050d074SAman Gupta }
4732050d074SAman Gupta
4742050d074SAman Gupta closeTagFile (false);
4752050d074SAman Gupta fputs ("{\"_type\": \"completed\", \"command\": \"generate-tags\"}\n", stdout);
4762050d074SAman Gupta fflush(stdout);
4772050d074SAman Gupta }
4782050d074SAman Gupta else
4792050d074SAman Gupta {
4802050d074SAman Gupta error (FATAL, "unknown command name");
4812050d074SAman Gupta goto next;
4822050d074SAman Gupta }
4832050d074SAman Gupta
4842050d074SAman Gupta next:
4852050d074SAman Gupta json_decref (request);
4862050d074SAman Gupta }
4872050d074SAman Gupta }
4882050d074SAman Gupta #endif
4892050d074SAman Gupta
isSafeVar(const char * var)490ce990805SThomas Braun static bool isSafeVar (const char* var)
491e9bf9b8fSMasatake YAMATO {
492923fc1dcSMasatake YAMATO const char *safe_vars[] = {
493e9bf9b8fSMasatake YAMATO "BASH_FUNC_module()=",
494e9bf9b8fSMasatake YAMATO "BASH_FUNC_scl()=",
495e9bf9b8fSMasatake YAMATO NULL
496e9bf9b8fSMasatake YAMATO };
497923fc1dcSMasatake YAMATO const char *sv;
498e9bf9b8fSMasatake YAMATO
499e9bf9b8fSMasatake YAMATO for (sv = safe_vars[0]; sv != NULL; sv++)
500e9bf9b8fSMasatake YAMATO if (strncmp(var, sv, strlen (sv)) == 0)
501ce990805SThomas Braun return true;
502e9bf9b8fSMasatake YAMATO
503ce990805SThomas Braun return false;
504e9bf9b8fSMasatake YAMATO }
505e9bf9b8fSMasatake YAMATO
sanitizeEnviron(void)506d4c6f1e6SMasatake YAMATO static void sanitizeEnviron (void)
507d4c6f1e6SMasatake YAMATO {
50862c9a9aaSMasatake YAMATO char **e;
509d4c6f1e6SMasatake YAMATO int i;
510d4c6f1e6SMasatake YAMATO
511d4c6f1e6SMasatake YAMATO #if HAVE_DECL___ENVIRON
512d4c6f1e6SMasatake YAMATO e = __environ;
513d4c6f1e6SMasatake YAMATO #elif HAVE_DECL__NSGETENVIRON
514d4c6f1e6SMasatake YAMATO {
515d4c6f1e6SMasatake YAMATO char ***ep = _NSGetEnviron();
516d4c6f1e6SMasatake YAMATO if (ep)
517d4c6f1e6SMasatake YAMATO e = *ep;
5183c1c846cSMasatake YAMATO else
5193c1c846cSMasatake YAMATO e = NULL;
520d4c6f1e6SMasatake YAMATO }
52162c9a9aaSMasatake YAMATO #else
52262c9a9aaSMasatake YAMATO e = NULL;
523d4c6f1e6SMasatake YAMATO #endif
524d4c6f1e6SMasatake YAMATO
525d4c6f1e6SMasatake YAMATO if (!e)
526d4c6f1e6SMasatake YAMATO return;
527d4c6f1e6SMasatake YAMATO
528d4c6f1e6SMasatake YAMATO for (i = 0; e [i]; i++)
529d4c6f1e6SMasatake YAMATO {
530d4c6f1e6SMasatake YAMATO char *value;
531d4c6f1e6SMasatake YAMATO
532d4c6f1e6SMasatake YAMATO value = strchr (e [i], '=');
533d4c6f1e6SMasatake YAMATO if (!value)
534d4c6f1e6SMasatake YAMATO continue;
535d4c6f1e6SMasatake YAMATO
536d4c6f1e6SMasatake YAMATO value++;
537d4c6f1e6SMasatake YAMATO if (!strncmp (value, "() {", 4))
538d4c6f1e6SMasatake YAMATO {
539e9bf9b8fSMasatake YAMATO if (isSafeVar (e [i]))
540e9bf9b8fSMasatake YAMATO continue;
541d4c6f1e6SMasatake YAMATO error (WARNING, "reset environment: %s", e [i]);
542d4c6f1e6SMasatake YAMATO value [0] = '\0';
543d4c6f1e6SMasatake YAMATO }
544d4c6f1e6SMasatake YAMATO }
545d4c6f1e6SMasatake YAMATO }
546d4c6f1e6SMasatake YAMATO
547d4c6f1e6SMasatake YAMATO /*
548d4c6f1e6SMasatake YAMATO * Start up code
549d4c6f1e6SMasatake YAMATO */
550d4c6f1e6SMasatake YAMATO
ctags_cli_main(int argc CTAGS_ATTR_UNUSED,char ** argv)5519670f3feSMasatake YAMATO extern int ctags_cli_main (int argc CTAGS_ATTR_UNUSED, char **argv)
552d4c6f1e6SMasatake YAMATO {
553d4c6f1e6SMasatake YAMATO cookedArgs *args;
554d4c6f1e6SMasatake YAMATO
555d75f1db8SK.Takata #if defined(WIN32) && defined(HAVE_MKSTEMP)
556d75f1db8SK.Takata /* MinGW-w64's mkstemp() uses rand() for generating temporary files. */
557d75f1db8SK.Takata srand ((unsigned int) clock ());
558d75f1db8SK.Takata #endif
559d75f1db8SK.Takata
560a09da8e0SMasatake YAMATO initDefaultTrashBox ();
561a09da8e0SMasatake YAMATO
56264f5cf22SMasatake YAMATO DEBUG_INIT();
563d33423e3SSzymon Tomasz Stefanek
564fc3ee6cbSMasatake YAMATO setErrorPrinter (stderrDefaultErrorPrinter, NULL);
565a0870c64SMasatake YAMATO setMainLoop (batchMakeTags, NULL);
566d7738cbeSMasatake YAMATO setTagWriter (WRITER_U_CTAGS, NULL);
567abd199feSMasatake YAMATO
568d4c6f1e6SMasatake YAMATO setCurrentDirectory ();
569d4c6f1e6SMasatake YAMATO setExecutableName (*argv++);
570d4c6f1e6SMasatake YAMATO sanitizeEnviron ();
571d4c6f1e6SMasatake YAMATO checkRegex ();
572f2af3ebdSMasatake YAMATO initFieldObjects ();
57306e8f520SMasatake YAMATO initXtagObjects ();
574d4c6f1e6SMasatake YAMATO
575d4c6f1e6SMasatake YAMATO args = cArgNewFromArgv (argv);
576d4c6f1e6SMasatake YAMATO previewFirstOption (args);
577d4c6f1e6SMasatake YAMATO initializeParsing ();
578acf4070dSReuben Thomas testEtagsInvocation ();
579d4c6f1e6SMasatake YAMATO initOptions ();
580965b7025SMasatake YAMATO initRegexOptscript ();
581df218e5bSMasatake YAMATO readOptionConfiguration ();
582d4c6f1e6SMasatake YAMATO verbose ("Reading initial options from command line\n");
583d4afb66eSMasatake YAMATO parseCmdlineOptions (args);
584d4c6f1e6SMasatake YAMATO checkOptions ();
585a0870c64SMasatake YAMATO
586a0870c64SMasatake YAMATO runMainLoop (args);
587d4c6f1e6SMasatake YAMATO
588d4c6f1e6SMasatake YAMATO /* Clean up.
589d4c6f1e6SMasatake YAMATO */
590d4c6f1e6SMasatake YAMATO cArgDelete (args);
591d4c6f1e6SMasatake YAMATO freeKeywordTable ();
592d4c6f1e6SMasatake YAMATO freeRoutineResources ();
5936b659a51SMasatake YAMATO freeInputFileResources ();
594d4c6f1e6SMasatake YAMATO freeTagFileResources ();
595d4c6f1e6SMasatake YAMATO freeOptionResources ();
596d4c6f1e6SMasatake YAMATO freeParserResources ();
597d4c6f1e6SMasatake YAMATO freeRegexResources ();
5982acdcfa1SYasuhiro Matsumoto #ifdef HAVE_ICONV
5992acdcfa1SYasuhiro Matsumoto freeEncodingResources ();
6002acdcfa1SYasuhiro Matsumoto #endif
601d4c6f1e6SMasatake YAMATO
602a09da8e0SMasatake YAMATO finiDefaultTrashBox();
603a09da8e0SMasatake YAMATO
604d4c6f1e6SMasatake YAMATO if (Option.printLanguage)
605ce990805SThomas Braun return (Option.printLanguage == true)? 0: 1;
606d4c6f1e6SMasatake YAMATO
607d4c6f1e6SMasatake YAMATO exit (0);
608d4c6f1e6SMasatake YAMATO return 0;
609d4c6f1e6SMasatake YAMATO }
610