xref: /Universal-ctags/main/read.c (revision 9128cdba03f06a84dcbe056af23316712f0db1b7)
1d4c6f1e6SMasatake YAMATO /*
2d4c6f1e6SMasatake YAMATO *   Copyright (c) 1996-2002, Darren Hiebert
3d4c6f1e6SMasatake YAMATO *
4d4c6f1e6SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
6d4c6f1e6SMasatake YAMATO *
7d316cd59SMasatake YAMATO *   This module contains low level input and tag file read functions (newline
8d316cd59SMasatake YAMATO *   conversion for input files are performed at this level).
9d4c6f1e6SMasatake YAMATO */
10d4c6f1e6SMasatake YAMATO 
11d4c6f1e6SMasatake YAMATO /*
12d4c6f1e6SMasatake YAMATO *   INCLUDE FILES
13d4c6f1e6SMasatake YAMATO */
14d4c6f1e6SMasatake YAMATO #include "general.h"  /* must always come first */
15d4c6f1e6SMasatake YAMATO 
16d4c6f1e6SMasatake YAMATO #include <string.h>
17d4c6f1e6SMasatake YAMATO #include <ctype.h>
18c434aea4SMasatake YAMATO #include <stdlib.h>
19d4c6f1e6SMasatake YAMATO 
20d4c6f1e6SMasatake YAMATO #define FILE_WRITE
21d4c6f1e6SMasatake YAMATO #include "read.h"
22b5df137eSMasatake YAMATO #include "read_p.h"
23d4c6f1e6SMasatake YAMATO #include "debug.h"
248cbf052bSMasatake YAMATO #include "entry_p.h"
25d4c6f1e6SMasatake YAMATO #include "routines.h"
2629e40fb6SMasatake YAMATO #include "routines_p.h"
2721996d92SMasatake YAMATO #include "options_p.h"
280d502ef0SMasatake YAMATO #include "parse_p.h"
29e3416868SMasatake YAMATO #include "promise_p.h"
30df2449f1SMasatake YAMATO #include "stats_p.h"
31a219c98cSMasatake YAMATO #include "trace.h"
3256065e52SMasatake YAMATO #include "trashbox.h"
332acdcfa1SYasuhiro Matsumoto #ifdef HAVE_ICONV
342acdcfa1SYasuhiro Matsumoto # include "mbcs.h"
35f38d6693SMasatake YAMATO # include "mbcs_p.h"
362acdcfa1SYasuhiro Matsumoto #endif
37d4c6f1e6SMasatake YAMATO 
38d4c6f1e6SMasatake YAMATO /*
39e54558c7SMasatake YAMATO *   DATA DECLARATIONS
40e54558c7SMasatake YAMATO */
41e54558c7SMasatake YAMATO 
42a8778562SMasatake YAMATO typedef struct sLangStack {
43a8778562SMasatake YAMATO 	langType *languages;
44a8778562SMasatake YAMATO 	unsigned int count;
45a8778562SMasatake YAMATO 	unsigned int size;
46a8778562SMasatake YAMATO } langStack;
47a8778562SMasatake YAMATO 
48e54558c7SMasatake YAMATO /*  Maintains the state of the current input file.
49e54558c7SMasatake YAMATO  */
50a8778562SMasatake YAMATO typedef union sInputLangInfo {
51a8778562SMasatake YAMATO 	langStack stack;
52a8778562SMasatake YAMATO 	langType  type;
53a8778562SMasatake YAMATO } inputLangInfo;
54a8778562SMasatake YAMATO 
55e54558c7SMasatake YAMATO typedef struct sInputFileInfo {
56e54558c7SMasatake YAMATO 	vString *name;           /* name to report for input file */
57e54558c7SMasatake YAMATO 	vString *tagPath;        /* path of input file relative to tag file */
58e54558c7SMasatake YAMATO 	unsigned long lineNumber;/* line number in the input file */
59aed2b6adSMasatake YAMATO 	unsigned long lineNumberOrigin; /* The value set to `lineNumber'
60aed2b6adSMasatake YAMATO 					   when `resetInputFile' is called
61aed2b6adSMasatake YAMATO 					   on the input stream.
62aed2b6adSMasatake YAMATO 					   This is needed for nested stream. */
63ce990805SThomas Braun 	bool isHeader;           /* is input file a header file? */
64e54558c7SMasatake YAMATO } inputFileInfo;
65e54558c7SMasatake YAMATO 
66c434aea4SMasatake YAMATO typedef struct sComputPos {
67c434aea4SMasatake YAMATO 	MIOPos  pos;
68c434aea4SMasatake YAMATO 	long    offset;
69c434aea4SMasatake YAMATO 	bool open;
703b035e33SMasatake YAMATO 	int crAdjustment;
71c434aea4SMasatake YAMATO } compoundPos;
72c434aea4SMasatake YAMATO 
73e54558c7SMasatake YAMATO typedef struct sInputLineFposMap {
74c434aea4SMasatake YAMATO 	compoundPos *pos;
75e54558c7SMasatake YAMATO 	unsigned int count;
76e54558c7SMasatake YAMATO 	unsigned int size;
77e54558c7SMasatake YAMATO } inputLineFposMap;
78e54558c7SMasatake YAMATO 
79a0c1e6d7SMasatake YAMATO typedef struct sNestedInputStreamInfo {
80a0c1e6d7SMasatake YAMATO 	unsigned long startLine;
81ef722b09SMasatake YAMATO 	long startCharOffset;
82a0c1e6d7SMasatake YAMATO 	unsigned long endLine;
83ef722b09SMasatake YAMATO 	long endCharOffset;
84a0c1e6d7SMasatake YAMATO } nestedInputStreamInfo;
85a0c1e6d7SMasatake YAMATO 
86e54558c7SMasatake YAMATO typedef struct sInputFile {
87e54558c7SMasatake YAMATO 	vString    *path;          /* path of input file (if any) */
88e54558c7SMasatake YAMATO 	vString    *line;          /* last line read from file */
89e54558c7SMasatake YAMATO 	const unsigned char* currentLine;  /* current line being worked on */
90203c6955SJiří Techet 	MIO        *mio;           /* MIO stream used for reading the file */
91c434aea4SMasatake YAMATO 	compoundPos    filePosition;  /* file position of current line */
92e54558c7SMasatake YAMATO 	unsigned int ungetchIdx;
934d985ad2SColomban Wendling 	int         ungetchBuf[8]; /* characters that were ungotten */
94e54558c7SMasatake YAMATO 
957d6be565SMasatake YAMATO 	bool bomFound;
96e54558c7SMasatake YAMATO 	/*  Contains data pertaining to the original `source' file in which the tag
97e54558c7SMasatake YAMATO 	 *  was defined. This may be different from the `input' file when #line
98e54558c7SMasatake YAMATO 	 *  directives are processed (i.e. the input file is preprocessor output).
99e54558c7SMasatake YAMATO 	 */
100e54558c7SMasatake YAMATO 	inputFileInfo input; /* name, lineNumber */
101e54558c7SMasatake YAMATO 	inputFileInfo source;
102e54558c7SMasatake YAMATO 
103a0c1e6d7SMasatake YAMATO 	nestedInputStreamInfo nestedInputStreamInfo;
104a0c1e6d7SMasatake YAMATO 
105e54558c7SMasatake YAMATO 	/* sourceTagPathHolder is a kind of trash box.
106e54558c7SMasatake YAMATO 	   The buffer pointed by tagPath field of source field can
107e54558c7SMasatake YAMATO 	   be referred from tagsEntryInfo instances. sourceTagPathHolder
108e54558c7SMasatake YAMATO 	   is used keeping the buffer till all processing about the current
109e54558c7SMasatake YAMATO 	   input file is done. After all processing is done, the buffers
110759d281dSK.Takata 	   in sourceTagPathHolder are destroyed. */
111e54558c7SMasatake YAMATO 	stringList  * sourceTagPathHolder;
112e54558c7SMasatake YAMATO 	inputLineFposMap lineFposMap;
1134e0c6ed6SMasatake YAMATO 	vString *allLines;
1142fa69c1bSMasatake YAMATO 	int thinDepth;
115c314f261SMasatake YAMATO 	time_t mtime;
116e54558c7SMasatake YAMATO } inputFile;
117e54558c7SMasatake YAMATO 
1187262d5eaSMasatake YAMATO static inputLangInfo inputLang;
1197262d5eaSMasatake YAMATO static langType sourceLang;
120e54558c7SMasatake YAMATO 
121e54558c7SMasatake YAMATO /*
122a8778562SMasatake YAMATO *   FUNCTION DECLARATIONS
123a8778562SMasatake YAMATO */
124a8778562SMasatake YAMATO static void     langStackInit (langStack *langStack);
125a8778562SMasatake YAMATO static langType langStackTop  (langStack *langStack);
126657cbb19SMasatake YAMATO static langType langStackBotom(langStack *langStack);
127a8778562SMasatake YAMATO static void     langStackPush (langStack *langStack, langType type);
128a8778562SMasatake YAMATO static langType langStackPop  (langStack *langStack);
12979758c23SMasatake YAMATO static void     langStackClear(langStack *langStack);
130a8778562SMasatake YAMATO 
131a8778562SMasatake YAMATO 
132a8778562SMasatake YAMATO /*
133d4c6f1e6SMasatake YAMATO *   DATA DEFINITIONS
134d4c6f1e6SMasatake YAMATO */
135d41a27faSMasatake YAMATO static inputFile File;  /* static read through functions */
1364fa68e36SMasatake YAMATO static inputFile BackupFile;	/* File is copied here when a nested parser is pushed */
137c434aea4SMasatake YAMATO static compoundPos StartOfLine;  /* holds deferred position of start of line */
138d4c6f1e6SMasatake YAMATO 
139d4c6f1e6SMasatake YAMATO /*
140d4c6f1e6SMasatake YAMATO *   FUNCTION DEFINITIONS
141d4c6f1e6SMasatake YAMATO */
142d4c6f1e6SMasatake YAMATO 
getInputLineNumber(void)143c7adb37bSMasatake YAMATO extern unsigned long getInputLineNumber (void)
144c7adb37bSMasatake YAMATO {
145c7adb37bSMasatake YAMATO 	return File.input.lineNumber;
146c7adb37bSMasatake YAMATO }
147c7adb37bSMasatake YAMATO 
getInputLineOffset(void)148f2d8a3d9SJiří Techet extern int getInputLineOffset (void)
149f2d8a3d9SJiří Techet {
150f2d8a3d9SJiří Techet 	unsigned char *base = (unsigned char *) vStringValue (File.line);
1512734995fSMasatake YAMATO 	int ret;
1522734995fSMasatake YAMATO 
1532734995fSMasatake YAMATO 	if (File.currentLine)
1542734995fSMasatake YAMATO 		ret = File.currentLine - base - File.ungetchIdx;
1552734995fSMasatake YAMATO 	else if (File.input.lineNumber)
1562734995fSMasatake YAMATO 	{
1572734995fSMasatake YAMATO 		/* When EOF is saw, currentLine is set to NULL.
1582734995fSMasatake YAMATO 		 * So the way to calculate the offset at the end of file is tricky.
1592734995fSMasatake YAMATO 		 */
1602734995fSMasatake YAMATO 		ret = (mio_tell (File.mio) - (File.bomFound? 3: 0))
1612734995fSMasatake YAMATO 			- getInputFileOffsetForLine(File.input.lineNumber);
1622734995fSMasatake YAMATO 	}
1632734995fSMasatake YAMATO 	else
1642734995fSMasatake YAMATO 	{
1652734995fSMasatake YAMATO 		/* At the first line of file. */
1662734995fSMasatake YAMATO 		ret = mio_tell (File.mio) - (File.bomFound? 3: 0);
1672734995fSMasatake YAMATO 	}
1682734995fSMasatake YAMATO 
169f2d8a3d9SJiří Techet 	return ret >= 0 ? ret : 0;
170f2d8a3d9SJiří Techet }
171f2d8a3d9SJiří Techet 
getInputFileName(void)172c7adb37bSMasatake YAMATO extern const char *getInputFileName (void)
173c7adb37bSMasatake YAMATO {
17454c2e083SMasatake YAMATO 	if (!File.input.name)
17554c2e083SMasatake YAMATO 		return NULL;
176c7adb37bSMasatake YAMATO 	return vStringValue (File.input.name);
177c7adb37bSMasatake YAMATO }
178c7adb37bSMasatake YAMATO 
getInputFilePosition(void)179c7adb37bSMasatake YAMATO extern MIOPos getInputFilePosition (void)
180c7adb37bSMasatake YAMATO {
181c434aea4SMasatake YAMATO 	return File.filePosition.pos;
182c7adb37bSMasatake YAMATO }
183c7adb37bSMasatake YAMATO 
getInputFileCompoundPosForLine(unsigned int line)1844d3d645dSMasatake YAMATO static compoundPos* getInputFileCompoundPosForLine (unsigned int line)
185c7adb37bSMasatake YAMATO {
186b21b2454SMasatake YAMATO 	int index;
187b21b2454SMasatake YAMATO 	if (line > 0)
188b21b2454SMasatake YAMATO 	{
189b21b2454SMasatake YAMATO 		if (File.lineFposMap.count > (line - 1))
190b21b2454SMasatake YAMATO 			index = line - 1;
191b21b2454SMasatake YAMATO 		else if (File.lineFposMap.count != 0)
192b21b2454SMasatake YAMATO 			index = File.lineFposMap.count - 1;
193b21b2454SMasatake YAMATO 		else
194b21b2454SMasatake YAMATO 			index = 0;
195b21b2454SMasatake YAMATO 	}
196b21b2454SMasatake YAMATO 	else
197b21b2454SMasatake YAMATO 		index = 0;
198b21b2454SMasatake YAMATO 
1994d3d645dSMasatake YAMATO 	return File.lineFposMap.pos + index;
2004d3d645dSMasatake YAMATO }
2014d3d645dSMasatake YAMATO 
getInputFilePositionForLine(unsigned int line)2024d3d645dSMasatake YAMATO extern MIOPos getInputFilePositionForLine (unsigned int line)
2034d3d645dSMasatake YAMATO {
2044d3d645dSMasatake YAMATO 	compoundPos *cpos = getInputFileCompoundPosForLine (line);
2054d3d645dSMasatake YAMATO 	return cpos->pos;
2064d3d645dSMasatake YAMATO }
2074d3d645dSMasatake YAMATO 
getInputFileOffsetForLine(unsigned int line)2084d3d645dSMasatake YAMATO extern long getInputFileOffsetForLine (unsigned int line)
2094d3d645dSMasatake YAMATO {
2104d3d645dSMasatake YAMATO 	compoundPos *cpos = getInputFileCompoundPosForLine (line);
21129f3d603SMasatake YAMATO 	return cpos->offset - (File.bomFound? 3: 0);
212c7adb37bSMasatake YAMATO }
213c7adb37bSMasatake YAMATO 
getInputLanguage(void)214c7adb37bSMasatake YAMATO extern langType getInputLanguage (void)
215c7adb37bSMasatake YAMATO {
216ebc3af7dSMasatake YAMATO 	return langStackTop (&inputLang.stack);
217c7adb37bSMasatake YAMATO }
218c7adb37bSMasatake YAMATO 
getInputLanguageName(void)219c7adb37bSMasatake YAMATO extern const char *getInputLanguageName (void)
220c7adb37bSMasatake YAMATO {
221a8778562SMasatake YAMATO 	return getLanguageName (getInputLanguage());
222c7adb37bSMasatake YAMATO }
223c7adb37bSMasatake YAMATO 
getInputFileTagPath(void)224c7adb37bSMasatake YAMATO extern const char *getInputFileTagPath (void)
225c7adb37bSMasatake YAMATO {
226c7adb37bSMasatake YAMATO 	return vStringValue (File.input.tagPath);
227c7adb37bSMasatake YAMATO }
228c7adb37bSMasatake YAMATO 
isInputLanguage(langType lang)229ce990805SThomas Braun extern bool isInputLanguage (langType lang)
230c7adb37bSMasatake YAMATO {
231ce990805SThomas Braun 	return (bool)((lang) == getInputLanguage ());
232c7adb37bSMasatake YAMATO }
233c7adb37bSMasatake YAMATO 
isInputHeaderFile(void)234ce990805SThomas Braun extern bool isInputHeaderFile (void)
235c7adb37bSMasatake YAMATO {
236c7adb37bSMasatake YAMATO 	return File.input.isHeader;
237c7adb37bSMasatake YAMATO }
238c7adb37bSMasatake YAMATO 
isInputLanguageKindEnabled(int kindIndex)2395c56d939SMasatake YAMATO extern bool isInputLanguageKindEnabled (int kindIndex)
240c7adb37bSMasatake YAMATO {
2415c56d939SMasatake YAMATO 	return isLanguageKindEnabled (getInputLanguage (), kindIndex);
242c7adb37bSMasatake YAMATO }
243c7adb37bSMasatake YAMATO 
isInputLanguageRoleEnabled(int kindIndex,int roleIndex)244320b1e8bSMasatake YAMATO extern bool isInputLanguageRoleEnabled (int kindIndex, int roleIndex)
245320b1e8bSMasatake YAMATO {
246320b1e8bSMasatake YAMATO 	return isLanguageRoleEnabled (getInputLanguage (),
247320b1e8bSMasatake YAMATO 								  kindIndex, roleIndex);
248320b1e8bSMasatake YAMATO }
249320b1e8bSMasatake YAMATO 
countInputLanguageKinds(void)2500f23950dSMasatake YAMATO extern unsigned int countInputLanguageKinds (void)
2510f23950dSMasatake YAMATO {
2520f23950dSMasatake YAMATO 	return countLanguageKinds (getInputLanguage ());
2530f23950dSMasatake YAMATO }
2540f23950dSMasatake YAMATO 
countInputLanguageRoles(int kindIndex)2550f23950dSMasatake YAMATO extern unsigned int countInputLanguageRoles (int kindIndex)
2560f23950dSMasatake YAMATO {
2570f23950dSMasatake YAMATO 	return countLanguageRoles (getInputLanguage (), kindIndex);
2580f23950dSMasatake YAMATO }
2590f23950dSMasatake YAMATO 
doesInputLanguageAllowNullTag(void)260ce990805SThomas Braun extern bool doesInputLanguageAllowNullTag (void)
261c7adb37bSMasatake YAMATO {
262a8778562SMasatake YAMATO 	return doesLanguageAllowNullTag (getInputLanguage ());
263c7adb37bSMasatake YAMATO }
264c7adb37bSMasatake YAMATO 
doesInputLanguageRequestAutomaticFQTag(const tagEntryInfo * e)2656f0c51d8SMasatake YAMATO extern bool doesInputLanguageRequestAutomaticFQTag (const tagEntryInfo *e)
266c7adb37bSMasatake YAMATO {
2676f0c51d8SMasatake YAMATO 	return doesLanguageRequestAutomaticFQTag (e->langType);
268c7adb37bSMasatake YAMATO }
269c7adb37bSMasatake YAMATO 
getSourceFileTagPath(void)270c7adb37bSMasatake YAMATO extern const char *getSourceFileTagPath (void)
271c7adb37bSMasatake YAMATO {
272c7adb37bSMasatake YAMATO 	return vStringValue (File.source.tagPath);
273c7adb37bSMasatake YAMATO }
274c7adb37bSMasatake YAMATO 
getSourceLanguage(void)2755bd00ccbSMasatake YAMATO extern langType getSourceLanguage (void)
276c7adb37bSMasatake YAMATO {
2777262d5eaSMasatake YAMATO 	return sourceLang;
278c7adb37bSMasatake YAMATO }
279c7adb37bSMasatake YAMATO 
getSourceLineNumber(void)280c7adb37bSMasatake YAMATO extern unsigned long getSourceLineNumber (void)
281c7adb37bSMasatake YAMATO {
282c7adb37bSMasatake YAMATO 	return File.source.lineNumber;
283c7adb37bSMasatake YAMATO }
284c7adb37bSMasatake YAMATO 
freeInputFileInfo(inputFileInfo * finfo)285a5b1fa4aSMasatake YAMATO static void freeInputFileInfo (inputFileInfo *finfo)
286a5b1fa4aSMasatake YAMATO {
287a5b1fa4aSMasatake YAMATO 	if (finfo->name)
288a5b1fa4aSMasatake YAMATO 	{
289a5b1fa4aSMasatake YAMATO 		vStringDelete (finfo->name);
290a5b1fa4aSMasatake YAMATO 		finfo->name = NULL;
291a5b1fa4aSMasatake YAMATO 	}
292a5b1fa4aSMasatake YAMATO 	if (finfo->tagPath)
293a5b1fa4aSMasatake YAMATO 	{
29454d7e089SMasatake YAMATO 		vStringDelete (finfo->tagPath);
295a5b1fa4aSMasatake YAMATO 		finfo->tagPath = NULL;
296a5b1fa4aSMasatake YAMATO 	}
297a5b1fa4aSMasatake YAMATO }
298a5b1fa4aSMasatake YAMATO 
freeInputFileResources(void)2996b659a51SMasatake YAMATO extern void freeInputFileResources (void)
300d4c6f1e6SMasatake YAMATO {
301d4c6f1e6SMasatake YAMATO 	if (File.path != NULL)
302d4c6f1e6SMasatake YAMATO 		vStringDelete (File.path);
303d4c6f1e6SMasatake YAMATO 	if (File.line != NULL)
304d4c6f1e6SMasatake YAMATO 		vStringDelete (File.line);
305a5b1fa4aSMasatake YAMATO 	freeInputFileInfo (&File.input);
306a5b1fa4aSMasatake YAMATO 	freeInputFileInfo (&File.source);
307d4c6f1e6SMasatake YAMATO }
308d4c6f1e6SMasatake YAMATO 
getInputFileData(size_t * size)309c0732dcaSMasatake YAMATO extern const unsigned char *getInputFileData (size_t *size)
31031cb4225SMasatake YAMATO {
311203c6955SJiří Techet 	return mio_memory_get_data (File.mio, size);
31231cb4225SMasatake YAMATO }
31331cb4225SMasatake YAMATO 
314d4c6f1e6SMasatake YAMATO /*
31501ceddeaSMasatake YAMATO  * inputLineFposMap related functions
31601ceddeaSMasatake YAMATO  */
freeLineFposMap(inputLineFposMap * lineFposMap)31701ceddeaSMasatake YAMATO static void freeLineFposMap (inputLineFposMap *lineFposMap)
31801ceddeaSMasatake YAMATO {
31901ceddeaSMasatake YAMATO 	if (lineFposMap->pos)
32001ceddeaSMasatake YAMATO 	{
321a32a50f1SMasatake YAMATO 		eFree (lineFposMap->pos);
32201ceddeaSMasatake YAMATO 		lineFposMap->pos = NULL;
32301ceddeaSMasatake YAMATO 		lineFposMap->count = 0;
32401ceddeaSMasatake YAMATO 		lineFposMap->size = 0;
32501ceddeaSMasatake YAMATO 	}
32601ceddeaSMasatake YAMATO }
32701ceddeaSMasatake YAMATO 
allocLineFposMap(inputLineFposMap * lineFposMap)32801ceddeaSMasatake YAMATO static void allocLineFposMap (inputLineFposMap *lineFposMap)
32901ceddeaSMasatake YAMATO {
33001ceddeaSMasatake YAMATO #define INITIAL_lineFposMap_LEN 256
331c434aea4SMasatake YAMATO 	lineFposMap->pos = xCalloc (INITIAL_lineFposMap_LEN, compoundPos);
33201ceddeaSMasatake YAMATO 	lineFposMap->size = INITIAL_lineFposMap_LEN;
33301ceddeaSMasatake YAMATO 	lineFposMap->count = 0;
33401ceddeaSMasatake YAMATO }
33501ceddeaSMasatake YAMATO 
appendLineFposMap(inputLineFposMap * lineFposMap,compoundPos * pos,bool crAdjustment)3363b035e33SMasatake YAMATO static void appendLineFposMap (inputLineFposMap *lineFposMap, compoundPos *pos,
3373b035e33SMasatake YAMATO 							   bool crAdjustment)
33801ceddeaSMasatake YAMATO {
3393b035e33SMasatake YAMATO 	int lastCrAdjustment = 0;
3403b035e33SMasatake YAMATO 
34101ceddeaSMasatake YAMATO 	if (lineFposMap->size == lineFposMap->count)
34201ceddeaSMasatake YAMATO 	{
34301ceddeaSMasatake YAMATO 		lineFposMap->size *= 2;
34401ceddeaSMasatake YAMATO 		lineFposMap->pos = xRealloc (lineFposMap->pos,
34501ceddeaSMasatake YAMATO 					     lineFposMap->size,
346c434aea4SMasatake YAMATO 					     compoundPos);
34701ceddeaSMasatake YAMATO 	}
348c434aea4SMasatake YAMATO 
349c434aea4SMasatake YAMATO 	if (lineFposMap->count != 0)
3503b035e33SMasatake YAMATO 	{
351c434aea4SMasatake YAMATO 		lineFposMap->pos [lineFposMap->count - 1].open = false;
3523b035e33SMasatake YAMATO 		lastCrAdjustment = lineFposMap->pos [lineFposMap->count - 1].crAdjustment;
3533b035e33SMasatake YAMATO 	}
3543b035e33SMasatake YAMATO 
355c434aea4SMasatake YAMATO 	lineFposMap->pos [lineFposMap->count] = *pos;
356c434aea4SMasatake YAMATO 	lineFposMap->pos [lineFposMap->count].open = true;
3573b035e33SMasatake YAMATO 	lineFposMap->pos [lineFposMap->count].crAdjustment
3583b035e33SMasatake YAMATO 		= lastCrAdjustment + ((crAdjustment)? 1: 0);
35901ceddeaSMasatake YAMATO 	lineFposMap->count++;
36001ceddeaSMasatake YAMATO }
36101ceddeaSMasatake YAMATO 
compoundPosForOffset(const void * oft,const void * p)362c434aea4SMasatake YAMATO static int compoundPosForOffset (const void* oft, const void *p)
363c434aea4SMasatake YAMATO {
364c434aea4SMasatake YAMATO 	long offset = *(long *)oft;
365c434aea4SMasatake YAMATO 	const compoundPos *pos = p;
366c434aea4SMasatake YAMATO 	const compoundPos *next = (compoundPos *)(((char *)pos) + sizeof (compoundPos));
367c434aea4SMasatake YAMATO 
3683b035e33SMasatake YAMATO 	if (offset < (pos->offset - pos->crAdjustment))
369c434aea4SMasatake YAMATO 		return -1;
3703b035e33SMasatake YAMATO 	else if (((pos->offset - pos->crAdjustment) <= offset)
371c434aea4SMasatake YAMATO 		 && (pos->open
3723b035e33SMasatake YAMATO 		     || (offset < (next->offset - next->crAdjustment))))
373c434aea4SMasatake YAMATO 		return 0;
374c434aea4SMasatake YAMATO 	else
375c434aea4SMasatake YAMATO 		return 1;
376c434aea4SMasatake YAMATO }
377c434aea4SMasatake YAMATO 
getInputLineNumberForFileOffset(long offset)378c434aea4SMasatake YAMATO extern unsigned long getInputLineNumberForFileOffset(long offset)
379c434aea4SMasatake YAMATO {
380c434aea4SMasatake YAMATO 	compoundPos *p;
381c434aea4SMasatake YAMATO 
38229f3d603SMasatake YAMATO 	if (File.bomFound)
38329f3d603SMasatake YAMATO 		offset += 3;
38429f3d603SMasatake YAMATO 
385c434aea4SMasatake YAMATO 	p = bsearch (&offset, File.lineFposMap.pos, File.lineFposMap.count, sizeof (compoundPos),
386c434aea4SMasatake YAMATO 		     compoundPosForOffset);
387c434aea4SMasatake YAMATO 	if (p == NULL)
388c434aea4SMasatake YAMATO 		return 1;	/* TODO: 0? */
389c434aea4SMasatake YAMATO 	else
390c434aea4SMasatake YAMATO 		return 1 + (p - File.lineFposMap.pos);
391c434aea4SMasatake YAMATO }
392c434aea4SMasatake YAMATO 
39301ceddeaSMasatake YAMATO /*
394d316cd59SMasatake YAMATO  *   Input file access functions
395d4c6f1e6SMasatake YAMATO  */
396d4c6f1e6SMasatake YAMATO 
setOwnerDirectoryOfInputFile(const char * const fileName)397fd12e3afSMasatake YAMATO static void setOwnerDirectoryOfInputFile (const char *const fileName)
398d4c6f1e6SMasatake YAMATO {
399d4c6f1e6SMasatake YAMATO 	const char *const head = fileName;
400d4c6f1e6SMasatake YAMATO 	const char *const tail = baseFilename (head);
401d4c6f1e6SMasatake YAMATO 
402d4c6f1e6SMasatake YAMATO 	if (File.path != NULL)
403d4c6f1e6SMasatake YAMATO 		vStringDelete (File.path);
404d4c6f1e6SMasatake YAMATO 	if (tail == head)
405d4c6f1e6SMasatake YAMATO 		File.path = NULL;
406d4c6f1e6SMasatake YAMATO 	else
407d4c6f1e6SMasatake YAMATO 	{
408d4c6f1e6SMasatake YAMATO 		const size_t length = tail - head - 1;
409d4c6f1e6SMasatake YAMATO 		File.path = vStringNew ();
410d4c6f1e6SMasatake YAMATO 		vStringNCopyS (File.path, fileName, length);
411d4c6f1e6SMasatake YAMATO 	}
412d4c6f1e6SMasatake YAMATO }
413d4c6f1e6SMasatake YAMATO 
setInputFileParametersCommon(inputFileInfo * finfo,vString * const fileName,const langType language,stringList * holder)414adff34b1SMasatake YAMATO static void setInputFileParametersCommon (inputFileInfo *finfo, vString *const fileName,
415a8778562SMasatake YAMATO 					  const langType language,
416a8778562SMasatake YAMATO 					  stringList *holder)
417d4c6f1e6SMasatake YAMATO {
418fd12e3afSMasatake YAMATO 	if (finfo->name != NULL)
419fd12e3afSMasatake YAMATO 		vStringDelete (finfo->name);
420fd12e3afSMasatake YAMATO 	finfo->name = fileName;
421d4c6f1e6SMasatake YAMATO 
422fd12e3afSMasatake YAMATO 	if (finfo->tagPath != NULL)
423adff34b1SMasatake YAMATO 	{
424adff34b1SMasatake YAMATO 		if (holder)
425adff34b1SMasatake YAMATO 			stringListAdd (holder, finfo->tagPath);
426adff34b1SMasatake YAMATO 		else
42754d7e089SMasatake YAMATO 			vStringDelete (finfo->tagPath);
428adff34b1SMasatake YAMATO 	}
42978478818SMasatake YAMATO 
43078478818SMasatake YAMATO 	if (0)
43178478818SMasatake YAMATO 		;
43278478818SMasatake YAMATO 	else if (  Option.tagRelative == TREL_ALWAYS )
43378478818SMasatake YAMATO 		finfo->tagPath =
43478478818SMasatake YAMATO 			vStringNewOwn (relativeFilename (vStringValue (fileName),
43578478818SMasatake YAMATO 							 getTagFileDirectory ()));
43678478818SMasatake YAMATO 	else if ( Option.tagRelative == TREL_NEVER )
43778478818SMasatake YAMATO 		finfo->tagPath =
43878478818SMasatake YAMATO 			vStringNewOwn (absoluteFilename (vStringValue (fileName)));
43978478818SMasatake YAMATO 	else if ( Option.tagRelative == TREL_NO || isAbsolutePath (vStringValue (fileName)) )
44054d7e089SMasatake YAMATO 		finfo->tagPath = vStringNewCopy (fileName);
441d4c6f1e6SMasatake YAMATO 	else
442fd12e3afSMasatake YAMATO 		finfo->tagPath =
443c1f939f9SMasatake YAMATO 			vStringNewOwn (relativeFilename (vStringValue (fileName),
444c1f939f9SMasatake YAMATO 							 getTagFileDirectory ()));
445d4c6f1e6SMasatake YAMATO 
446fd12e3afSMasatake YAMATO 	finfo->isHeader = isIncludeFile (vStringValue (fileName));
447a8778562SMasatake YAMATO }
448a8778562SMasatake YAMATO 
resetLangOnStack(inputLangInfo * langInfo,langType lang)449a8778562SMasatake YAMATO static void resetLangOnStack (inputLangInfo *langInfo, langType lang)
450a8778562SMasatake YAMATO {
45179758c23SMasatake YAMATO 	Assert (langInfo->stack.count > 0);
45279758c23SMasatake YAMATO 	langStackClear  (& (langInfo->stack));
453a8778562SMasatake YAMATO 	langStackPush (& (langInfo->stack), lang);
454a8778562SMasatake YAMATO }
455a8778562SMasatake YAMATO 
baseLangOnStack(inputLangInfo * langInfo)456657cbb19SMasatake YAMATO extern langType baseLangOnStack (inputLangInfo *langInfo)
457657cbb19SMasatake YAMATO {
458657cbb19SMasatake YAMATO 	Assert (langInfo->stack.count > 0);
459657cbb19SMasatake YAMATO 	return langStackBotom (& (langInfo->stack));
460657cbb19SMasatake YAMATO }
461657cbb19SMasatake YAMATO 
pushLangOnStack(inputLangInfo * langInfo,langType lang)462a8778562SMasatake YAMATO static void pushLangOnStack (inputLangInfo *langInfo, langType lang)
463a8778562SMasatake YAMATO {
464a8778562SMasatake YAMATO 	langStackPush (& langInfo->stack, lang);
465a8778562SMasatake YAMATO }
466a8778562SMasatake YAMATO 
popLangOnStack(inputLangInfo * langInfo)467a8778562SMasatake YAMATO static langType popLangOnStack (inputLangInfo *langInfo)
468a8778562SMasatake YAMATO {
469a8778562SMasatake YAMATO 	return langStackPop (& langInfo->stack);
470a8778562SMasatake YAMATO }
471a8778562SMasatake YAMATO 
clearLangOnStack(inputLangInfo * langInfo)47279758c23SMasatake YAMATO static void clearLangOnStack (inputLangInfo *langInfo)
47379758c23SMasatake YAMATO {
4742b62e072SThomas Braun 	langStackClear (& langInfo->stack);
47579758c23SMasatake YAMATO }
47679758c23SMasatake YAMATO 
setInputFileParameters(vString * const fileName,const langType language)477fd12e3afSMasatake YAMATO static void setInputFileParameters (vString *const fileName, const langType language)
478fd12e3afSMasatake YAMATO {
479a8778562SMasatake YAMATO 	setInputFileParametersCommon (&File.input, fileName,
480ebc3af7dSMasatake YAMATO 				      language, NULL);
481ebc3af7dSMasatake YAMATO 	pushLangOnStack(&inputLang, language);
482fd12e3afSMasatake YAMATO }
483fd12e3afSMasatake YAMATO 
setSourceFileParameters(vString * const fileName,const langType language)484fd12e3afSMasatake YAMATO static void setSourceFileParameters (vString *const fileName, const langType language)
485fd12e3afSMasatake YAMATO {
486a8778562SMasatake YAMATO 	setInputFileParametersCommon (&File.source, fileName,
487ebc3af7dSMasatake YAMATO 				      language, File.sourceTagPathHolder);
4887262d5eaSMasatake YAMATO 	sourceLang = language;
489d4c6f1e6SMasatake YAMATO }
490d4c6f1e6SMasatake YAMATO 
setSourceFileName(vString * const fileName)491ce990805SThomas Braun static bool setSourceFileName (vString *const fileName)
492d4c6f1e6SMasatake YAMATO {
4935329ae51SMasatake YAMATO 	const langType language = getLanguageForFilenameAndContents (vStringValue (fileName));
494ce990805SThomas Braun 	bool result = false;
495d4c6f1e6SMasatake YAMATO 	if (language != LANG_IGNORE)
496d4c6f1e6SMasatake YAMATO 	{
497d4c6f1e6SMasatake YAMATO 		vString *pathName;
498d4c6f1e6SMasatake YAMATO 		if (isAbsolutePath (vStringValue (fileName)) || File.path == NULL)
499d4c6f1e6SMasatake YAMATO 			pathName = vStringNewCopy (fileName);
500d4c6f1e6SMasatake YAMATO 		else
501d4c6f1e6SMasatake YAMATO 		{
502d4c6f1e6SMasatake YAMATO 			char *tmp = combinePathAndFile (
503d4c6f1e6SMasatake YAMATO 				vStringValue (File.path), vStringValue (fileName));
504d4c6f1e6SMasatake YAMATO 			pathName = vStringNewOwn (tmp);
505d4c6f1e6SMasatake YAMATO 		}
506d4c6f1e6SMasatake YAMATO 		setSourceFileParameters (pathName, language);
507ce990805SThomas Braun 		result = true;
508d4c6f1e6SMasatake YAMATO 	}
509d4c6f1e6SMasatake YAMATO 	return result;
510d4c6f1e6SMasatake YAMATO }
511d4c6f1e6SMasatake YAMATO 
512d4c6f1e6SMasatake YAMATO /*
513d4c6f1e6SMasatake YAMATO  *   Line directive parsing
514d4c6f1e6SMasatake YAMATO  */
515d4c6f1e6SMasatake YAMATO 
skipWhite(char ** str)5165388d8eaSJiří Techet static void skipWhite (char **str)
517d4c6f1e6SMasatake YAMATO {
5185388d8eaSJiří Techet 	while (**str == ' '  ||  **str == '\t')
5195388d8eaSJiří Techet 		(*str)++;
520d4c6f1e6SMasatake YAMATO }
521d4c6f1e6SMasatake YAMATO 
readLineNumber(char ** str)5225388d8eaSJiří Techet static unsigned long readLineNumber (char **str)
523d4c6f1e6SMasatake YAMATO {
5245388d8eaSJiří Techet 	char *s;
525d4c6f1e6SMasatake YAMATO 	unsigned long lNum = 0;
5265388d8eaSJiří Techet 
5275388d8eaSJiří Techet 	skipWhite (str);
5285388d8eaSJiří Techet 	s = *str;
5295388d8eaSJiří Techet 	while (*s != '\0' && isdigit (*s))
530d4c6f1e6SMasatake YAMATO 	{
5315388d8eaSJiří Techet 		lNum = (lNum * 10) + (*s - '0');
5325388d8eaSJiří Techet 		s++;
533d4c6f1e6SMasatake YAMATO 	}
5345388d8eaSJiří Techet 	if (*s != ' ' && *s != '\t')
535d4c6f1e6SMasatake YAMATO 		lNum = 0;
5365388d8eaSJiří Techet 	*str = s;
537d4c6f1e6SMasatake YAMATO 
538d4c6f1e6SMasatake YAMATO 	return lNum;
539d4c6f1e6SMasatake YAMATO }
540d4c6f1e6SMasatake YAMATO 
541d4c6f1e6SMasatake YAMATO /* While ANSI only permits lines of the form:
542d4c6f1e6SMasatake YAMATO  *   # line n "filename"
543d4c6f1e6SMasatake YAMATO  * Earlier compilers generated lines of the form
544d4c6f1e6SMasatake YAMATO  *   # n filename
545d4c6f1e6SMasatake YAMATO  * GNU C will output lines of the form:
546d4c6f1e6SMasatake YAMATO  *   # n "filename"
547d4c6f1e6SMasatake YAMATO  * So we need to be fairly flexible in what we accept.
548d4c6f1e6SMasatake YAMATO  */
readFileName(char * s)5495388d8eaSJiří Techet static vString *readFileName (char *s)
550d4c6f1e6SMasatake YAMATO {
551d4c6f1e6SMasatake YAMATO 	vString *const fileName = vStringNew ();
552ce990805SThomas Braun 	bool quoteDelimited = false;
553d4c6f1e6SMasatake YAMATO 
5545388d8eaSJiří Techet 	skipWhite (&s);
5555388d8eaSJiří Techet 	if (*s == '"')
556d4c6f1e6SMasatake YAMATO 	{
5575388d8eaSJiří Techet 		s++;  /* skip double-quote */
558ce990805SThomas Braun 		quoteDelimited = true;
559d4c6f1e6SMasatake YAMATO 	}
5605388d8eaSJiří Techet 	while (*s != '\0'  &&  *s != '\n'  &&
5615388d8eaSJiří Techet 			(quoteDelimited ? (*s != '"') : (*s != ' '  &&  *s != '\t')))
562d4c6f1e6SMasatake YAMATO 	{
5635388d8eaSJiří Techet 		vStringPut (fileName, *s);
5645388d8eaSJiří Techet 		s++;
565d4c6f1e6SMasatake YAMATO 	}
566d4c6f1e6SMasatake YAMATO 	vStringPut (fileName, '\0');
567d4c6f1e6SMasatake YAMATO 
568d4c6f1e6SMasatake YAMATO 	return fileName;
569d4c6f1e6SMasatake YAMATO }
570d4c6f1e6SMasatake YAMATO 
parseLineDirective(char * s)5715388d8eaSJiří Techet static bool parseLineDirective (char *s)
572d4c6f1e6SMasatake YAMATO {
573ce990805SThomas Braun 	bool result = false;
5745388d8eaSJiří Techet 
5755388d8eaSJiří Techet 	skipWhite (&s);
576d4c6f1e6SMasatake YAMATO 	DebugStatement ( const char* lineStr = ""; )
577d4c6f1e6SMasatake YAMATO 
5785388d8eaSJiří Techet 	if (isdigit (*s))
579ce990805SThomas Braun 		result = true;
5805388d8eaSJiří Techet 	else if (strncmp (s, "line", 4) == 0)
581d4c6f1e6SMasatake YAMATO 	{
5825388d8eaSJiří Techet 		s += 4;
5835388d8eaSJiří Techet 		if (*s == ' '  ||  *s == '\t')
584d4c6f1e6SMasatake YAMATO 		{
585d4c6f1e6SMasatake YAMATO 			DebugStatement ( lineStr = "line"; )
586ce990805SThomas Braun 			result = true;
587d4c6f1e6SMasatake YAMATO 		}
588d4c6f1e6SMasatake YAMATO 	}
589d4c6f1e6SMasatake YAMATO 	if (result)
590d4c6f1e6SMasatake YAMATO 	{
5915388d8eaSJiří Techet 		const unsigned long lNum = readLineNumber (&s);
592d4c6f1e6SMasatake YAMATO 		if (lNum == 0)
593ce990805SThomas Braun 			result = false;
594d4c6f1e6SMasatake YAMATO 		else
595d4c6f1e6SMasatake YAMATO 		{
5965388d8eaSJiří Techet 			vString *const fileName = readFileName (s);
597d4c6f1e6SMasatake YAMATO 			if (vStringLength (fileName) == 0)
598d4c6f1e6SMasatake YAMATO 			{
599d4c6f1e6SMasatake YAMATO 				File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
600d4c6f1e6SMasatake YAMATO 				DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld", lineStr, lNum); )
601d4c6f1e6SMasatake YAMATO 			}
602d4c6f1e6SMasatake YAMATO 			else if (setSourceFileName (fileName))
603d4c6f1e6SMasatake YAMATO 			{
604d4c6f1e6SMasatake YAMATO 				File.source.lineNumber = lNum - 1;  /* applies to NEXT line */
605d4c6f1e6SMasatake YAMATO 				DebugStatement ( debugPrintf (DEBUG_RAW, "#%s %ld \"%s\"",
606d4c6f1e6SMasatake YAMATO 								lineStr, lNum, vStringValue (fileName)); )
607d4c6f1e6SMasatake YAMATO 			}
608d4c6f1e6SMasatake YAMATO 
60997e10dd0SMasatake YAMATO 			if (vStringLength (fileName) > 0 &&
610d4c6f1e6SMasatake YAMATO 				lNum == 1)
61197e10dd0SMasatake YAMATO 				makeFileTag (vStringValue (fileName));
612d4c6f1e6SMasatake YAMATO 			vStringDelete (fileName);
613ce990805SThomas Braun 			result = true;
614d4c6f1e6SMasatake YAMATO 		}
615d4c6f1e6SMasatake YAMATO 	}
616d4c6f1e6SMasatake YAMATO 	return result;
617d4c6f1e6SMasatake YAMATO }
618d4c6f1e6SMasatake YAMATO 
619d4c6f1e6SMasatake YAMATO /*
620d316cd59SMasatake YAMATO  *   Input file I/O operations
621d4c6f1e6SMasatake YAMATO  */
6226b917ee2SMasatake YAMATO #ifdef DEBUG
6236b917ee2SMasatake YAMATO #define MAX_IN_MEMORY_FILE_SIZE 0
6246b917ee2SMasatake YAMATO #else
6259d5edacaSJiří Techet #define MAX_IN_MEMORY_FILE_SIZE (1024*1024)
6266b917ee2SMasatake YAMATO #endif
6279d5edacaSJiří Techet 
getMioFull(const char * const fileName,const char * const openMode,bool memStreamRequired,time_t * mtime)628c314f261SMasatake YAMATO static MIO *getMioFull (const char *const fileName, const char *const openMode,
629c314f261SMasatake YAMATO 		    bool memStreamRequired, time_t *mtime)
6309d5edacaSJiří Techet {
631c5e3c546SJiří Techet 	FILE *src;
632c5e3c546SJiří Techet 	fileStatus *st;
633c5e3c546SJiří Techet 	unsigned long size;
634c5e3c546SJiří Techet 	unsigned char *data;
6359d5edacaSJiří Techet 
636c5e3c546SJiří Techet 	st = eStat (fileName);
637c5e3c546SJiří Techet 	size = st->size;
638c314f261SMasatake YAMATO 	if (mtime)
639c314f261SMasatake YAMATO 		*mtime = st->mtime;
640c5e3c546SJiří Techet 	eStatFree (st);
64131cb4225SMasatake YAMATO 	if ((!memStreamRequired)
64231cb4225SMasatake YAMATO 	    && (size > MAX_IN_MEMORY_FILE_SIZE || size == 0))
643c5e3c546SJiří Techet 		return mio_new_file (fileName, openMode);
644c5e3c546SJiří Techet 
645c5e3c546SJiří Techet 	src = fopen (fileName, openMode);
646231e40e7SMasatake YAMATO 	if (!src)
647231e40e7SMasatake YAMATO 		return NULL;
648231e40e7SMasatake YAMATO 
649231e40e7SMasatake YAMATO 	data = eMalloc (size);
650c5e3c546SJiří Techet 	if (fread (data, 1, size, src) != size)
6519d5edacaSJiří Techet 	{
652c5e3c546SJiří Techet 		eFree (data);
653c5e3c546SJiří Techet 		fclose (src);
65431cb4225SMasatake YAMATO 		if (memStreamRequired)
65531cb4225SMasatake YAMATO 			return NULL;
65631cb4225SMasatake YAMATO 		else
657c5e3c546SJiří Techet 			return mio_new_file (fileName, openMode);
6589d5edacaSJiří Techet 	}
659c5e3c546SJiří Techet 	fclose (src);
660a055e2beSMasatake YAMATO 	return mio_new_memory (data, size, eRealloc, eFreeNoNullCheck);
6619d5edacaSJiří Techet }
6629d5edacaSJiří Techet 
getMio(const char * const fileName,const char * const openMode,bool memStreamRequired)663c314f261SMasatake YAMATO extern MIO *getMio (const char *const fileName, const char *const openMode,
664c314f261SMasatake YAMATO 		    bool memStreamRequired)
665c314f261SMasatake YAMATO {
666c314f261SMasatake YAMATO 	return getMioFull (fileName, openMode, memStreamRequired, NULL);
667c314f261SMasatake YAMATO }
668c314f261SMasatake YAMATO 
6697d6be565SMasatake YAMATO /* Return true if utf8 BOM is found */
checkUTF8BOM(MIO * mio,bool skipIfFound)6707d6be565SMasatake YAMATO static bool checkUTF8BOM (MIO *mio, bool skipIfFound)
6717d6be565SMasatake YAMATO {
6727d6be565SMasatake YAMATO 	bool r = false;
6737d6be565SMasatake YAMATO 	if ((0xEF == mio_getc (mio))
6747d6be565SMasatake YAMATO 		&& (0xBB == mio_getc (mio))
6757d6be565SMasatake YAMATO 		&& (0xBF == mio_getc (mio)))
6767d6be565SMasatake YAMATO 		r = true;
6777d6be565SMasatake YAMATO 
6787d6be565SMasatake YAMATO 	if (! (r && skipIfFound))
6797d6be565SMasatake YAMATO 		mio_rewind (mio);
6807d6be565SMasatake YAMATO 	return r;
6817d6be565SMasatake YAMATO }
6827d6be565SMasatake YAMATO 
rewindInputFile(inputFile * f)6837d6be565SMasatake YAMATO static void rewindInputFile (inputFile *f)
6847d6be565SMasatake YAMATO {
6857d6be565SMasatake YAMATO 	mio_rewind (f->mio);
6867d6be565SMasatake YAMATO 	if (f->bomFound)
6877d6be565SMasatake YAMATO 	{
688ee2b7a33SMasatake YAMATO 		int c CTAGS_ATTR_UNUSED;
6897d6be565SMasatake YAMATO 
6907d6be565SMasatake YAMATO 		c = mio_getc (f->mio);
6917d6be565SMasatake YAMATO 		Assert (c == 0xEF);
6927d6be565SMasatake YAMATO 		c = mio_getc (f->mio);
6937d6be565SMasatake YAMATO 		Assert (c == 0xBB);
6947d6be565SMasatake YAMATO 		c = mio_getc (f->mio);
6957d6be565SMasatake YAMATO 		Assert (c == 0xBF);
6967d6be565SMasatake YAMATO 	}
6977d6be565SMasatake YAMATO }
6987d6be565SMasatake YAMATO 
699d316cd59SMasatake YAMATO /*  This function opens an input file, and resets the line counter.  If it
700203c6955SJiří Techet  *  fails, it will display an error message and leave the File.mio set to NULL.
701d4c6f1e6SMasatake YAMATO  */
openInputFile(const char * const fileName,const langType language,MIO * mio,time_t mtime)702ce990805SThomas Braun extern bool openInputFile (const char *const fileName, const langType language,
703ce1f2415SMasatake YAMATO 			      MIO *mio, time_t mtime)
704d4c6f1e6SMasatake YAMATO {
705d4c6f1e6SMasatake YAMATO 	const char *const openMode = "rb";
706ce990805SThomas Braun 	bool opened = false;
707ce990805SThomas Braun 	bool memStreamRequired;
708d4c6f1e6SMasatake YAMATO 
709d4c6f1e6SMasatake YAMATO 	/*	If another file was already open, then close it.
710d4c6f1e6SMasatake YAMATO 	 */
711203c6955SJiří Techet 	if (File.mio != NULL)
712d4c6f1e6SMasatake YAMATO 	{
713b978efd6SMasatake YAMATO 		mio_unref (File.mio);  /* close any open input file */
714203c6955SJiří Techet 		File.mio = NULL;
715d4c6f1e6SMasatake YAMATO 	}
716d4c6f1e6SMasatake YAMATO 
71746204f78SBen Wiederhake 	/* File position is used as key for checking the availability of
71855a8e4c6SMasatake YAMATO 	   pattern cache in entry.h. If an input file is changed, the
71955a8e4c6SMasatake YAMATO 	   key is meaningless. So notifying the changing here. */
720800267f1SJonathon Reinhart 	invalidatePatternCache();
721adff34b1SMasatake YAMATO 
722adff34b1SMasatake YAMATO 	if (File.sourceTagPathHolder == NULL)
72356065e52SMasatake YAMATO 	{
724adff34b1SMasatake YAMATO 		File.sourceTagPathHolder = stringListNew ();
72533a6fdb8SMasatake YAMATO 		DEFAULT_TRASH_BOX(File.sourceTagPathHolder, stringListDelete);
72656065e52SMasatake YAMATO 	}
727adff34b1SMasatake YAMATO 	stringListClear (File.sourceTagPathHolder);
728adff34b1SMasatake YAMATO 
72931cb4225SMasatake YAMATO 	memStreamRequired = doesParserRequireMemoryStream (language);
730e9d4c72cSMasatake YAMATO 
731e9d4c72cSMasatake YAMATO 	if (mio)
732e9d4c72cSMasatake YAMATO 	{
733e9d4c72cSMasatake YAMATO 		size_t tmp;
734e9d4c72cSMasatake YAMATO 		if (memStreamRequired && (!mio_memory_get_data (mio, &tmp)))
735e9d4c72cSMasatake YAMATO 			mio = NULL;
736e9d4c72cSMasatake YAMATO 		else
737e9d4c72cSMasatake YAMATO 			mio_rewind (mio);
738e9d4c72cSMasatake YAMATO 	}
739e9d4c72cSMasatake YAMATO 
740c314f261SMasatake YAMATO 	File.mio = mio? mio_ref (mio): getMioFull (fileName, openMode, memStreamRequired, &File.mtime);
741e9d4c72cSMasatake YAMATO 
742203c6955SJiří Techet 	if (File.mio == NULL)
743d4c6f1e6SMasatake YAMATO 		error (WARNING | PERROR, "cannot open \"%s\"", fileName);
744d4c6f1e6SMasatake YAMATO 	else
745d4c6f1e6SMasatake YAMATO 	{
746ce990805SThomas Braun 		opened = true;
747d4c6f1e6SMasatake YAMATO 
748c314f261SMasatake YAMATO 		if (File.mio == mio)
749ce1f2415SMasatake YAMATO 			File.mtime = mtime;
7507d6be565SMasatake YAMATO 
7517d6be565SMasatake YAMATO 		File.bomFound = checkUTF8BOM (File.mio, true);
7527d6be565SMasatake YAMATO 
753fd12e3afSMasatake YAMATO 		setOwnerDirectoryOfInputFile (fileName);
754c434aea4SMasatake YAMATO 		mio_getpos (File.mio, &StartOfLine.pos);
755c434aea4SMasatake YAMATO 		mio_getpos (File.mio, &File.filePosition.pos);
756c434aea4SMasatake YAMATO 		File.filePosition.offset = StartOfLine.offset = mio_tell (File.mio);
757d4c6f1e6SMasatake YAMATO 		File.currentLine  = NULL;
758d4c6f1e6SMasatake YAMATO 
759314a657dSMasatake YAMATO 		File.line = vStringNewOrClear (File.line);
760539a03ffSMasatake YAMATO 		File.ungetchIdx = 0;
761d4c6f1e6SMasatake YAMATO 
762fd12e3afSMasatake YAMATO 		setInputFileParameters  (vStringNewInit (fileName), language);
763aed2b6adSMasatake YAMATO 		File.input.lineNumberOrigin = 0L;
764aed2b6adSMasatake YAMATO 		File.input.lineNumber = File.input.lineNumberOrigin;
765d4c6f1e6SMasatake YAMATO 		setSourceFileParameters (vStringNewInit (fileName), language);
766aed2b6adSMasatake YAMATO 		File.source.lineNumberOrigin = 0L;
767aed2b6adSMasatake YAMATO 		File.source.lineNumber = File.source.lineNumberOrigin;
76801ceddeaSMasatake YAMATO 		allocLineFposMap (&File.lineFposMap);
769d4c6f1e6SMasatake YAMATO 
7702fa69c1bSMasatake YAMATO 		File.thinDepth = 0;
7717d6be565SMasatake YAMATO 		verbose ("OPENING%s %s as %s language %sfile [%s%s]\n",
7727d6be565SMasatake YAMATO 				 (File.bomFound? "(skipping utf-8 bom)": ""),
7737d6be565SMasatake YAMATO 				 fileName,
774d4c6f1e6SMasatake YAMATO 				 getLanguageName (language),
77587803844SMasatake YAMATO 				 File.input.isHeader ? "include " : "",
77687803844SMasatake YAMATO 				 mio? "reused": "new",
77787803844SMasatake YAMATO 				 memStreamRequired? ",required": "");
778d4c6f1e6SMasatake YAMATO 	}
779d4c6f1e6SMasatake YAMATO 	return opened;
780d4c6f1e6SMasatake YAMATO }
781d4c6f1e6SMasatake YAMATO 
getInputFileMtime(void)782c314f261SMasatake YAMATO extern time_t getInputFileMtime (void)
783c314f261SMasatake YAMATO {
784c314f261SMasatake YAMATO 	return File.mtime;
785c314f261SMasatake YAMATO }
786c314f261SMasatake YAMATO 
resetInputFile(const langType language)787bc1a5e1bSMasatake YAMATO extern void resetInputFile (const langType language)
788bc1a5e1bSMasatake YAMATO {
789203c6955SJiří Techet 	Assert (File.mio);
790bc1a5e1bSMasatake YAMATO 
7917d6be565SMasatake YAMATO 	rewindInputFile  (&File);
792c434aea4SMasatake YAMATO 	mio_getpos (File.mio, &StartOfLine.pos);
793c434aea4SMasatake YAMATO 	mio_getpos (File.mio, &File.filePosition.pos);
794c434aea4SMasatake YAMATO 	File.filePosition.offset = StartOfLine.offset = mio_tell (File.mio);
795bc1a5e1bSMasatake YAMATO 	File.currentLine  = NULL;
796bc1a5e1bSMasatake YAMATO 
797314a657dSMasatake YAMATO 	Assert (File.line);
798bc1a5e1bSMasatake YAMATO 	vStringClear (File.line);
799539a03ffSMasatake YAMATO 	File.ungetchIdx = 0;
800539a03ffSMasatake YAMATO 
801587a8e25SMasatake YAMATO 	if (hasLanguageMultilineRegexPatterns (language))
802587a8e25SMasatake YAMATO 		File.allLines = vStringNew ();
803bc1a5e1bSMasatake YAMATO 
804ebc3af7dSMasatake YAMATO 	resetLangOnStack (& inputLang, language);
805aed2b6adSMasatake YAMATO 	File.input.lineNumber = File.input.lineNumberOrigin;
8067262d5eaSMasatake YAMATO 	sourceLang = language;
807aed2b6adSMasatake YAMATO 	File.source.lineNumber = File.source.lineNumberOrigin;
808bc1a5e1bSMasatake YAMATO }
809bc1a5e1bSMasatake YAMATO 
closeInputFile(void)81049bb7f66SMasatake YAMATO extern void closeInputFile (void)
811d4c6f1e6SMasatake YAMATO {
812203c6955SJiří Techet 	if (File.mio != NULL)
813d4c6f1e6SMasatake YAMATO 	{
814ebc3af7dSMasatake YAMATO 		clearLangOnStack (& inputLang);
815a8778562SMasatake YAMATO 
816d4c6f1e6SMasatake YAMATO 		/*  The line count of the file is 1 too big, since it is one-based
817d4c6f1e6SMasatake YAMATO 		 *  and is incremented upon each newline.
818d4c6f1e6SMasatake YAMATO 		 */
819d4c6f1e6SMasatake YAMATO 		if (Option.printTotals)
820d4c6f1e6SMasatake YAMATO 		{
821a5b1fa4aSMasatake YAMATO 			fileStatus *status = eStat (vStringValue (File.input.name));
822a5b1fa4aSMasatake YAMATO 			addTotals (0, File.input.lineNumber - 1L, status->size);
823d4c6f1e6SMasatake YAMATO 		}
824b978efd6SMasatake YAMATO 		mio_unref (File.mio);
825203c6955SJiří Techet 		File.mio = NULL;
82601ceddeaSMasatake YAMATO 		freeLineFposMap (&File.lineFposMap);
827d4c6f1e6SMasatake YAMATO 	}
828d4c6f1e6SMasatake YAMATO }
829d4c6f1e6SMasatake YAMATO 
getInputFileUserData(void)83061f7a0ebSMasatake YAMATO extern void *getInputFileUserData(void)
83161f7a0ebSMasatake YAMATO {
832203c6955SJiří Techet 	return mio_get_user_data (File.mio);
83361f7a0ebSMasatake YAMATO }
83461f7a0ebSMasatake YAMATO 
835d316cd59SMasatake YAMATO /*  Action to take for each encountered input newline.
836d4c6f1e6SMasatake YAMATO  */
fileNewline(bool crAdjustment)8373b035e33SMasatake YAMATO static void fileNewline (bool crAdjustment)
838d4c6f1e6SMasatake YAMATO {
839d4c6f1e6SMasatake YAMATO 	File.filePosition = StartOfLine;
8404fa68e36SMasatake YAMATO 
841203c6955SJiří Techet 	if (BackupFile.mio == NULL)
8423b035e33SMasatake YAMATO 		appendLineFposMap (&File.lineFposMap, &File.filePosition,
8433b035e33SMasatake YAMATO 						   crAdjustment);
8444fa68e36SMasatake YAMATO 
845a5b1fa4aSMasatake YAMATO 	File.input.lineNumber++;
846d4c6f1e6SMasatake YAMATO 	File.source.lineNumber++;
847a5b1fa4aSMasatake YAMATO 	DebugStatement ( if (Option.breakLine == File.input.lineNumber) lineBreak (); )
848a5b1fa4aSMasatake YAMATO 	DebugStatement ( debugPrintf (DEBUG_RAW, "%6ld: ", File.input.lineNumber); )
849d4c6f1e6SMasatake YAMATO }
850d4c6f1e6SMasatake YAMATO 
ungetcToInputFile(int c)85161f14fa5SMasatake YAMATO extern void ungetcToInputFile (int c)
852d4c6f1e6SMasatake YAMATO {
853158a3387SMasatake YAMATO 	const size_t len = ARRAY_SIZE (File.ungetchBuf);
854956af055SColomban Wendling 
855956af055SColomban Wendling 	Assert (File.ungetchIdx < len);
856956af055SColomban Wendling 	/* we cannot rely on the assertion that might be disabled in non-debug mode */
857956af055SColomban Wendling 	if (File.ungetchIdx < len)
858956af055SColomban Wendling 		File.ungetchBuf[File.ungetchIdx++] = c;
859d4c6f1e6SMasatake YAMATO }
860d4c6f1e6SMasatake YAMATO 
861c447d2e2SMasatake YAMATO typedef enum eEolType {
862c447d2e2SMasatake YAMATO 	eol_eof = 0,
863c447d2e2SMasatake YAMATO 	eol_nl,
864c447d2e2SMasatake YAMATO 	eol_cr_nl,
865c447d2e2SMasatake YAMATO } eolType;
866c447d2e2SMasatake YAMATO 
readLine(vString * const vLine,MIO * const mio)867c447d2e2SMasatake YAMATO static eolType readLine (vString *const vLine, MIO *const mio)
868d4c6f1e6SMasatake YAMATO {
8695388d8eaSJiří Techet 	char *str;
8705388d8eaSJiří Techet 	size_t size;
871c447d2e2SMasatake YAMATO 	eolType r = eol_nl;
8725388d8eaSJiří Techet 
873454b08edSJiří Techet 	vStringClear (vLine);
874454b08edSJiří Techet 
875454b08edSJiří Techet 	str = vStringValue (vLine);
876454b08edSJiří Techet 	size = vStringSize (vLine);
8775388d8eaSJiří Techet 
8785388d8eaSJiří Techet 	for (;;)
879d4c6f1e6SMasatake YAMATO 	{
8805388d8eaSJiří Techet 		bool newLine;
8815388d8eaSJiří Techet 		bool eof;
8825388d8eaSJiří Techet 
883454b08edSJiří Techet 		if (mio_gets (mio, str, size) == NULL)
884454b08edSJiří Techet 		{
885454b08edSJiří Techet 			if (!mio_eof (mio))
886454b08edSJiří Techet 				error (FATAL | PERROR, "Failure on attempt to read file");
887454b08edSJiří Techet 		}
888454b08edSJiří Techet 		vStringSetLength (vLine);
889454b08edSJiří Techet 		newLine = vStringLength (vLine) > 0 && vStringLast (vLine) == '\n';
890454b08edSJiří Techet 		eof = mio_eof (mio);
891c447d2e2SMasatake YAMATO 		if (eof)
892c447d2e2SMasatake YAMATO 			r = eol_eof;
8938fac6ad5SJiří Techet 
8948fac6ad5SJiří Techet 		/* Turn line breaks into a canonical form. The three commonly
8958fac6ad5SJiří Techet 		 * used forms of line breaks are: LF (UNIX/Mac OS X), CR-LF (MS-DOS) and
896759d281dSK.Takata 		 * CR (Mac OS 9). As CR-only EOL isn't handled by gets() and Mac OS 9
8978fac6ad5SJiří Techet 		 * is dead, we only handle CR-LF EOLs and convert them into LF. */
898454b08edSJiří Techet 		if (newLine && vStringLength (vLine) > 1 &&
8997171591bSMasatake YAMATO 			vStringChar (vLine, vStringLength (vLine) - 2) == '\r')
900d4c6f1e6SMasatake YAMATO 		{
9017171591bSMasatake YAMATO 			vStringChar (vLine, vStringLength (vLine) - 2) = '\n';
902454b08edSJiří Techet 			vStringChop (vLine);
903c447d2e2SMasatake YAMATO 			r = eol_cr_nl;
9045388d8eaSJiří Techet 		}
9055388d8eaSJiří Techet 
9065388d8eaSJiří Techet 		if (newLine || eof)
9075388d8eaSJiří Techet 			break;
9085388d8eaSJiří Techet 
909454b08edSJiří Techet 		vStringResize (vLine, vStringLength (vLine) * 2);
910454b08edSJiří Techet 		str = vStringValue (vLine) + vStringLength (vLine);
911454b08edSJiří Techet 		size = vStringSize (vLine) - vStringLength (vLine);
912454b08edSJiří Techet 	}
913c447d2e2SMasatake YAMATO 	return r;
9145388d8eaSJiří Techet }
9155388d8eaSJiří Techet 
iFileGetLine(bool chop_newline)9165b7dabdaSMasatake YAMATO static vString *iFileGetLine (bool chop_newline)
917454b08edSJiří Techet {
918c447d2e2SMasatake YAMATO 	eolType eol;
919f98241cdSjannick0 	langType lang = getInputLanguage();
920c447d2e2SMasatake YAMATO 
921314a657dSMasatake YAMATO 	Assert (File.line);
922c447d2e2SMasatake YAMATO 	eol = readLine (File.line, File.mio);
923454b08edSJiří Techet 
924454b08edSJiří Techet 	if (vStringLength (File.line) > 0)
9255388d8eaSJiří Techet 	{
9265388d8eaSJiří Techet 		/* Use StartOfLine from previous iFileGetLine() call */
9273b035e33SMasatake YAMATO 		fileNewline (eol == eol_cr_nl);
9285388d8eaSJiří Techet 		/* Store StartOfLine for the next iFileGetLine() call */
929c434aea4SMasatake YAMATO 		mio_getpos (File.mio, &StartOfLine.pos);
930c434aea4SMasatake YAMATO 		StartOfLine.offset = mio_tell (File.mio);
9315388d8eaSJiří Techet 
9325388d8eaSJiří Techet 		if (Option.lineDirectives && vStringChar (File.line, 0) == '#')
9335388d8eaSJiří Techet 			parseLineDirective (vStringValue (File.line) + 1);
934a656c9bfSMasatake YAMATO 
935587a8e25SMasatake YAMATO 		if (File.allLines)
9364e0c6ed6SMasatake YAMATO 			vStringCat (File.allLines, File.line);
9373b035e33SMasatake YAMATO 
9385b7dabdaSMasatake YAMATO 		bool chopped = vStringStripNewline (File.line);
9395b7dabdaSMasatake YAMATO 
9405b7dabdaSMasatake YAMATO 		matchLanguageRegex (lang, File.line);
9415b7dabdaSMasatake YAMATO 
9425b7dabdaSMasatake YAMATO 		if (chopped && !chop_newline)
9435b7dabdaSMasatake YAMATO 			vStringPutNewlinAgainUnsafe (File.line);
9445b7dabdaSMasatake YAMATO 
9455388d8eaSJiří Techet 		return File.line;
946d4c6f1e6SMasatake YAMATO 	}
9474e0c6ed6SMasatake YAMATO 	else
9484e0c6ed6SMasatake YAMATO 	{
949587a8e25SMasatake YAMATO 		if (File.allLines)
9504e0c6ed6SMasatake YAMATO 		{
951f98241cdSjannick0 			matchLanguageMultilineRegex (lang, File.allLines);
952f98241cdSjannick0 			matchLanguageMultitableRegex (lang, File.allLines);
953587a8e25SMasatake YAMATO 
954587a8e25SMasatake YAMATO 			/* To limit the execution of multiline/multitable parser(s) only
955587a8e25SMasatake YAMATO 			   ONCE, clear File.allLines field. */
9564e0c6ed6SMasatake YAMATO 			vStringDelete (File.allLines);
9574e0c6ed6SMasatake YAMATO 			File.allLines = NULL;
9584e0c6ed6SMasatake YAMATO 		}
9595388d8eaSJiří Techet 		return NULL;
960d4c6f1e6SMasatake YAMATO 	}
9614e0c6ed6SMasatake YAMATO }
962d4c6f1e6SMasatake YAMATO 
9636c6421daSJiří Techet /*  Do not mix use of readLineFromInputFile () and getcFromInputFile () for the same file.
964d4c6f1e6SMasatake YAMATO  */
getcFromInputFile(void)965018bce0bSMasatake YAMATO extern int getcFromInputFile (void)
966d4c6f1e6SMasatake YAMATO {
967d4c6f1e6SMasatake YAMATO 	int c;
968d4c6f1e6SMasatake YAMATO 
969d4c6f1e6SMasatake YAMATO 	/*  If there is an ungotten character, then return it.  Don't do any
970d4c6f1e6SMasatake YAMATO 	 *  other processing on it, though, because we already did that the
971018bce0bSMasatake YAMATO 	 *  first time it was read through getcFromInputFile ().
972d4c6f1e6SMasatake YAMATO 	 */
973956af055SColomban Wendling 	if (File.ungetchIdx > 0)
974d4c6f1e6SMasatake YAMATO 	{
975956af055SColomban Wendling 		c = File.ungetchBuf[--File.ungetchIdx];
976d4c6f1e6SMasatake YAMATO 		return c;  /* return here to avoid re-calling debugPutc () */
977d4c6f1e6SMasatake YAMATO 	}
978d4c6f1e6SMasatake YAMATO 	do
979d4c6f1e6SMasatake YAMATO 	{
980d4c6f1e6SMasatake YAMATO 		if (File.currentLine != NULL)
981d4c6f1e6SMasatake YAMATO 		{
982d4c6f1e6SMasatake YAMATO 			c = *File.currentLine++;
983d4c6f1e6SMasatake YAMATO 			if (c == '\0')
984d4c6f1e6SMasatake YAMATO 				File.currentLine = NULL;
985d4c6f1e6SMasatake YAMATO 		}
986d4c6f1e6SMasatake YAMATO 		else
987d4c6f1e6SMasatake YAMATO 		{
9885b7dabdaSMasatake YAMATO 			vString* const line = iFileGetLine (false);
989d4c6f1e6SMasatake YAMATO 			if (line != NULL)
990d4c6f1e6SMasatake YAMATO 				File.currentLine = (unsigned char*) vStringValue (line);
991d4c6f1e6SMasatake YAMATO 			if (File.currentLine == NULL)
992d4c6f1e6SMasatake YAMATO 				c = EOF;
993d4c6f1e6SMasatake YAMATO 			else
994d4c6f1e6SMasatake YAMATO 				c = '\0';
995d4c6f1e6SMasatake YAMATO 		}
996d4c6f1e6SMasatake YAMATO 	} while (c == '\0');
997d4c6f1e6SMasatake YAMATO 	DebugStatement ( debugPutc (DEBUG_READ, c); )
998d4c6f1e6SMasatake YAMATO 	return c;
999d4c6f1e6SMasatake YAMATO }
1000d4c6f1e6SMasatake YAMATO 
10017b90026cSColomban Wendling /* returns the nth previous character (0 meaning current), or def if nth cannot
10027b90026cSColomban Wendling  * be accessed.  Note that this can't access previous line data. */
getNthPrevCFromInputFile(unsigned int nth,int def)10037b90026cSColomban Wendling extern int getNthPrevCFromInputFile (unsigned int nth, int def)
10047b90026cSColomban Wendling {
10057b90026cSColomban Wendling 	const unsigned char *base = (unsigned char *) vStringValue (File.line);
1006dfe9904aSColomban Wendling 	const unsigned int offset = File.ungetchIdx + 1 + nth;
10077b90026cSColomban Wendling 
1008dfe9904aSColomban Wendling 	if (File.currentLine != NULL && File.currentLine >= base + offset)
1009dfe9904aSColomban Wendling 		return (int) *(File.currentLine - offset);
10107b90026cSColomban Wendling 	else
10117b90026cSColomban Wendling 		return def;
10127b90026cSColomban Wendling }
10137b90026cSColomban Wendling 
skipToCharacterInInputFile(int c)10144fffc5afSMasatake YAMATO extern int skipToCharacterInInputFile (int c)
1015d4c6f1e6SMasatake YAMATO {
1016d4c6f1e6SMasatake YAMATO 	int d;
1017d4c6f1e6SMasatake YAMATO 	do
1018d4c6f1e6SMasatake YAMATO 	{
1019018bce0bSMasatake YAMATO 		d = getcFromInputFile ();
1020d4c6f1e6SMasatake YAMATO 	} while (d != EOF && d != c);
1021d4c6f1e6SMasatake YAMATO 	return d;
1022d4c6f1e6SMasatake YAMATO }
1023d4c6f1e6SMasatake YAMATO 
skipToCharacterInInputFile2(int c0,int c1)102464a05963SMasatake YAMATO extern int skipToCharacterInInputFile2 (int c0, int c1)
102564a05963SMasatake YAMATO {
102664a05963SMasatake YAMATO 	int d;
102764a05963SMasatake YAMATO 	do
102864a05963SMasatake YAMATO 	{
102964a05963SMasatake YAMATO 		skipToCharacterInInputFile(c0);
103064a05963SMasatake YAMATO 		do
103164a05963SMasatake YAMATO 			d = getcFromInputFile ();
103264a05963SMasatake YAMATO 		while (d == c0 && d != c1);
103364a05963SMasatake YAMATO 	} while (d != EOF && d != c1);
103464a05963SMasatake YAMATO 	return d;
103564a05963SMasatake YAMATO }
103664a05963SMasatake YAMATO 
10376c6421daSJiří Techet /*  An alternative interface to getcFromInputFile (). Do not mix use of readLineFromInputFile()
1038018bce0bSMasatake YAMATO  *  and getcFromInputFile() for the same file. The returned string does not contain
1039d4c6f1e6SMasatake YAMATO  *  the terminating newline. A NULL return value means that all lines in the
1040d4c6f1e6SMasatake YAMATO  *  file have been read and we are at the end of file.
1041d4c6f1e6SMasatake YAMATO  */
readLineFromInputFile(void)10421b312fe7SMasatake YAMATO extern const unsigned char *readLineFromInputFile (void)
1043d4c6f1e6SMasatake YAMATO {
10445b7dabdaSMasatake YAMATO 	vString* const line = iFileGetLine (true);
1045d4c6f1e6SMasatake YAMATO 	const unsigned char* result = NULL;
1046d4c6f1e6SMasatake YAMATO 	if (line != NULL)
1047d4c6f1e6SMasatake YAMATO 	{
1048d4c6f1e6SMasatake YAMATO 		result = (const unsigned char*) vStringValue (line);
1049d4c6f1e6SMasatake YAMATO 		DebugStatement ( debugPrintf (DEBUG_READ, "%s\n", result); )
1050d4c6f1e6SMasatake YAMATO 	}
1051d4c6f1e6SMasatake YAMATO 	return result;
1052d4c6f1e6SMasatake YAMATO }
1053d4c6f1e6SMasatake YAMATO 
1054d4c6f1e6SMasatake YAMATO /*
1055918a642dSMasatake YAMATO  *   Raw file line reading with automatic buffer sizing
1056d4c6f1e6SMasatake YAMATO  */
readLineRaw(vString * const vLine,MIO * const mio)1057203c6955SJiří Techet extern char *readLineRaw (vString *const vLine, MIO *const mio)
1058d4c6f1e6SMasatake YAMATO {
1059203c6955SJiří Techet 	if (mio == NULL)  /* to free memory allocated to buffer */
1060d4c6f1e6SMasatake YAMATO 		error (FATAL, "NULL file pointer");
1061d4c6f1e6SMasatake YAMATO 	else
1062d4c6f1e6SMasatake YAMATO 	{
1063454b08edSJiří Techet 		readLine (vLine, mio);
10642acdcfa1SYasuhiro Matsumoto 
10652acdcfa1SYasuhiro Matsumoto #ifdef HAVE_ICONV
10662acdcfa1SYasuhiro Matsumoto 		if (isConverting ())
10672acdcfa1SYasuhiro Matsumoto 			convertString (vLine);
10682acdcfa1SYasuhiro Matsumoto #endif
1069d4c6f1e6SMasatake YAMATO 	}
1070454b08edSJiří Techet 	return vStringLength (vLine) > 0 ? vStringValue (vLine) : NULL;
1071d4c6f1e6SMasatake YAMATO }
1072d4c6f1e6SMasatake YAMATO 
1073d4c6f1e6SMasatake YAMATO /*  Places into the line buffer the contents of the line referenced by
1074d4c6f1e6SMasatake YAMATO  *  "location".
1075d4c6f1e6SMasatake YAMATO  */
readLineFromBypass(vString * const vLine,MIOPos location,long * const pSeekValue)107674e1a7cfSMasatake YAMATO extern char *readLineFromBypass (
1077509a47dbSJiří Techet 		vString *const vLine, MIOPos location, long *const pSeekValue)
1078d4c6f1e6SMasatake YAMATO {
1079509a47dbSJiří Techet 	MIOPos orignalPosition;
1080d4c6f1e6SMasatake YAMATO 	char *result;
1081d4c6f1e6SMasatake YAMATO 
1082203c6955SJiří Techet 	mio_getpos (File.mio, &orignalPosition);
1083203c6955SJiří Techet 	mio_setpos (File.mio, &location);
108402d2d3b4SJiří Techet 	mio_clearerr (File.mio);
1085d4c6f1e6SMasatake YAMATO 	if (pSeekValue != NULL)
1086203c6955SJiří Techet 		*pSeekValue = mio_tell (File.mio);
1087203c6955SJiří Techet 	result = readLineRaw (vLine, File.mio);
1088203c6955SJiří Techet 	mio_setpos (File.mio, &orignalPosition);
10895dbd2e67SK.Takata 	/* If the file is empty, we can't get the line
109074e1a7cfSMasatake YAMATO 	   for location 0. readLineFromBypass doesn't know
1091521e3c77SMasatake YAMATO 	   what itself should do; just report it to the caller. */
1092d4c6f1e6SMasatake YAMATO 	return result;
1093d4c6f1e6SMasatake YAMATO }
1094d4c6f1e6SMasatake YAMATO 
pushNarrowedInputStream(bool useMemoryStreamInput,unsigned long startLine,long startCharOffset,unsigned long endLine,long endCharOffset,unsigned long sourceLineOffset,int promise)10954d1713c7SMasatake YAMATO extern void   pushNarrowedInputStream (
1096*9128cdbaSMasatake YAMATO 				       bool useMemoryStreamInput,
1097ef722b09SMasatake YAMATO 				       unsigned long startLine, long startCharOffset,
1098ef722b09SMasatake YAMATO 				       unsigned long endLine, long endCharOffset,
109911e58e48SMasatake YAMATO 				       unsigned long sourceLineOffset,
110011e58e48SMasatake YAMATO 				       int promise)
11014fa68e36SMasatake YAMATO {
11024fa68e36SMasatake YAMATO 	long p, q;
11034fa68e36SMasatake YAMATO 	MIOPos original;
11044fa68e36SMasatake YAMATO 	MIOPos tmp;
11054fa68e36SMasatake YAMATO 	MIO *subio;
11064fa68e36SMasatake YAMATO 
11072fa69c1bSMasatake YAMATO 	if (isThinStreamSpec (startLine, startCharOffset,
11082fa69c1bSMasatake YAMATO 						  endLine, endCharOffset,
11092fa69c1bSMasatake YAMATO 						  sourceLineOffset))
11102fa69c1bSMasatake YAMATO 	{
1111*9128cdbaSMasatake YAMATO 		if ((!useMemoryStreamInput
1112*9128cdbaSMasatake YAMATO 			 || mio_memory_get_data (File.mio, NULL)))
1113*9128cdbaSMasatake YAMATO 		{
11142fa69c1bSMasatake YAMATO 			File.thinDepth++;
11152fa69c1bSMasatake YAMATO 			verbose ("push thin stream (%d)\n", File.thinDepth);
11162fa69c1bSMasatake YAMATO 			return;
11172fa69c1bSMasatake YAMATO 		}
1118*9128cdbaSMasatake YAMATO 		error(WARNING, "INTERNAL ERROR: though pushing thin MEMORY stream, "
1119*9128cdbaSMasatake YAMATO 			  "underlying input stream is a FILE stream: %s@%s",
1120*9128cdbaSMasatake YAMATO 			  vStringValue (File.input.name), vStringValue (File.input.tagPath));
1121*9128cdbaSMasatake YAMATO 		AssertNotReached ();
1122*9128cdbaSMasatake YAMATO 	}
11232fa69c1bSMasatake YAMATO 	Assert (File.thinDepth == 0);
11242fa69c1bSMasatake YAMATO 
11254fa68e36SMasatake YAMATO 	original = getInputFilePosition ();
11264fa68e36SMasatake YAMATO 
11274fa68e36SMasatake YAMATO 	tmp = getInputFilePositionForLine (startLine);
1128203c6955SJiří Techet 	mio_setpos (File.mio, &tmp);
1129203c6955SJiří Techet 	mio_seek (File.mio, startCharOffset, SEEK_CUR);
1130203c6955SJiří Techet 	p = mio_tell (File.mio);
11314fa68e36SMasatake YAMATO 
11324fa68e36SMasatake YAMATO 	tmp = getInputFilePositionForLine (endLine);
1133203c6955SJiří Techet 	mio_setpos (File.mio, &tmp);
1134203c6955SJiří Techet 	mio_seek (File.mio, endCharOffset, SEEK_CUR);
1135203c6955SJiří Techet 	q = mio_tell (File.mio);
11364fa68e36SMasatake YAMATO 
1137203c6955SJiří Techet 	mio_setpos (File.mio, &original);
11384fa68e36SMasatake YAMATO 
1139f546df63SMasatake YAMATO 	invalidatePatternCache();
1140f546df63SMasatake YAMATO 
114111e58e48SMasatake YAMATO 	size_t size = q - p;
114211e58e48SMasatake YAMATO 	subio = mio_new_mio (File.mio, p, size);
11431aa31b1aSMasatake YAMATO 	if (subio == NULL)
11441aa31b1aSMasatake YAMATO 		error (FATAL, "memory for mio may be exhausted");
11454fa68e36SMasatake YAMATO 
114611e58e48SMasatake YAMATO 	runModifiers (promise,
114711e58e48SMasatake YAMATO 				  startLine, startCharOffset,
114811e58e48SMasatake YAMATO 				  endLine, endCharOffset,
114911e58e48SMasatake YAMATO 				  mio_memory_get_data (subio, NULL),
115011e58e48SMasatake YAMATO 				  size);
115111e58e48SMasatake YAMATO 
11524fa68e36SMasatake YAMATO 	BackupFile = File;
11534fa68e36SMasatake YAMATO 
1154203c6955SJiří Techet 	File.mio = subio;
11557d6be565SMasatake YAMATO 	File.bomFound = false;
1156a0c1e6d7SMasatake YAMATO 	File.nestedInputStreamInfo.startLine = startLine;
1157a0c1e6d7SMasatake YAMATO 	File.nestedInputStreamInfo.startCharOffset = startCharOffset;
1158a0c1e6d7SMasatake YAMATO 	File.nestedInputStreamInfo.endLine = endLine;
1159a0c1e6d7SMasatake YAMATO 	File.nestedInputStreamInfo.endCharOffset = endCharOffset;
11604fa68e36SMasatake YAMATO 
11614fa68e36SMasatake YAMATO 	File.input.lineNumberOrigin = ((startLine == 0)? 0: startLine - 1);
11624fa68e36SMasatake YAMATO 	File.source.lineNumberOrigin = ((sourceLineOffset == 0)? 0: sourceLineOffset - 1);
11634fa68e36SMasatake YAMATO }
11644fa68e36SMasatake YAMATO 
doesParserRunAsGuest(void)116513b5aee2SMasatake YAMATO extern bool doesParserRunAsGuest (void)
116613b5aee2SMasatake YAMATO {
116713b5aee2SMasatake YAMATO 	return !(File.nestedInputStreamInfo.startLine == 0
116813b5aee2SMasatake YAMATO 			 && File.nestedInputStreamInfo.startCharOffset == 0
116913b5aee2SMasatake YAMATO 			 && File.nestedInputStreamInfo.endLine == 0
117013b5aee2SMasatake YAMATO 			 && File.nestedInputStreamInfo.endCharOffset == 0);
117113b5aee2SMasatake YAMATO }
117213b5aee2SMasatake YAMATO 
getNestedInputBoundaryInfo(unsigned long lineNumber)1173a0c1e6d7SMasatake YAMATO extern unsigned int getNestedInputBoundaryInfo (unsigned long lineNumber)
1174a0c1e6d7SMasatake YAMATO {
1175a0c1e6d7SMasatake YAMATO 	unsigned int info;
1176a0c1e6d7SMasatake YAMATO 
117713b5aee2SMasatake YAMATO 	if (!doesParserRunAsGuest())
1178a0c1e6d7SMasatake YAMATO 		/* Not in a nested input stream  */
1179a0c1e6d7SMasatake YAMATO 		return 0;
1180a0c1e6d7SMasatake YAMATO 
1181a0c1e6d7SMasatake YAMATO 	info = 0;
1182a0c1e6d7SMasatake YAMATO 	if (File.nestedInputStreamInfo.startLine == lineNumber
1183a0c1e6d7SMasatake YAMATO 	    && File.nestedInputStreamInfo.startCharOffset != 0)
1184a0c1e6d7SMasatake YAMATO 		info |= BOUNDARY_START;
1185a0c1e6d7SMasatake YAMATO 	if (File.nestedInputStreamInfo.endLine == lineNumber
1186a0c1e6d7SMasatake YAMATO 	    && File.nestedInputStreamInfo.endCharOffset != 0)
1187a0c1e6d7SMasatake YAMATO 		info |= BOUNDARY_END;
1188a0c1e6d7SMasatake YAMATO 
1189a0c1e6d7SMasatake YAMATO 	return info;
1190a0c1e6d7SMasatake YAMATO }
popNarrowedInputStream(void)11914fa68e36SMasatake YAMATO extern void   popNarrowedInputStream  (void)
11924fa68e36SMasatake YAMATO {
11932fa69c1bSMasatake YAMATO 	if (File.thinDepth)
11942fa69c1bSMasatake YAMATO 	{
11952fa69c1bSMasatake YAMATO 		File.thinDepth--;
11962fa69c1bSMasatake YAMATO 		verbose ("CLEARING thin flag(%d)\n", File.thinDepth);
11972fa69c1bSMasatake YAMATO 		return;
11982fa69c1bSMasatake YAMATO 	}
1199b978efd6SMasatake YAMATO 	mio_unref (File.mio);
12004fa68e36SMasatake YAMATO 	File = BackupFile;
12014fa68e36SMasatake YAMATO 	memset (&BackupFile, 0, sizeof (BackupFile));
12024fa68e36SMasatake YAMATO }
12034fa68e36SMasatake YAMATO 
pushLanguage(const langType language)1204a8778562SMasatake YAMATO extern void pushLanguage (const langType language)
1205a8778562SMasatake YAMATO {
1206ebc3af7dSMasatake YAMATO 	pushLangOnStack (& inputLang, language);
1207a8778562SMasatake YAMATO }
1208a8778562SMasatake YAMATO 
popLanguage(void)1209a8778562SMasatake YAMATO extern langType popLanguage (void)
1210a8778562SMasatake YAMATO {
1211ebc3af7dSMasatake YAMATO 	return popLangOnStack (& inputLang);
1212a8778562SMasatake YAMATO }
1213a8778562SMasatake YAMATO 
getLanguageForBaseParser(void)1214657cbb19SMasatake YAMATO extern langType getLanguageForBaseParser (void)
1215657cbb19SMasatake YAMATO {
1216657cbb19SMasatake YAMATO 	return baseLangOnStack (& inputLang);
1217657cbb19SMasatake YAMATO }
1218657cbb19SMasatake YAMATO 
langStackInit(langStack * langStack)1219a8778562SMasatake YAMATO static void langStackInit (langStack *langStack)
1220a8778562SMasatake YAMATO {
1221a8778562SMasatake YAMATO 	langStack->count = 0;
1222a8778562SMasatake YAMATO 	langStack->size  = 1;
1223a8778562SMasatake YAMATO 	langStack->languages = xCalloc (langStack->size, langType);
122433a6fdb8SMasatake YAMATO 	DEFAULT_TRASH_BOX(&(langStack->languages), eFreeIndirect);
1225a8778562SMasatake YAMATO }
1226a8778562SMasatake YAMATO 
langStackTop(langStack * langStack)1227a8778562SMasatake YAMATO static langType langStackTop (langStack *langStack)
1228a8778562SMasatake YAMATO {
1229a8778562SMasatake YAMATO 	Assert (langStack->count > 0);
1230a8778562SMasatake YAMATO 	return langStack->languages [langStack->count - 1];
1231a8778562SMasatake YAMATO }
1232a8778562SMasatake YAMATO 
langStackBotom(langStack * langStack)1233657cbb19SMasatake YAMATO static langType langStackBotom(langStack *langStack)
1234657cbb19SMasatake YAMATO {
1235657cbb19SMasatake YAMATO 	Assert (langStack->count > 0);
1236657cbb19SMasatake YAMATO 	return langStack->languages [0];
1237657cbb19SMasatake YAMATO }
1238657cbb19SMasatake YAMATO 
langStackClear(langStack * langStack)123979758c23SMasatake YAMATO static void     langStackClear (langStack *langStack)
124079758c23SMasatake YAMATO {
124179758c23SMasatake YAMATO 	while (langStack->count > 0)
124279758c23SMasatake YAMATO 		langStackPop (langStack);
124379758c23SMasatake YAMATO }
124479758c23SMasatake YAMATO 
langStackPush(langStack * langStack,langType type)1245a8778562SMasatake YAMATO static void     langStackPush (langStack *langStack, langType type)
1246a8778562SMasatake YAMATO {
1247a8778562SMasatake YAMATO 	if (langStack->size == 0)
1248a8778562SMasatake YAMATO 		langStackInit (langStack);
1249a8778562SMasatake YAMATO 	else if (langStack->count == langStack->size)
1250a8778562SMasatake YAMATO 		langStack->languages = xRealloc (langStack->languages,
1251a8778562SMasatake YAMATO 						 ++ langStack->size, langType);
1252a8778562SMasatake YAMATO 	langStack->languages [ langStack->count ++ ] = type;
1253a8778562SMasatake YAMATO }
1254a8778562SMasatake YAMATO 
langStackPop(langStack * langStack)1255a8778562SMasatake YAMATO static langType langStackPop  (langStack *langStack)
1256a8778562SMasatake YAMATO {
1257a8778562SMasatake YAMATO 	return langStack->languages [ -- langStack->count ];
1258a8778562SMasatake YAMATO }
12592fa69c1bSMasatake YAMATO 
isThinStreamSpec(unsigned long startLine,long startCharOffset,unsigned long endLine,long endCharOffset,unsigned long sourceLineOffset)12602fa69c1bSMasatake YAMATO extern bool isThinStreamSpec(unsigned long startLine, long startCharOffset,
12612fa69c1bSMasatake YAMATO 							 unsigned long endLine, long endCharOffset,
12622fa69c1bSMasatake YAMATO 							 unsigned long sourceLineOffset)
12632fa69c1bSMasatake YAMATO {
12642fa69c1bSMasatake YAMATO 	return (startLine == 0 &&
12652fa69c1bSMasatake YAMATO 			startCharOffset == 0 &&
12662fa69c1bSMasatake YAMATO 			endLine == 0 &&
12672fa69c1bSMasatake YAMATO 			endCharOffset == 0 &&
12682fa69c1bSMasatake YAMATO 			sourceLineOffset == 0);
12692fa69c1bSMasatake YAMATO }
1270782707aeSMasatake YAMATO 
1271782707aeSMasatake YAMATO #ifdef DO_TRACING
isTraced(void)1272782707aeSMasatake YAMATO extern bool isTraced (void)
1273782707aeSMasatake YAMATO {
1274782707aeSMasatake YAMATO 	if (File.mio == NULL)
1275782707aeSMasatake YAMATO 		/* A parser is not given. In that case, just check whether --_trace option
1276782707aeSMasatake YAMATO 		   is given or not. */
1277782707aeSMasatake YAMATO 		return isMainTraced ();
1278782707aeSMasatake YAMATO 	else
1279782707aeSMasatake YAMATO 		/* A parser is given. In that case, check whether the current parser is
1280782707aeSMasatake YAMATO 		   specified in --_trace=<LANG>,... option */
1281782707aeSMasatake YAMATO 		return isLanguageTraced (getInputLanguage ());
1282782707aeSMasatake YAMATO }
1283782707aeSMasatake YAMATO #endif	/* DO_TRACING */
1284