xref: /Universal-ctags/main/promise.c (revision 5066e2feadfa1f2d1826125a60095f6246895369)
1 /*
2  *
3  *  Copyright (c) 2016, Red Hat, Inc.
4  *  Copyright (c) 2016, 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  */
12 
13 #include "general.h"
14 #include "parse_p.h"
15 #include "promise.h"
16 #include "promise_p.h"
17 #include "ptrarray.h"
18 #include "debug.h"
19 #include "read_p.h"
20 #include "trashbox.h"
21 #include "xtag.h"
22 #include "numarray.h"
23 #include "routines.h"
24 #include "options.h"
25 
26 #include <string.h>
27 
28 struct promise {
29 	langType lang;
30 	unsigned long startLine;
31 	long startCharOffset;
32 	unsigned long endLine;
33 	long endCharOffset;
34 	unsigned long sourceLineOffset;
35 	int parent_promise;
36 	ptrArray *modifiers;
37 };
38 
39 typedef void ( *promiseInputModifier) (unsigned char * input,
40 									   size_t size,
41 									   unsigned long startLine, long startCharOffset,
42 									   unsigned long endLine, long endCharOffset,
43 									   void *data);
44 typedef void ( *promiseDestroyAttachedData) (void *data);
45 
46 struct modifier {
47 	promiseInputModifier modifier;
48 	promiseDestroyAttachedData destroyData;
49 	void *data;
50 };
51 
52 static struct promise *promises;
53 static int promise_count;
54 static int promise_allocated;
55 
56 #define NO_PROMISE -1
57 static int current_promise = NO_PROMISE;
58 
59 static void attachPromiseModifier (int promise,
60 								   promiseInputModifier modifier,
61 								   promiseDestroyAttachedData destroyData,
62 								   void *data);
63 
64 
makePromise(const char * parser,unsigned long startLine,long startCharOffset,unsigned long endLine,long endCharOffset,unsigned long sourceLineOffset)65 int  makePromise   (const char *parser,
66 		    unsigned long startLine, long startCharOffset,
67 		    unsigned long endLine, long endCharOffset,
68 		    unsigned long sourceLineOffset)
69 {
70 	struct promise *p;
71 	int r;
72 	langType lang = LANG_IGNORE;
73 
74 	verbose("makePromise: %s start(line: %lu, offset: %lu, srcline: %lu), end(line: %lu, offset: %lu)\n",
75 			parser? parser: "*", startLine, startCharOffset, sourceLineOffset,
76 			endLine, endCharOffset);
77 
78 	if ((!isThinStreamSpec(startLine,
79 						   startCharOffset,
80 						   endLine,
81 						   endCharOffset,
82 						   sourceLineOffset))
83 		&& ( !isXtagEnabled (XTAG_GUEST)))
84 		return -1;
85 
86 	if (parser)
87 	{
88 		lang = getNamedLanguage (parser, 0);
89 		if (lang == LANG_IGNORE)
90 			return -1;
91 	}
92 
93 	if ( promise_count == promise_allocated)
94 	{
95 		size_t c = promise_allocated? (promise_allocated * 2): 8;
96 		if (promises)
97 			DEFAULT_TRASH_BOX_TAKE_BACK(promises);
98 		promises = xRealloc (promises, c, struct promise);
99 		DEFAULT_TRASH_BOX(promises, eFree);
100 		promise_allocated = c;
101 	}
102 
103 	p = promises + promise_count;
104 	p->parent_promise = current_promise;
105 	p->lang = lang;
106 	p->startLine = startLine;
107 	p->startCharOffset = startCharOffset;
108 	p->endLine = endLine;
109 	p->endCharOffset = endCharOffset;
110 	p->sourceLineOffset = sourceLineOffset;
111 	p->modifiers = NULL;
112 
113 	r = promise_count;
114 	promise_count++;
115 	return r;
116 }
117 
freeModifier(void * data)118 static void freeModifier (void *data)
119 {
120 	struct modifier *m = data;
121 	m->destroyData(m->data);
122 	eFree (m);
123 }
124 
attachPromiseModifier(int promise,promiseInputModifier modifier,promiseDestroyAttachedData destroyData,void * data)125 static void attachPromiseModifier (int promise,
126 								   promiseInputModifier modifier,
127 								   promiseDestroyAttachedData destroyData,
128 								   void *data)
129 {
130 	struct modifier *m = xMalloc (1, struct modifier);
131 
132 	m->modifier = modifier;
133 	m->destroyData = destroyData;
134 	m->data = data;
135 
136 	struct promise *p = promises + promise;
137 	if (!p->modifiers)
138 		p->modifiers = ptrArrayNew(freeModifier);
139 
140 	ptrArrayAdd (p->modifiers, m);
141 }
142 
freeModifiers(int promise)143 static void freeModifiers(int promise)
144 {
145 	for (int i = promise; i < promise_count; i++)
146 	{
147 		struct promise *p = promises + promise;
148 		if (p->modifiers)
149 		{
150 			ptrArrayDelete (p->modifiers);
151 			p->modifiers = NULL;
152 		}
153 	}
154 }
155 
breakPromisesAfter(int promise)156 void breakPromisesAfter (int promise)
157 {
158 	Assert (promise_count >= promise);
159 	if (promise == NO_PROMISE)
160 		promise = 0;
161 
162 	freeModifiers(promise);
163 	promise_count = promise;
164 }
165 
forcePromises(void)166 bool forcePromises (void)
167 {
168 	int i;
169 	bool tagFileResized = false;
170 
171 	for (i = 0; i < promise_count; ++i)
172 	{
173 		current_promise = i;
174 		struct promise *p = promises + i;
175 
176 		if (p->lang != LANG_IGNORE && isLanguageEnabled (p->lang))
177 			tagFileResized = runParserInNarrowedInputStream (p->lang,
178 															 p->startLine,
179 															 p->startCharOffset,
180 															 p->endLine,
181 															 p->endCharOffset,
182 															 p->sourceLineOffset,
183 															 i)
184 				? true
185 				: tagFileResized;
186 	}
187 
188 	freeModifiers (0);
189 	current_promise  = NO_PROMISE;
190 	promise_count = 0;
191 	return tagFileResized;
192 }
193 
194 
getLastPromise(void)195 int getLastPromise (void)
196 {
197 	return promise_count - 1;
198 }
199 
fill_or_skip(unsigned char * input,unsigned char * input_end,bool filling)200 static unsigned char* fill_or_skip (unsigned char *input, unsigned char *input_end, bool filling)
201 {
202 	if ( !(input < input_end))
203 		return NULL;
204 
205 	unsigned char *next = memchr(input, '\n', input_end - input);
206 	if (next)
207 	{
208 		if (filling)
209 			memset(input, ' ', next - input);
210 		input = next + 1;
211 		if (input == input_end)
212 			return NULL;
213 		else
214 			return input;
215 	}
216 	else
217 	{
218 		if (filling)
219 			memset(input, ' ', input_end - input);
220 		return NULL;
221 	}
222 }
223 
line_filler(unsigned char * input,size_t size,unsigned long startLine,long startCharOffset,unsigned long endLine,long endCharOffset,void * data)224 static void line_filler (unsigned char *input, size_t size,
225 						 unsigned long startLine, long startCharOffset,
226 						 unsigned long endLine, long endCharOffset,
227 						 void *data)
228 {
229 	ulongArray *lines = data;
230 	unsigned int start_index, end_index;
231 	unsigned int i;
232 
233 	for (i = 0; i < ulongArrayCount (lines); i++)
234 	{
235 		unsigned long line = ulongArrayItem (lines, i);
236 		if (line >= startLine)
237 			break;
238 	}
239 	if (i == ulongArrayCount (lines))
240 		return;
241 	if (i > endLine)
242 		return;
243 	start_index = i;
244 
245 	for (; i < ulongArrayCount (lines); i++)
246 	{
247 		unsigned long line = ulongArrayItem (lines, i);
248 		if (line > endLine)
249 			break;
250 	}
251 	end_index = i;
252 
253 	unsigned long input_line = startLine;
254 	for (i = start_index; i < end_index; i++)
255 	{
256 		unsigned long line = ulongArrayItem (lines, i);
257 
258 		while (1)
259 		{
260 			if (input_line == line)
261 			{
262 				input = fill_or_skip (input, input + size, true);
263 				input_line++;
264 				break;
265 			}
266 			else
267 			{
268 				input = fill_or_skip (input, input + size, false);
269 				input_line++;
270 			}
271 		}
272 	}
273 }
274 
promiseAttachLineFiller(int promise,ulongArray * lines)275 void promiseAttachLineFiller (int promise, ulongArray *lines)
276 {
277 	attachPromiseModifier (promise, line_filler,
278 						   (promiseDestroyAttachedData)ulongArrayDelete,
279 						   lines);
280 }
281 
282 
collectModifiers(int promise,ptrArray * modifiers)283 static void collectModifiers(int promise, ptrArray *modifiers)
284 {
285 	while (promise != NO_PROMISE)
286 	{
287 		struct promise *p = promises + promise;
288 		if (p->modifiers)
289 		{
290 			for (int i = ptrArrayCount(p->modifiers); i > 0; i--)
291 			{
292 				struct modifier *m = ptrArrayItem(p->modifiers, i - 1);
293 				ptrArrayAdd (modifiers, m);
294 			}
295 		}
296 		promise = p->parent_promise;
297 	}
298 }
299 
runModifiers(int promise,unsigned long startLine,long startCharOffset,unsigned long endLine,long endCharOffset,unsigned char * input,size_t size)300 void runModifiers (int promise,
301 				   unsigned long startLine, long startCharOffset,
302 				   unsigned long endLine, long endCharOffset,
303 				   unsigned char *input,
304 				   size_t size)
305 {
306 	ptrArray *modifiers = ptrArrayNew (NULL);
307 
308 	collectModifiers (promise, modifiers);
309 	for (int i = ptrArrayCount (modifiers); i > 0 ; i--)
310 	{
311 		struct modifier *m = ptrArrayItem (modifiers, i - 1);
312 		m->modifier (input, size,
313 					 startLine, startCharOffset,
314 					 endLine, endCharOffset,
315 					 m->data);
316 	}
317 	ptrArrayDelete (modifiers);
318 }
319 
promiseUpdateLanguage(int promise,langType lang)320 void promiseUpdateLanguage  (int promise, langType lang)
321 {
322 	Assert (promise >= 0);
323 
324 	struct promise *p = promises + promise;
325 
326 	p->lang = lang;
327 }
328