xref: /Universal-ctags/main/main.c (revision eed4431b6359e8abcd517010da6a38608c456d19)
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