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