1 /*
2 *
3 * Copyright (c) 2019, Red Hat, Inc.
4 * Copyright (c) 2019, Masatake YAMATO
5 *
6 * Author: Masatake YAMATO <yamato@redhat.com>
7 *
8 * This source code is released for free distribution under the terms of the
9 * GNU General Public License version 2 or (at your option) any later version.
10 *
11 * Unwindable input stream / Unlimited ungetc
12 *
13 */
14
15 /*
16 * INCLUDE FILES
17 */
18
19 #include "general.h"
20
21 #include "debug.h"
22 #include "gcc-attr.h"
23 #include "inline.h"
24 #include "mio.h"
25 #include "objpool.h"
26 #include "ptrarray.h"
27 #include "read.h"
28 #include "routines.h"
29 #include "trashbox.h"
30 #include "unwindi.h"
31
32 #include <string.h>
33
34 typedef struct sUugcChar {
35 int c;
36 /* lineNumber before reading the char (frontLineNumber).
37 * The lineNumber after reading the char (rearLineNumber) can be calculated:
38 * If the char is \n, rearLineNumber is frontLineNumber + 1.
39 * If the char is not, rearLineNumber is the same as frontLineNumber. */
40 unsigned long lineNumber;
41 } uugcChar;
42
43
44 static ptrArray *uugcInputFile;
45 static uugcChar *uugcCurrentChar;
46 static objPool *uugcCharPool;
47
48 static struct sUwiStats uwiStats;
49
deleteChar(void * c)50 static void deleteChar (void *c)
51 {
52 eFree (c);
53 }
54
newChar(void * data CTAGS_ATTR_UNUSED)55 static void* newChar (void *data CTAGS_ATTR_UNUSED)
56 {
57 return xMalloc (1, uugcChar);
58 }
59
uugcDeleteC(uugcChar * c)60 CTAGS_INLINE void uugcDeleteC (uugcChar *c)
61 {
62 if (c == uugcCurrentChar)
63 uugcCurrentChar = NULL;
64
65 objPoolPut (uugcCharPool, c);
66 }
67
uugcActivate(void)68 static void uugcActivate (void)
69 {
70 Assert (!uugcInputFile);
71 Assert (!uugcCurrentChar);
72
73 if (uugcCharPool == NULL)
74 {
75 uugcCharPool = objPoolNew(256,
76 newChar,
77 deleteChar,
78 NULL,
79 NULL);
80 DEFAULT_TRASH_BOX(uugcCharPool, objPoolDelete);
81 }
82
83 uugcInputFile = ptrArrayNew ((ptrArrayDeleteFunc)uugcDeleteC);
84 }
85
uugcDeactive(void)86 static void uugcDeactive(void)
87 {
88 Assert (uugcInputFile);
89 ptrArrayDelete (uugcInputFile);
90 uugcInputFile = NULL;
91 uugcCurrentChar = NULL;
92 }
93
uugcNewC(int chr,unsigned long ln)94 CTAGS_INLINE uugcChar *uugcNewC (int chr, unsigned long ln)
95 {
96 Assert (uugcCharPool);
97
98 uugcChar *c = objPoolGet (uugcCharPool);
99 c->c = chr;
100 c->lineNumber = ln;
101 return c;
102 }
103
uugciGetC(void)104 CTAGS_INLINE uugcChar *uugciGetC (void)
105 {
106 uugcChar *c;
107
108 Assert (uugcInputFile);
109
110 if (ptrArrayCount (uugcInputFile) > 0)
111 {
112 c = ptrArrayLast (uugcInputFile);
113 ptrArrayRemoveLast (uugcInputFile);
114 }
115 else
116 {
117 unsigned long lineNumber = getInputLineNumber ();
118 int chr = getcFromInputFile();
119 c = uugcNewC (chr, lineNumber);
120 }
121
122 uugcCurrentChar = c;
123 return uugcCurrentChar;
124 }
125
uugcUngetC(uugcChar * c)126 CTAGS_INLINE void uugcUngetC (uugcChar *c)
127 {
128 uugcCurrentChar = NULL;
129
130 if (c->c == EOF)
131 {
132 ptrArrayClear (uugcInputFile);
133 uugcDeleteC (c);
134 return;
135 }
136
137 ptrArrayAdd (uugcInputFile, c);
138 }
139
uugcInjectC(int chr)140 CTAGS_INLINE void uugcInjectC (int chr)
141 {
142 if (chr == EOF)
143 return;
144
145 uugcChar *lastc = NULL;
146 if (ptrArrayCount (uugcInputFile) > 0)
147 lastc = ptrArrayLast (uugcInputFile);
148
149 unsigned long lineNumber;
150 if (lastc)
151 {
152 if (chr == '\n' && lastc->lineNumber > 0)
153 lineNumber = lastc->lineNumber - 1;
154 else
155 lineNumber = lastc->lineNumber;
156 }
157 else
158 {
159 lineNumber = getInputLineNumber ();
160 if (chr == '\n')
161 lineNumber--;
162 }
163
164 uugcChar *c = uugcNewC(chr, lineNumber);
165 uugcUngetC (c);
166 }
167
uugcGetLineNumber()168 CTAGS_INLINE long uugcGetLineNumber ()
169 {
170 Assert (uugcInputFile);
171
172 if (uugcCurrentChar)
173 {
174 unsigned long ln;
175 if (uugcCurrentChar->c == '\n')
176 ln = uugcCurrentChar->lineNumber + 1;
177 else
178 ln = uugcCurrentChar->lineNumber;
179 return ln;
180 }
181 else if (ptrArrayCount (uugcInputFile) > 0)
182 {
183 uugcChar *c = ptrArrayLast (uugcInputFile);
184 return c->lineNumber;
185 }
186 else
187 return getInputLineNumber ();
188 }
189
uugcGetFilePosition(void)190 CTAGS_INLINE MIOPos uugcGetFilePosition (void)
191 {
192 if (uugcCurrentChar)
193 {
194 unsigned long ln;
195 if (uugcCurrentChar->c == '\n')
196 ln = uugcCurrentChar->lineNumber + 1;
197 else
198 ln = uugcCurrentChar->lineNumber;
199 return getInputFilePositionForLine (ln);
200 }
201 else if (ptrArrayCount (uugcInputFile) > 0)
202 {
203 uugcChar *c = ptrArrayLast (uugcInputFile);
204 return getInputFilePositionForLine (c->lineNumber);
205 }
206 else
207 return getInputFilePosition ();
208 }
209
210 static ptrArray *uwiBuffer;
211 static unsigned int *uwiMarkerStack;
212 static unsigned int uwiMarkerStackLength;
213 static unsigned int *uwiCurrentMarker;
214
uwiActivate(unsigned int stackLength)215 extern void uwiActivate (unsigned int stackLength)
216 {
217 Assert (stackLength > 0);
218
219 uugcActivate ();
220 uwiBuffer = ptrArrayNew ((ptrArrayDeleteFunc)uugcDeleteC);
221 uwiMarkerStackLength = stackLength;
222 uwiMarkerStack = xMalloc (stackLength, unsigned int);
223 uwiCurrentMarker = NULL;
224
225 uwiStatsInit (&uwiStats);
226 }
227
uwiDeactivate(struct sUwiStats * statsToBeUpdated)228 extern void uwiDeactivate (struct sUwiStats *statsToBeUpdated)
229 {
230 Assert (uwiBuffer);
231 Assert (uwiMarkerStack);
232
233 if (statsToBeUpdated)
234 {
235 if (statsToBeUpdated->maxLength < uwiStats.maxLength)
236 statsToBeUpdated->maxLength = uwiStats.maxLength;
237 if (!statsToBeUpdated->overflow)
238 statsToBeUpdated->overflow = uwiStats.overflow;
239 if (!statsToBeUpdated->underflow)
240 statsToBeUpdated->underflow = uwiStats.underflow;
241 }
242
243 ptrArrayDelete (uwiBuffer);
244 eFree (uwiMarkerStack);
245 uwiBuffer = NULL;
246 uwiMarkerStack = NULL;
247 uwiMarkerStackLength = 0;
248 uugcDeactive();
249 }
250
uwiGetC()251 extern int uwiGetC ()
252 {
253 int c;
254 uugcChar *chr = uugciGetC ();
255
256 c = chr->c;
257
258 if (uwiCurrentMarker)
259 {
260 *uwiCurrentMarker += 1;
261 ptrArrayAdd (uwiBuffer, chr);
262 }
263 else
264 {
265 uugcCurrentChar = NULL;
266 uugcDeleteC (chr);
267 }
268
269 return c;
270 }
271
uwiUngetC(int c)272 extern void uwiUngetC (int c)
273 {
274 Assert (!uwiCurrentMarker);
275 uugcInjectC (c);
276 }
277
uwiGetLineNumber(void)278 extern unsigned long uwiGetLineNumber (void)
279 {
280 return uugcGetLineNumber ();
281 }
282
uwiGetFilePosition(void)283 extern MIOPos uwiGetFilePosition (void)
284 {
285 return uugcGetFilePosition ();
286 }
287
uwiPushMarker(void)288 extern void uwiPushMarker (void)
289 {
290
291 if (uwiStats.maxLength < (uwiCurrentMarker - uwiMarkerStack) + 1)
292 uwiStats.maxLength = (uwiCurrentMarker - uwiMarkerStack) + 1;
293
294 if (uwiCurrentMarker - uwiMarkerStack >= ( uwiMarkerStackLength - 1 )) {
295 error (WARNING,
296 "trying to add too many markers during parsing: %s "
297 "(this is a bug, please consider filing an issue)", getInputFileName());
298 uwiCurrentMarker = NULL;
299 uwiStats.overflow = true;
300 }
301
302 if (uwiCurrentMarker) uwiCurrentMarker++;
303 else uwiCurrentMarker = uwiMarkerStack;
304
305 *uwiCurrentMarker = 0;
306 }
307
uwiPopMarker(const int upto,const bool revertChars)308 extern void uwiPopMarker (const int upto, const bool revertChars)
309 {
310 if (uwiCurrentMarker - uwiMarkerStack < 0) {
311 error (WARNING,
312 "trying to drop too many markers during parsing: %s "
313 "(this is a bug, please consider filing an issue)", getInputFileName());
314
315 uwiCurrentMarker = NULL;
316 uwiStats.underflow = true;
317 return;
318 }
319
320 uwiClearMarker (upto, revertChars);
321
322 if (uwiCurrentMarker == uwiMarkerStack) uwiCurrentMarker = NULL;
323 else uwiCurrentMarker--;
324 }
325
uwiClearMarker(const int upto,const bool revertChars)326 extern void uwiClearMarker (const int upto, const bool revertChars)
327 {
328 Assert (uwiCurrentMarker);
329 int count = (upto <= 0)? *uwiCurrentMarker : upto;
330 void (*charHandler)(uugcChar *) = revertChars ? uugcUngetC : uugcDeleteC;
331
332 while (count-- > 0)
333 {
334 charHandler (ptrArrayLast (uwiBuffer));
335 ptrArrayRemoveLast (uwiBuffer);
336 *uwiCurrentMarker -= 1;
337 }
338 }
339
uwiDropMaker()340 extern void uwiDropMaker ()
341 {
342 uwiPopMarker (0, false);
343 }
344
uwiStatsInit(struct sUwiStats * stats)345 extern void uwiStatsInit (struct sUwiStats *stats)
346 {
347 memset (stats, 0, sizeof (*stats));
348 }
349
uwiStatsPrint(struct sUwiStats * stats)350 extern void uwiStatsPrint (struct sUwiStats *stats)
351 {
352 fprintf(stderr, "Unwinding the longest input stream stack usage: %d\n",
353 stats->maxLength);
354 fprintf(stderr, "Unwinding input stream stack overflow incidence: %s\n",
355 stats->overflow? "yes": "no");
356 fprintf(stderr, "Unwinding input stream stack underflow incidence: %s\n",
357 stats->underflow? "yes": "no");
358 }
359