1 /* Automatically generated by Ragel from "ragel_xmlscanner.c".
3 * Parts of this file are copied from Ragel source covered by the GNU
4 * GPL. As a special exception, you may use the parts of this file copied
5 * from Ragel source without restriction. The remainder is derived from
6 * "ragel_xmlscanner.c" and inherits the copyright status of that file.
9 # 1 "ragel_xmlscanner.c"
12 * This is an input file for the "Ragel" finite state machine compiler utility.
13 * It produces output code which implements a tag scanner for XML data.
14 * It is used for intelligent xml tag completion in an XML editor interface.
16 * See the Ragel online documentation for additional
17 * information about the format of this file.
19 * Written by Marc Liyanage <http://www.entropy.ch>
24 #include "ragel_xmlscanner.h"
27 /* modes for the scan, before or after cursor position */
34 # 35 "ragel_xmlscanner_out.c"
35 /* Forward dec state for the transition structure. */
36 struct XMLScannerStateStruct;
38 /* Only non-static data: current state, acceptance indicator. */
39 struct XMLScannerStruct
43 # 26 "ragel_xmlscanner.c"
46 char *stack[STACKDEPTH];
47 char *stack_e[STACKDEPTH];
61 # 62 "ragel_xmlscanner_out.c"
63 typedef struct XMLScannerStruct XMLScanner;
66 void XMLScannerInit( XMLScanner *fsm );
68 /* Execute some chunk of data. */
69 void XMLScannerExecute( XMLScanner *fsm, char *data, int dlen );
71 /* Indicate to the fsm tha there is no more data. */
72 void XMLScannerFinish( XMLScanner *fsm );
74 /* Did the machine accept? */
75 int XMLScannerAccept( XMLScanner *fsm );
77 # 43 "ragel_xmlscanner.c"
82 void checkETag(XMLScanner *fsm);
83 void popTag(XMLScanner *fsm);
84 void pushTag(XMLScanner *fsm);
86 # 87 "ragel_xmlscanner_out.c"
87 #define f XMLScanner_f
88 #define s XMLScanner_s
89 #define k XMLScanner_k
90 #define i XMLScanner_i
91 #define t XMLScanner_t
93 #define SPEC_ANY_FLAT 0x01
94 #define SPEC_ANY_SINGLE 0x02
95 #define SPEC_ANY_RANGE 0x04
96 #define SPEC_ANY_DEF 0x08
97 #define SPEC_IS_FINAL 0x10
98 #define SPEC_OUT_FUNC 0x20
100 /* The array of functions. */
101 static int XMLScanner_f[] = {
102 1, 0, 1, 1, 1, 2, 1, 3,
103 1, 4, 1, 5, 1, 9, 1, 10,
104 2, 1, 1, 2, 3, 3, 2, 4,
105 4, 2, 5, 7, 2, 5, 8, 2,
106 11, 11, 2, 12, 13, 3, 10, 11,
107 11, 4, 4, 4, 9, 4, 4, 12,
108 13, 12, 13, 6, 12, 13, 11, 12,
112 /* The array of keys of transitions. */
113 static char XMLScanner_k[] = {
114 45, 45, 45, 45, 45, 62, 45, 60,
115 45, 45, 62, 60, 67, 68, 65, 84,
116 65, 91, 91, 93, 93, 93, 62, 93,
117 60, 93, 93, 62, 93, 60, 60, 62,
118 60, 32, 47, 58, 62, 95, 9, 13,
119 65, 90, 97, 122, 32, 45, 46, 47,
120 58, 62, 95, 9, 13, 48, 57, 65,
121 90, 97, 122, 32, 45, 46, 47, 58,
122 62, 95, 9, 13, 48, 57, 65, 90,
123 97, 122, 32, 45, 46, 47, 58, 61,
124 62, 95, 9, 13, 48, 57, 65, 90,
125 97, 122, 32, 45, 46, 47, 58, 61,
126 62, 95, 9, 13, 48, 57, 65, 90,
127 97, 122, 32, 45, 46, 47, 58, 62,
128 95, 9, 13, 48, 57, 65, 90, 97,
129 122, 32, 45, 46, 47, 58, 61, 62,
130 95, 9, 13, 48, 57, 65, 90, 97,
131 122, 45, 46, 58, 61, 95, 48, 57,
132 65, 90, 97, 122, 45, 46, 58, 61,
133 95, 48, 57, 65, 90, 97, 122, 45,
134 46, 58, 61, 95, 48, 57, 65, 90,
135 97, 122, 32, 45, 46, 47, 58, 61,
136 62, 95, 9, 13, 48, 57, 65, 90,
137 97, 122, 32, 45, 46, 47, 58, 61,
138 62, 95, 9, 13, 48, 57, 65, 90,
139 97, 122, 32, 45, 46, 47, 58, 61,
140 62, 95, 9, 13, 48, 57, 65, 90,
141 97, 122, 34, 39, 32, 45, 46, 47,
142 58, 61, 62, 95, 9, 13, 48, 57,
143 65, 90, 97, 122, 32, 45, 46, 47,
144 58, 61, 62, 95, 9, 13, 48, 57,
145 65, 90, 97, 122, 32, 45, 46, 47,
146 58, 61, 62, 95, 9, 13, 48, 57,
147 65, 90, 97, 122, 45, 46, 58, 61,
148 95, 48, 57, 65, 90, 97, 122, 45,
149 46, 58, 61, 95, 48, 57, 65, 90,
150 97, 122, 45, 46, 58, 61, 95, 48,
151 57, 65, 90, 97, 122, 45, 46, 58,
152 61, 95, 48, 57, 65, 90, 97, 122,
153 45, 46, 58, 61, 95, 48, 57, 65,
154 90, 97, 122, 45, 46, 58, 61, 95,
155 48, 57, 65, 90, 97, 122, 34, 39,
156 32, 47, 58, 62, 95, 9, 13, 65,
157 90, 97, 122, 34, 32, 47, 58, 62,
158 95, 9, 13, 65, 90, 97, 122, 39,
159 45, 46, 58, 62, 95, 48, 57, 65,
160 90, 97, 122, 45, 46, 58, 62, 95,
161 48, 57, 65, 90, 97, 122, 45, 46,
162 58, 62, 95, 48, 57, 65, 90, 97,
163 122, 45, 46, 58, 62, 95, 48, 57,
164 65, 90, 97, 122, 45, 46, 58, 62,
165 95, 48, 57, 65, 90, 97, 122, 45,
166 46, 58, 62, 95, 48, 57, 65, 90,
167 97, 122, 45, 46, 58, 62, 95, 48,
168 57, 65, 90, 97, 122, 45, 46, 58,
169 62, 95, 48, 57, 65, 90, 97, 122,
170 45, 46, 58, 62, 95, 48, 57, 65,
171 90, 97, 122, 60, 33, 47, 58, 60,
172 95, 65, 90, 97, 122, 60, 60, 45,
173 60, 91, 58, 60, 95, 65, 90, 97,
174 122, 32, 45, 46, 47, 58, 60, 62,
175 95, 9, 13, 48, 57, 65, 90, 97,
176 122, 32, 45, 46, 47, 58, 60, 62,
177 95, 9, 13, 48, 57, 65, 90, 97,
178 122, 32, 45, 46, 47, 58, 60, 62,
179 95, 9, 13, 48, 57, 65, 90, 97,
183 /* The array of indicies into the transition array. */
184 static unsigned char XMLScanner_i[] = {
185 1, 2, 3, 4, 5, 6, 5, 6,
186 7, 5, 8, 9, 8, 10, 5, 6,
187 11, 5, 12, 13, 14, 15, 16, 17,
188 18, 19, 20, 21, 22, 23, 24, 25,
189 24, 26, 25, 24, 27, 28, 28, 29,
190 24, 30, 25, 24, 31, 32, 33, 34,
191 35, 36, 37, 38, 39, 40, 41, 42,
192 38, 43, 43, 44, 45, 46, 39, 47,
193 48, 49, 44, 50, 51, 51, 44, 45,
194 46, 39, 47, 48, 49, 44, 50, 51,
195 51, 44, 52, 53, 39, 54, 55, 48,
196 56, 44, 57, 58, 58, 44, 52, 53,
197 39, 54, 55, 48, 56, 44, 57, 58,
198 58, 44, 45, 46, 39, 47, 48, 49,
199 44, 50, 51, 51, 44, 52, 53, 39,
200 54, 55, 48, 56, 44, 57, 58, 58,
201 59, 60, 61, 55, 62, 63, 64, 64,
202 59, 60, 61, 55, 62, 63, 64, 64,
203 59, 60, 61, 55, 62, 63, 64, 64,
204 44, 52, 53, 39, 54, 55, 48, 56,
205 44, 57, 58, 58, 44, 52, 53, 39,
206 54, 55, 48, 56, 44, 57, 58, 58,
207 44, 52, 53, 39, 54, 55, 48, 56,
208 44, 57, 58, 58, 65, 66, 44, 52,
209 53, 39, 54, 55, 48, 56, 44, 57,
210 58, 58, 44, 52, 53, 39, 54, 55,
211 48, 56, 44, 57, 58, 58, 44, 52,
212 53, 39, 54, 55, 48, 56, 44, 57,
213 58, 58, 59, 60, 61, 55, 62, 63,
214 64, 64, 59, 60, 61, 55, 62, 63,
215 64, 64, 59, 60, 61, 55, 62, 63,
216 64, 64, 59, 60, 61, 55, 62, 63,
217 64, 64, 59, 60, 61, 55, 62, 63,
218 64, 64, 59, 60, 61, 55, 62, 63,
219 64, 64, 67, 68, 69, 70, 71, 72,
220 73, 74, 75, 71, 76, 76, 67, 68,
221 71, 72, 73, 74, 75, 71, 76, 76,
222 69, 70, 77, 78, 79, 80, 81, 82,
223 83, 83, 77, 78, 79, 80, 81, 82,
224 83, 83, 77, 78, 79, 80, 81, 82,
225 83, 83, 77, 78, 79, 80, 81, 82,
226 83, 83, 77, 78, 79, 80, 81, 82,
227 83, 83, 77, 78, 79, 80, 81, 82,
228 83, 83, 77, 78, 79, 80, 81, 82,
229 83, 83, 77, 78, 79, 80, 81, 82,
230 83, 83, 77, 78, 79, 80, 81, 82,
231 83, 83, 84, 85, 86, 87, 88, 89,
232 90, 91, 91, 92, 93, 94, 93, 94,
233 95, 93, 96, 94, 97, 93, 98, 99,
234 99, 94, 44, 45, 46, 39, 47, 93,
235 48, 49, 44, 50, 51, 51, 94, 44,
236 45, 46, 39, 47, 93, 48, 49, 44,
237 50, 51, 51, 94, 44, 45, 46, 39,
238 47, 93, 48, 49, 44, 50, 51, 51,
242 /* The aray of states. */
243 static int XMLScanner_s[] = {
244 768, 0, 0, 1026, 0, 0, 1, 1034,
245 1, 1, 1, 1034, 2, 3, 1, 1034,
246 3, 5, 1, 1034, 4, 7, 2, 1338,
247 6, 10, 2, 2, 1034, 8, 13, 1,
248 1034, 9, 15, 2, 1338, 11, 18, 1,
249 16, 1026, 12, 20, 1, 1026, 13, 21,
250 1, 1026, 14, 22, 1, 1026, 15, 23,
251 1, 1026, 16, 24, 1, 1026, 17, 25,
252 1, 1026, 18, 26, 1, 1034, 19, 27,
253 1, 1034, 20, 29, 1, 1034, 21, 31,
254 1, 1034, 22, 33, 2, 1338, 24, 36,
255 2, 6, 1034, 26, 39, 1, 1034, 27,
256 41, 2, 1338, 29, 44, 1, 19, 1338,
257 30, 46, 1, 25, 1026, 31, 48, 1,
258 1338, 32, 49, 1, 10, 1286, 33, 51,
259 5, 3, 1286, 44, 59, 7, 4, 1286,
260 59, 70, 7, 4, 1286, 74, 81, 8,
261 4, 1286, 90, 93, 8, 4, 1286, 106,
262 105, 7, 4, 1286, 121, 116, 8, 4,
263 1286, 137, 128, 5, 3, 1286, 148, 136,
264 5, 3, 1286, 159, 144, 5, 3, 1286,
265 170, 152, 8, 4, 1286, 186, 164, 8,
266 4, 1286, 202, 176, 8, 4, 1026, 218,
267 188, 2, 1286, 220, 190, 8, 4, 1286,
268 236, 202, 8, 4, 1286, 252, 214, 8,
269 4, 1286, 268, 226, 5, 3, 1286, 279,
270 234, 5, 3, 1286, 290, 242, 5, 3,
271 1286, 301, 250, 5, 3, 1286, 312, 258,
272 5, 3, 1286, 323, 266, 5, 3, 1034,
273 334, 274, 1, 1034, 335, 276, 1, 1286,
274 336, 278, 5, 3, 1034, 347, 286, 1,
275 1286, 348, 288, 5, 3, 1034, 359, 296,
276 1, 1286, 360, 298, 5, 3, 1286, 371,
277 306, 5, 3, 1286, 382, 314, 5, 3,
278 1286, 393, 322, 5, 3, 1286, 404, 330,
279 5, 3, 1286, 415, 338, 5, 3, 1286,
280 426, 346, 5, 3, 1286, 437, 354, 5,
281 3, 1286, 448, 362, 5, 3, 1338, 459,
282 370, 1, 28, 1598, 460, 372, 5, 2,
283 8, 1050, 469, 380, 1, 1050, 470, 382,
284 1, 1050, 471, 384, 3, 1310, 474, 388,
285 3, 2, 1310, 481, 394, 8, 4, 1310,
286 497, 407, 8, 4, 1310, 513, 420, 8,
290 /* The array of transitions. */
291 static int *XMLScanner_t[] = {
292 0, 0, s+7, 0, s+28, f+0, s+11, f+0,
293 s+15, 0, s+11, 0, s+19, 0, s+23, 0,
294 s+313, f+2, s+307, f+2, s+32, 0, s+36, 0,
295 s+307, f+16, s+313, f+16, s+45, 0, s+49, 0,
296 s+53, 0, s+57, 0, s+61, 0, s+65, 0,
297 s+69, 0, s+90, f+4, s+73, f+4, s+77, 0,
298 s+73, 0, s+81, 0, s+85, 0, s+307, f+6,
299 s+313, f+6, s+94, 0, s+98, 0, s+307, f+19,
300 s+313, f+19, s+307, f+25, s+313, f+25, s+112, 0,
301 s+307, f+10, s+313, f+10, s+117, 0, s+108, 0,
302 s+152, f+31, s+103, 0, s+157, f+31, s+162, f+31,
303 s+117, f+14, s+122, 0, s+127, 0, s+132, f+37,
304 s+103, f+14, s+137, f+37, s+142, 0, s+147, f+37,
305 s+167, 0, s+172, 0, s+177, f+37, s+182, 0,
306 s+186, f+37, s+191, 0, s+196, f+37, s+201, 0,
307 s+206, 0, s+211, 0, s+216, 0, s+221, 0,
308 s+226, 0, s+231, 0, s+235, 0, s+239, 0,
309 s+244, 0, s+248, 0, s+253, 0, s+117, f+46,
310 s+108, f+34, s+152, f+51, s+103, f+34, s+157, f+51,
311 s+162, f+51, s+287, 0, s+282, 0, s+297, 0,
312 s+302, f+14, s+292, 0, s+277, 0, s+272, 0,
313 s+307, f+28, s+313, f+28, s+321, f+8, s+325, f+22,
314 s+330, f+41, s+307, f+8, s+335, f+41, s+340, f+41,
315 s+313, f+8, s+307, 0, s+313, 0, s+3, 0,
316 s+41, 0, s+267, f+12, s+262, f+12, s+257, f+12,
320 /* The start state. */
321 static int *XMLScanner_start = s+317;
323 /* Init the fsm to a runnable state. */
324 void XMLScannerInit( XMLScanner *fsm )
326 fsm->curState = XMLScanner_start;
328 # 53 "ragel_xmlscanner.c"
337 # 338 "ragel_xmlscanner_out.c"
340 /* Did the fsm accept? */
341 int XMLScannerAccept( XMLScanner *fsm )
346 /* Binary search an array of keys looking for a key. */
347 static char *XMLScannerBSearch( char c, char *keys, int len )
351 char *upper = keys + len - 1;
356 /* Find the midpoint. */
357 mid = lower + ((upper-lower) >> 1);
368 /* Binary search an array of keys looking for a key. */
369 static char *XMLScannerRangeBSearch( char c, char *keys, int len )
373 char *upper = keys + len - 2;
378 /* Find the midpoint. Be sure to settle on the
379 * lower end of a range. */
380 mid = lower + (((upper-lower) >> 1) & ~1);
384 else if ( c > mid[1] )
387 /* The key was found in the range mid, return it. */
393 /* Execute the fsm on some chunk of data. */
394 void XMLScannerExecute( XMLScanner *fsm, char *data, int dlen )
398 int *cs = fsm->curState;
399 int specs, **trans, *funcs, nfuncs;
407 if ( cs == 0 || len == 0 )
410 /* Get required data. */
415 /* Try flat index. */
416 if ( specs & SPEC_ANY_FLAT ) {
422 /* Try binary search single. */
423 if ( specs & SPEC_ANY_SINGLE ) {
424 /* Try to find the key. */
426 char *match = XMLScannerBSearch( *p, keys, indsLen );
429 trans = t + (inds[match - keys]<<1);
433 /* Advance over the keys and indicies. */
438 /* Try binary search range. */
439 if ( specs & SPEC_ANY_RANGE ) {
440 /* Try to find the key. */
442 char *match = XMLScannerRangeBSearch( *p, keys, (indsLen<<1) );
445 trans = t + (inds[(match - keys)>>1]<<1);
449 /* Advance over the keys and indicies. */
450 keys += (indsLen<<1);
454 /* Try the default transition. */
455 if ( specs & SPEC_ANY_DEF ) {
456 trans = t + ((*inds)<<1);
465 /* Move to the new state. */
468 /* Check for functions. */
469 if ( (funcs=*trans) == 0 )
474 while ( nfuncs-- > 0 ) {
475 switch ( *funcs++ ) {
477 # 63 "ragel_xmlscanner.c"
479 DEBUG && fprintf(stderr, "commentstart: %d %c\n", p - data, *p);
483 # 68 "ragel_xmlscanner.c"
485 DEBUG && fprintf(stderr, "commentend: %d %c\n", p - data, *p);
490 # 74 "ragel_xmlscanner.c"
495 # 78 "ragel_xmlscanner.c"
501 # 83 "ragel_xmlscanner.c"
503 DEBUG && fprintf(stderr, "enter tag at %d\n", p - data);
507 # 88 "ragel_xmlscanner.c"
509 DEBUG && fprintf(stderr, "exit tag at %d\n", p - data);
513 # 93 "ragel_xmlscanner.c"
515 // fprintf(stderr, "name: %d %c\n", p - data, *p);
518 # 97 "ragel_xmlscanner.c"
520 DEBUG && fprintf(stderr, "stag\n");
524 # 102 "ragel_xmlscanner.c"
526 DEBUG && fprintf(stderr, "stag: start: %d end: %d %c\n", fsm->mark_namestart - data, fsm->mark_nameend - data, *p);
530 # 107 "ragel_xmlscanner.c"
532 DEBUG && fprintf(stderr, "markstart: %d %c\n", p - data, *p);
533 fsm->mark_namestart = p;
536 # 112 "ragel_xmlscanner.c"
538 DEBUG && fprintf(stderr, "markend: %d %c\n", (p - 1) - data, *(p-1));
539 fsm->mark_nameend = p;
542 # 117 "ragel_xmlscanner.c"
544 // fprintf(stderr, "attrstart: %d %c\n", p - data, *p);
545 fsm->mark_attrstart = p;
548 # 122 "ragel_xmlscanner.c"
550 // fprintf(stderr, "attrend: %d %c\n", (p - 1) - data, *(p - 1));
551 fsm->mark_attrend = p;
554 # 128 "ragel_xmlscanner.c"
556 // fprintf(stderr, "attr: start: %d end: %d %c\n", fsm->mark_attrstart - data, fsm->mark_attrend - data, *p);
559 # 132 "ragel_xmlscanner.c"
561 DEBUG && fprintf(stderr, "pi: %d\n", p - data);
563 # 564 "ragel_xmlscanner_out.c"
572 if ( cs != 0 && *cs & SPEC_IS_FINAL ) {
573 /* The machine accepts. */
575 /* If finishing in a final state then execute the
576 * out functions for it. (if any). */
577 if ( *cs & SPEC_OUT_FUNC ) {
578 funcs = f+*(cs + (*cs>>8)-1);
584 /* If we are not in a final state then this
585 * is an error. Move to the error state. */
593 /* Indicate to the fsm that the input is done. Does cleanup tasks. */
594 void XMLScannerFinish( XMLScanner *fsm )
596 XMLScannerExecute( fsm, 0, 0 );
605 #undef SPEC_ANY_SINGLE
606 #undef SPEC_ANY_RANGE
611 # 165 "ragel_xmlscanner.c"
616 * findCompletion does the actual work of driving the state machine
619 * data - pointer to the buffer containing the XML data
620 * len - length of the data to analyze
621 * cursor - logical position of the editing cursor in the data buffer
622 * result - pointer to integer, which will contain a bit field with
623 * additional status information after completion:
627 * - The system builds a stack of tags which are open at the indicated cursor
628 * position in the XML data.
629 * - If completion is possible at that cursor position, the integer
630 * result will be 0. The caller should insert a closing tag for the
631 * topmost tag name on the stack.
632 * - It can use the other elements of the
633 * stack for GUI goodies, like display of a stack of currently open tags
634 * in the editor. However, it should not assume that the tag stack can be
635 * used to close all opening tags. Instead, it should re-evaluate
636 * the document with this routine after the tag has been inserted and the
637 * cursor position might have moved as a result.
639 * - There are a few cases where completion should not be performed, this
640 * will be indicated by the bitfield in the result int parameter:
641 * - ERROR_IN_TAG: The cursor is in the middle of a tag. No useful completion
642 * is possible (maybe look at the prefix and complete
643 * accordingly, sometime in the future...)
644 * - ERROR_IN_COMMENT: The cursor is inside a comment block.
645 * - ERROR_IN_CDATA: The cursor is inside a cdata section.
646 * - ERROR_NO_TAG: There's no unmatched opening tag to the left of the cursor
647 * - ERROR_ALREADY_BALANCED_HERE: The currently open tags to the left of the
648 * cursor are already balanced with an equal amount
649 * of closing tags to the right of the cursor.
653 * Returns a pointer to an array of pointers to chars.
654 * Each array entry contains one tag from the stack
655 * tags open at the cursor position.
658 char (*findCompletion(char *data, int len, int cursor, int *result, int tagpositions[]))[] {
660 XMLScanner scanner, *machine = &scanner;
661 char toptag[MAXTAGLENGTH];
662 unsigned int i, lower, upper, openingcount, closingcount, identical_opening, identical_closing;
664 char (*resultstack)[MAXTAGLENGTH] = NULL;
665 char (*resultstack_e)[MAXTAGLENGTH] = NULL;
669 bzero(toptag, MAXTAGLENGTH);
672 // ------------ analyze data before cursor position ------------------
674 XMLScannerInit(machine);
676 machine->mode = BEFORE;
677 machine->cursor = cursor;
679 XMLScannerExecute(machine, data, cursor);
680 XMLScannerFinish(machine);
683 /* Any unbalanced open tags on the stack at all? If so, allocate memory
684 * and copy the tags over to a newly allocated buffer, into a stack.
687 resultstack = malloc(MAXTAGLENGTH * ((machine->sp/2) + 1));
689 /* Nothing useful to return to caller */
690 *result |= ERROR_NO_TAG;
694 openingcount = (machine->sp / 2);
696 for (i = 0; i < openingcount; i++) {
699 bzero(resultstack[i], MAXTAGLENGTH);
700 strncpy(resultstack[i], machine->stack[lower], machine->stack[upper] - machine->stack[lower]);
702 tagpositions[lower] = machine->stack[lower] - data;
703 tagpositions[upper] = machine->stack[upper] - data;
707 /* make sure the slot after the topmost tag is zeroed out, so the
708 * calling code can use that as an end of stack marker.
710 bzero(resultstack[openingcount], MAXTAGLENGTH);
712 strncpy(toptag, resultstack[openingcount - 1], MAXTAGLENGTH);
715 *result |= ERROR_IN_TAG;
716 if (machine->in_comment)
717 *result |= ERROR_IN_COMMENT;
718 if (machine->in_cdata)
719 *result |= ERROR_IN_CDATA;
725 // count identical opening tags on the top of the stack.
726 identical_opening = 1;
727 for (i = (openingcount - 2); i >= 0; i--) {
728 if (!strcmp(resultstack[i], resultstack[i + 1])) {
736 // ------------ analyze data after cursor position ------------------
738 // fprintf(stderr, "accept: %d\n", XMLScannerAccept(machine));
741 /* Reinitialize and reconfigure the scanner, and run it again, but this time with
742 * the data from the cursor position until the end.
744 XMLScannerInit(machine);
745 machine->mode = AFTER;
746 machine->cursor = cursor;
747 XMLScannerExecute(machine, data + cursor, len - cursor);
748 XMLScannerFinish(machine);
750 /* If there are no closing tags, we don't need to check if
751 * the topmost opening tags on the stacks are already balanced
753 closingcount = (machine->sp_e / 2);
758 resultstack_e = malloc(MAXTAGLENGTH * ((machine->sp_e/2) + 1));
760 for (i = 0; i < closingcount; i++) {
764 bzero(resultstack_e[i], MAXTAGLENGTH);
765 strncpy(resultstack_e[i], machine->stack_e[lower], machine->stack_e[upper] - machine->stack_e[lower]);
769 DEBUG && fprintf(stderr, "closing count %d\n", closingcount);
771 identical_closing = closingcount ? 1 : 0;
772 for (i = 0; i < closingcount - 1; i++) {
773 if (!strcmp(resultstack_e[i], resultstack_e[i + 1])) {
780 DEBUG && fprintf(stderr, "identical_closing %d\n", identical_closing);
782 /* last opening tag before cursor and first closing tag after
783 * cursor have to be identical, otherwise we are not interested
784 * if they are balanced
786 if (strcmp(resultstack[openingcount - 1], resultstack_e[0])) {
791 /* ok, the adjacent opening and closing tags are identical, so we
792 * need to know if there are less closing tags than opening tags,
793 * because only then does tag completion make any sense at this location
796 if (identical_opening <= identical_closing) {
797 *result |= ERROR_ALREADY_BALANCED_HERE;
802 // caller needs to free() this...
812 * Push the current start and end buffer position markers onto our
813 * stack of currently open tags. We're operating with position numbers
814 * only at this point, later there will be actual copies out of the buffer
816 void pushTag(XMLScanner *fsm) {
818 char buffer[MAXTAGLENGTH];
819 bzero(buffer, sizeof(buffer));
821 if (fsm->sp + 2 >= (STACKDEPTH - 1)) {
822 fprintf(stderr, "pushTag: stack overflow at %d, can't push more!\n", STACKDEPTH);
826 fsm->stack[fsm->sp++] = fsm->mark_namestart;
827 fsm->stack[fsm->sp++] = fsm->mark_nameend;
829 DEBUG && strncpy(buffer, fsm->stack[fsm->sp - 2], fsm->stack[fsm->sp - 1] - fsm->stack[fsm->sp - 2]);
830 DEBUG && fprintf(stderr, "pushTag: pushing '%s'\n", buffer);
837 * Push the current start and end buffer position markers for
838 * *end* tags onto the stack.
840 void pushETag(XMLScanner *fsm) {
842 char buffer[MAXTAGLENGTH];
843 bzero(buffer, sizeof(buffer));
845 if (fsm->sp_e + 2 >= (STACKDEPTH - 1)) {
846 fprintf(stderr, "pushETag: stack overflow at %d, can't push more!\n", STACKDEPTH);
850 fsm->stack_e[fsm->sp_e++] = fsm->mark_namestart;
851 fsm->stack_e[fsm->sp_e++] = fsm->mark_nameend;
853 DEBUG && strncpy(buffer, fsm->stack_e[fsm->sp_e - 2], fsm->stack_e[fsm->sp_e - 1] - fsm->stack_e[fsm->sp_e - 2]);
854 DEBUG && fprintf(stderr, "pushETag: pushing '%s'\n", buffer);
860 * pop the topmost element
862 void popTag(XMLScanner *fsm) {
864 char buffer[MAXTAGLENGTH];
865 bzero(buffer, sizeof(buffer));
868 fprintf(stderr, "popTag: stack underflow, can't pop more!\n");
874 DEBUG && strncpy(buffer, fsm->stack[fsm->sp], fsm->stack[fsm->sp + 1] - fsm->stack[fsm->sp]);
875 DEBUG && fprintf(stderr, "popTag: popping '%s'\n", buffer);
880 * check out the end tag we just stumbled upon.
881 * the behavior is different here, according to the scan mode
882 * (before or after cursor position).
884 void checkETag(XMLScanner *fsm) {
886 char buffer[MAXTAGLENGTH];
887 bzero(buffer, sizeof(buffer));
890 /* return if the stack is empty in BEFORE mode, we can't do anything interesting */
891 if (!fsm->sp && fsm->mode == BEFORE) {
895 len = fsm->mark_nameend - fsm->mark_namestart;
897 strncpy(buffer, fsm->mark_namestart, len);
899 /* if topmost tag on stack is identical to current end tag, pop it */
900 if(fsm->sp && !strncmp(fsm->stack[fsm->sp - 2], buffer, len)) {
901 // fprintf(stderr, "checkETag: popping, len = %d, etag = '%s'\n", len, buffer);