/* Automatically generated by Ragel from "ragel_xmlscanner.c". * * Parts of this file are copied from Ragel source covered by the GNU * GPL. As a special exception, you may use the parts of this file copied * from Ragel source without restriction. The remainder is derived from * "ragel_xmlscanner.c" and inherits the copyright status of that file. */ # 1 "ragel_xmlscanner.c" /* * This is an input file for the "Ragel" finite state machine compiler utility. * It produces output code which implements a tag scanner for XML data. * It is used for intelligent xml tag completion in an XML editor interface. * * See the Ragel online documentation for additional * information about the format of this file. * * Written by Marc Liyanage * */ #include "ragel_xmlscanner.h" /* modes for the scan, before or after cursor position */ enum { BEFORE = 1, AFTER }; # 35 "ragel_xmlscanner_out.c" /* Forward dec state for the transition structure. */ struct XMLScannerStateStruct; /* Only non-static data: current state, acceptance indicator. */ struct XMLScannerStruct { int *curState; int accept; # 26 "ragel_xmlscanner.c" char *data; char *stack[STACKDEPTH]; char *stack_e[STACKDEPTH]; int sp; int sp_e; char *mark_namestart; char *mark_nameend; char *mark_attrstart; char *mark_attrend; char *before_toptag; int cursor; int in_comment; int in_cdata; int in_tag; int mode; # 62 "ragel_xmlscanner_out.c" }; typedef struct XMLScannerStruct XMLScanner; /* Init the fsm. */ void XMLScannerInit( XMLScanner *fsm ); /* Execute some chunk of data. */ void XMLScannerExecute( XMLScanner *fsm, char *data, int dlen ); /* Indicate to the fsm tha there is no more data. */ void XMLScannerFinish( XMLScanner *fsm ); /* Did the machine accept? */ int XMLScannerAccept( XMLScanner *fsm ); # 43 "ragel_xmlscanner.c" void checkETag(XMLScanner *fsm); void popTag(XMLScanner *fsm); void pushTag(XMLScanner *fsm); # 87 "ragel_xmlscanner_out.c" #define f XMLScanner_f #define s XMLScanner_s #define k XMLScanner_k #define i XMLScanner_i #define t XMLScanner_t #define SPEC_ANY_FLAT 0x01 #define SPEC_ANY_SINGLE 0x02 #define SPEC_ANY_RANGE 0x04 #define SPEC_ANY_DEF 0x08 #define SPEC_IS_FINAL 0x10 #define SPEC_OUT_FUNC 0x20 /* The array of functions. */ static int XMLScanner_f[] = { 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 9, 1, 10, 2, 1, 1, 2, 3, 3, 2, 4, 4, 2, 5, 7, 2, 5, 8, 2, 11, 11, 2, 12, 13, 3, 10, 11, 11, 4, 4, 4, 9, 4, 4, 12, 13, 12, 13, 6, 12, 13, 11, 12, 13, 11 }; /* The array of keys of transitions. */ static char XMLScanner_k[] = { 45, 45, 45, 45, 45, 62, 45, 60, 45, 45, 62, 60, 67, 68, 65, 84, 65, 91, 91, 93, 93, 93, 62, 93, 60, 93, 93, 62, 93, 60, 60, 62, 60, 32, 47, 58, 62, 95, 9, 13, 65, 90, 97, 122, 32, 45, 46, 47, 58, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 34, 39, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 61, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 61, 95, 48, 57, 65, 90, 97, 122, 34, 39, 32, 47, 58, 62, 95, 9, 13, 65, 90, 97, 122, 34, 32, 47, 58, 62, 95, 9, 13, 65, 90, 97, 122, 39, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 45, 46, 58, 62, 95, 48, 57, 65, 90, 97, 122, 60, 33, 47, 58, 60, 95, 65, 90, 97, 122, 60, 60, 45, 60, 91, 58, 60, 95, 65, 90, 97, 122, 32, 45, 46, 47, 58, 60, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 60, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 32, 45, 46, 47, 58, 60, 62, 95, 9, 13, 48, 57, 65, 90, 97, 122, 0 }; /* The array of indicies into the transition array. */ static unsigned char XMLScanner_i[] = { 1, 2, 3, 4, 5, 6, 5, 6, 7, 5, 8, 9, 8, 10, 5, 6, 11, 5, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 24, 26, 25, 24, 27, 28, 28, 29, 24, 30, 25, 24, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 38, 43, 43, 44, 45, 46, 39, 47, 48, 49, 44, 50, 51, 51, 44, 45, 46, 39, 47, 48, 49, 44, 50, 51, 51, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 44, 45, 46, 39, 47, 48, 49, 44, 50, 51, 51, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 59, 60, 61, 55, 62, 63, 64, 64, 59, 60, 61, 55, 62, 63, 64, 64, 59, 60, 61, 55, 62, 63, 64, 64, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 65, 66, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 44, 52, 53, 39, 54, 55, 48, 56, 44, 57, 58, 58, 59, 60, 61, 55, 62, 63, 64, 64, 59, 60, 61, 55, 62, 63, 64, 64, 59, 60, 61, 55, 62, 63, 64, 64, 59, 60, 61, 55, 62, 63, 64, 64, 59, 60, 61, 55, 62, 63, 64, 64, 59, 60, 61, 55, 62, 63, 64, 64, 67, 68, 69, 70, 71, 72, 73, 74, 75, 71, 76, 76, 67, 68, 71, 72, 73, 74, 75, 71, 76, 76, 69, 70, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 77, 78, 79, 80, 81, 82, 83, 83, 84, 85, 86, 87, 88, 89, 90, 91, 91, 92, 93, 94, 93, 94, 95, 93, 96, 94, 97, 93, 98, 99, 99, 94, 44, 45, 46, 39, 47, 93, 48, 49, 44, 50, 51, 51, 94, 44, 45, 46, 39, 47, 93, 48, 49, 44, 50, 51, 51, 94, 44, 45, 46, 39, 47, 93, 48, 49, 44, 50, 51, 51, 94, 0 }; /* The aray of states. */ static int XMLScanner_s[] = { 768, 0, 0, 1026, 0, 0, 1, 1034, 1, 1, 1, 1034, 2, 3, 1, 1034, 3, 5, 1, 1034, 4, 7, 2, 1338, 6, 10, 2, 2, 1034, 8, 13, 1, 1034, 9, 15, 2, 1338, 11, 18, 1, 16, 1026, 12, 20, 1, 1026, 13, 21, 1, 1026, 14, 22, 1, 1026, 15, 23, 1, 1026, 16, 24, 1, 1026, 17, 25, 1, 1026, 18, 26, 1, 1034, 19, 27, 1, 1034, 20, 29, 1, 1034, 21, 31, 1, 1034, 22, 33, 2, 1338, 24, 36, 2, 6, 1034, 26, 39, 1, 1034, 27, 41, 2, 1338, 29, 44, 1, 19, 1338, 30, 46, 1, 25, 1026, 31, 48, 1, 1338, 32, 49, 1, 10, 1286, 33, 51, 5, 3, 1286, 44, 59, 7, 4, 1286, 59, 70, 7, 4, 1286, 74, 81, 8, 4, 1286, 90, 93, 8, 4, 1286, 106, 105, 7, 4, 1286, 121, 116, 8, 4, 1286, 137, 128, 5, 3, 1286, 148, 136, 5, 3, 1286, 159, 144, 5, 3, 1286, 170, 152, 8, 4, 1286, 186, 164, 8, 4, 1286, 202, 176, 8, 4, 1026, 218, 188, 2, 1286, 220, 190, 8, 4, 1286, 236, 202, 8, 4, 1286, 252, 214, 8, 4, 1286, 268, 226, 5, 3, 1286, 279, 234, 5, 3, 1286, 290, 242, 5, 3, 1286, 301, 250, 5, 3, 1286, 312, 258, 5, 3, 1286, 323, 266, 5, 3, 1034, 334, 274, 1, 1034, 335, 276, 1, 1286, 336, 278, 5, 3, 1034, 347, 286, 1, 1286, 348, 288, 5, 3, 1034, 359, 296, 1, 1286, 360, 298, 5, 3, 1286, 371, 306, 5, 3, 1286, 382, 314, 5, 3, 1286, 393, 322, 5, 3, 1286, 404, 330, 5, 3, 1286, 415, 338, 5, 3, 1286, 426, 346, 5, 3, 1286, 437, 354, 5, 3, 1286, 448, 362, 5, 3, 1338, 459, 370, 1, 28, 1598, 460, 372, 5, 2, 8, 1050, 469, 380, 1, 1050, 470, 382, 1, 1050, 471, 384, 3, 1310, 474, 388, 3, 2, 1310, 481, 394, 8, 4, 1310, 497, 407, 8, 4, 1310, 513, 420, 8, 4, 0 }; /* The array of transitions. */ static int *XMLScanner_t[] = { 0, 0, s+7, 0, s+28, f+0, s+11, f+0, s+15, 0, s+11, 0, s+19, 0, s+23, 0, s+313, f+2, s+307, f+2, s+32, 0, s+36, 0, s+307, f+16, s+313, f+16, s+45, 0, s+49, 0, s+53, 0, s+57, 0, s+61, 0, s+65, 0, s+69, 0, s+90, f+4, s+73, f+4, s+77, 0, s+73, 0, s+81, 0, s+85, 0, s+307, f+6, s+313, f+6, s+94, 0, s+98, 0, s+307, f+19, s+313, f+19, s+307, f+25, s+313, f+25, s+112, 0, s+307, f+10, s+313, f+10, s+117, 0, s+108, 0, s+152, f+31, s+103, 0, s+157, f+31, s+162, f+31, s+117, f+14, s+122, 0, s+127, 0, s+132, f+37, s+103, f+14, s+137, f+37, s+142, 0, s+147, f+37, s+167, 0, s+172, 0, s+177, f+37, s+182, 0, s+186, f+37, s+191, 0, s+196, f+37, s+201, 0, s+206, 0, s+211, 0, s+216, 0, s+221, 0, s+226, 0, s+231, 0, s+235, 0, s+239, 0, s+244, 0, s+248, 0, s+253, 0, s+117, f+46, s+108, f+34, s+152, f+51, s+103, f+34, s+157, f+51, s+162, f+51, s+287, 0, s+282, 0, s+297, 0, s+302, f+14, s+292, 0, s+277, 0, s+272, 0, s+307, f+28, s+313, f+28, s+321, f+8, s+325, f+22, s+330, f+41, s+307, f+8, s+335, f+41, s+340, f+41, s+313, f+8, s+307, 0, s+313, 0, s+3, 0, s+41, 0, s+267, f+12, s+262, f+12, s+257, f+12, 0 }; /* The start state. */ static int *XMLScanner_start = s+317; /* Init the fsm to a runnable state. */ void XMLScannerInit( XMLScanner *fsm ) { fsm->curState = XMLScanner_start; fsm->accept = 0; # 53 "ragel_xmlscanner.c" { fsm->sp = 0; fsm->sp_e = 0; fsm->mode = BEFORE; fsm->in_comment = 0; fsm->in_cdata = 0; fsm->in_tag = 0; } # 338 "ragel_xmlscanner_out.c" } /* Did the fsm accept? */ int XMLScannerAccept( XMLScanner *fsm ) { return fsm->accept; } /* Binary search an array of keys looking for a key. */ static char *XMLScannerBSearch( char c, char *keys, int len ) { char *lower = keys; char *mid; char *upper = keys + len - 1; while (1) { if ( upper < lower ) return 0; /* Find the midpoint. */ mid = lower + ((upper-lower) >> 1); if ( c < *mid ) upper = mid - 1; else if ( c > *mid ) lower = mid + 1; else return mid; } } /* Binary search an array of keys looking for a key. */ static char *XMLScannerRangeBSearch( char c, char *keys, int len ) { char *lower = keys; char *mid; char *upper = keys + len - 2; while (1) { if ( upper < lower ) return 0; /* Find the midpoint. Be sure to settle on the * lower end of a range. */ mid = lower + (((upper-lower) >> 1) & ~1); if ( c < mid[0] ) upper = mid - 2; else if ( c > mid[1] ) lower = mid + 2; else { /* The key was found in the range mid, return it. */ return mid; } } } /* Execute the fsm on some chunk of data. */ void XMLScannerExecute( XMLScanner *fsm, char *data, int dlen ) { char *p = data; int len = dlen; int *cs = fsm->curState; int specs, **trans, *funcs, nfuncs; char *keys; unsigned char *inds; if ( data == 0 ) goto finishInput; again: if ( cs == 0 || len == 0 ) goto out; /* Get required data. */ specs = *cs++; keys = k + *cs++; inds = i + *cs++; /* Try flat index. */ if ( specs & SPEC_ANY_FLAT ) { int indsLen = *cs++; keys += 2; inds += indsLen; } /* Try binary search single. */ if ( specs & SPEC_ANY_SINGLE ) { /* Try to find the key. */ int indsLen = *cs++; char *match = XMLScannerBSearch( *p, keys, indsLen ); if ( match != 0 ) { trans = t + (inds[match - keys]<<1); goto match; } /* Advance over the keys and indicies. */ keys += indsLen; inds += indsLen; } /* Try binary search range. */ if ( specs & SPEC_ANY_RANGE ) { /* Try to find the key. */ int indsLen = *cs++; char *match = XMLScannerRangeBSearch( *p, keys, (indsLen<<1) ); if ( match != 0 ) { trans = t + (inds[(match - keys)>>1]<<1); goto match; } /* Advance over the keys and indicies. */ keys += (indsLen<<1); inds += indsLen; } /* Try the default transition. */ if ( specs & SPEC_ANY_DEF ) { trans = t + ((*inds)<<1); goto match; } /* No match. */ cs = 0; goto out; match: /* Move to the new state. */ cs = *trans++; /* Check for functions. */ if ( (funcs=*trans) == 0 ) goto noFuncs; execFuncs: nfuncs = *funcs++; while ( nfuncs-- > 0 ) { switch ( *funcs++ ) { case 0: # 63 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "commentstart: %d %c\n", p - data, *p); fsm->in_comment = 1; } break; case 1: # 68 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "commentend: %d %c\n", p - data, *p); fsm->in_comment = 0; fsm->in_tag = 0; } break; case 2: # 74 "ragel_xmlscanner.c" { fsm->in_cdata = 1; } break; case 3: # 78 "ragel_xmlscanner.c" { fsm->in_cdata = 0; fsm->in_tag = 0; } break; case 4: # 83 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "enter tag at %d\n", p - data); fsm->in_tag = 1; } break; case 5: # 88 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "exit tag at %d\n", p - data); fsm->in_tag = 0; } break; case 6: # 93 "ragel_xmlscanner.c" { // fprintf(stderr, "name: %d %c\n", p - data, *p); } break; case 7: # 97 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "stag\n"); pushTag(fsm); } break; case 8: # 102 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "stag: start: %d end: %d %c\n", fsm->mark_namestart - data, fsm->mark_nameend - data, *p); checkETag(fsm); } break; case 9: # 107 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "markstart: %d %c\n", p - data, *p); fsm->mark_namestart = p; } break; case 10: # 112 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "markend: %d %c\n", (p - 1) - data, *(p-1)); fsm->mark_nameend = p; } break; case 11: # 117 "ragel_xmlscanner.c" { // fprintf(stderr, "attrstart: %d %c\n", p - data, *p); fsm->mark_attrstart = p; } break; case 12: # 122 "ragel_xmlscanner.c" { // fprintf(stderr, "attrend: %d %c\n", (p - 1) - data, *(p - 1)); fsm->mark_attrend = p; } break; case 13: # 128 "ragel_xmlscanner.c" { // fprintf(stderr, "attr: start: %d end: %d %c\n", fsm->mark_attrstart - data, fsm->mark_attrend - data, *p); } break; case 14: # 132 "ragel_xmlscanner.c" { DEBUG && fprintf(stderr, "pi: %d\n", p - data); } break; # 564 "ragel_xmlscanner_out.c" } } noFuncs: p++, len--; goto again; finishInput: if ( cs != 0 && *cs & SPEC_IS_FINAL ) { /* The machine accepts. */ fsm->accept = 1; /* If finishing in a final state then execute the * out functions for it. (if any). */ if ( *cs & SPEC_OUT_FUNC ) { funcs = f+*(cs + (*cs>>8)-1); len = 1; goto execFuncs; } } else { /* If we are not in a final state then this * is an error. Move to the error state. */ fsm->curState = 0; } out: fsm->curState = cs; } /* Indicate to the fsm that the input is done. Does cleanup tasks. */ void XMLScannerFinish( XMLScanner *fsm ) { XMLScannerExecute( fsm, 0, 0 ); } #undef f #undef s #undef k #undef i #undef t #undef SPEC_ANY_FLAT #undef SPEC_ANY_SINGLE #undef SPEC_ANY_RANGE #undef SPEC_ANY_DEF #undef SPEC_IS_FINAL #undef SPEC_OUT_FUNC # 165 "ragel_xmlscanner.c" /* * findCompletion does the actual work of driving the state machine * * Input: * data - pointer to the buffer containing the XML data * len - length of the data to analyze * cursor - logical position of the editing cursor in the data buffer * result - pointer to integer, which will contain a bit field with * additional status information after completion: * * Completion rules: * * - The system builds a stack of tags which are open at the indicated cursor * position in the XML data. * - If completion is possible at that cursor position, the integer * result will be 0. The caller should insert a closing tag for the * topmost tag name on the stack. * - It can use the other elements of the * stack for GUI goodies, like display of a stack of currently open tags * in the editor. However, it should not assume that the tag stack can be * used to close all opening tags. Instead, it should re-evaluate * the document with this routine after the tag has been inserted and the * cursor position might have moved as a result. * * - There are a few cases where completion should not be performed, this * will be indicated by the bitfield in the result int parameter: * - ERROR_IN_TAG: The cursor is in the middle of a tag. No useful completion * is possible (maybe look at the prefix and complete * accordingly, sometime in the future...) * - ERROR_IN_COMMENT: The cursor is inside a comment block. * - ERROR_IN_CDATA: The cursor is inside a cdata section. * - ERROR_NO_TAG: There's no unmatched opening tag to the left of the cursor * - ERROR_ALREADY_BALANCED_HERE: The currently open tags to the left of the * cursor are already balanced with an equal amount * of closing tags to the right of the cursor. * * Results: * * Returns a pointer to an array of pointers to chars. * Each array entry contains one tag from the stack * tags open at the cursor position. * */ char (*findCompletion(char *data, int len, int cursor, int *result, int tagpositions[]))[] { XMLScanner scanner, *machine = &scanner; char toptag[MAXTAGLENGTH]; unsigned int i, lower, upper, openingcount, closingcount, identical_opening, identical_closing; char (*resultstack)[MAXTAGLENGTH] = NULL; char (*resultstack_e)[MAXTAGLENGTH] = NULL; *result = 0; bzero(toptag, MAXTAGLENGTH); // ------------ analyze data before cursor position ------------------ XMLScannerInit(machine); machine->mode = BEFORE; machine->cursor = cursor; XMLScannerExecute(machine, data, cursor); XMLScannerFinish(machine); /* Any unbalanced open tags on the stack at all? If so, allocate memory * and copy the tags over to a newly allocated buffer, into a stack. */ if (machine->sp) { resultstack = malloc(MAXTAGLENGTH * ((machine->sp/2) + 1)); } else { /* Nothing useful to return to caller */ *result |= ERROR_NO_TAG; return NULL; } openingcount = (machine->sp / 2); for (i = 0; i < openingcount; i++) { lower = i * 2; upper = lower + 1; bzero(resultstack[i], MAXTAGLENGTH); strncpy(resultstack[i], machine->stack[lower], machine->stack[upper] - machine->stack[lower]); if (tagpositions) { tagpositions[lower] = machine->stack[lower] - data; tagpositions[upper] = machine->stack[upper] - data; } } /* make sure the slot after the topmost tag is zeroed out, so the * calling code can use that as an end of stack marker. */ bzero(resultstack[openingcount], MAXTAGLENGTH); strncpy(toptag, resultstack[openingcount - 1], MAXTAGLENGTH); if (machine->in_tag) *result |= ERROR_IN_TAG; if (machine->in_comment) *result |= ERROR_IN_COMMENT; if (machine->in_cdata) *result |= ERROR_IN_CDATA; if (*result) { return resultstack; } // count identical opening tags on the top of the stack. identical_opening = 1; for (i = (openingcount - 2); i >= 0; i--) { if (!strcmp(resultstack[i], resultstack[i + 1])) { identical_opening++; } else { break; } } // ------------ analyze data after cursor position ------------------ // fprintf(stderr, "accept: %d\n", XMLScannerAccept(machine)); /* Reinitialize and reconfigure the scanner, and run it again, but this time with * the data from the cursor position until the end. */ XMLScannerInit(machine); machine->mode = AFTER; machine->cursor = cursor; XMLScannerExecute(machine, data + cursor, len - cursor); XMLScannerFinish(machine); /* If there are no closing tags, we don't need to check if * the topmost opening tags on the stacks are already balanced */ closingcount = (machine->sp_e / 2); if (!closingcount) { return resultstack; } resultstack_e = malloc(MAXTAGLENGTH * ((machine->sp_e/2) + 1)); for (i = 0; i < closingcount; i++) { lower = i * 2; upper = lower + 1; bzero(resultstack_e[i], MAXTAGLENGTH); strncpy(resultstack_e[i], machine->stack_e[lower], machine->stack_e[upper] - machine->stack_e[lower]); } DEBUG && fprintf(stderr, "closing count %d\n", closingcount); identical_closing = closingcount ? 1 : 0; for (i = 0; i < closingcount - 1; i++) { if (!strcmp(resultstack_e[i], resultstack_e[i + 1])) { identical_closing++; } else { break; } } DEBUG && fprintf(stderr, "identical_closing %d\n", identical_closing); /* last opening tag before cursor and first closing tag after * cursor have to be identical, otherwise we are not interested * if they are balanced */ if (strcmp(resultstack[openingcount - 1], resultstack_e[0])) { free(resultstack_e); return resultstack; } /* ok, the adjacent opening and closing tags are identical, so we * need to know if there are less closing tags than opening tags, * because only then does tag completion make any sense at this location */ if (identical_opening <= identical_closing) { *result |= ERROR_ALREADY_BALANCED_HERE; } free(resultstack_e); // caller needs to free() this... return resultstack; } /* * Push the current start and end buffer position markers onto our * stack of currently open tags. We're operating with position numbers * only at this point, later there will be actual copies out of the buffer */ void pushTag(XMLScanner *fsm) { char buffer[MAXTAGLENGTH]; bzero(buffer, sizeof(buffer)); if (fsm->sp + 2 >= (STACKDEPTH - 1)) { fprintf(stderr, "pushTag: stack overflow at %d, can't push more!\n", STACKDEPTH); return; } fsm->stack[fsm->sp++] = fsm->mark_namestart; fsm->stack[fsm->sp++] = fsm->mark_nameend; DEBUG && strncpy(buffer, fsm->stack[fsm->sp - 2], fsm->stack[fsm->sp - 1] - fsm->stack[fsm->sp - 2]); DEBUG && fprintf(stderr, "pushTag: pushing '%s'\n", buffer); } /* * Push the current start and end buffer position markers for * *end* tags onto the stack. */ void pushETag(XMLScanner *fsm) { char buffer[MAXTAGLENGTH]; bzero(buffer, sizeof(buffer)); if (fsm->sp_e + 2 >= (STACKDEPTH - 1)) { fprintf(stderr, "pushETag: stack overflow at %d, can't push more!\n", STACKDEPTH); return; } fsm->stack_e[fsm->sp_e++] = fsm->mark_namestart; fsm->stack_e[fsm->sp_e++] = fsm->mark_nameend; DEBUG && strncpy(buffer, fsm->stack_e[fsm->sp_e - 2], fsm->stack_e[fsm->sp_e - 1] - fsm->stack_e[fsm->sp_e - 2]); DEBUG && fprintf(stderr, "pushETag: pushing '%s'\n", buffer); } /* * pop the topmost element */ void popTag(XMLScanner *fsm) { char buffer[MAXTAGLENGTH]; bzero(buffer, sizeof(buffer)); if (fsm->sp < 2) { fprintf(stderr, "popTag: stack underflow, can't pop more!\n"); return; } fsm->sp -= 2; DEBUG && strncpy(buffer, fsm->stack[fsm->sp], fsm->stack[fsm->sp + 1] - fsm->stack[fsm->sp]); DEBUG && fprintf(stderr, "popTag: popping '%s'\n", buffer); } /* * check out the end tag we just stumbled upon. * the behavior is different here, according to the scan mode * (before or after cursor position). */ void checkETag(XMLScanner *fsm) { char buffer[MAXTAGLENGTH]; bzero(buffer, sizeof(buffer)); int len; /* return if the stack is empty in BEFORE mode, we can't do anything interesting */ if (!fsm->sp && fsm->mode == BEFORE) { return; } len = fsm->mark_nameend - fsm->mark_namestart; strncpy(buffer, fsm->mark_namestart, len); /* if topmost tag on stack is identical to current end tag, pop it */ if(fsm->sp && !strncmp(fsm->stack[fsm->sp - 2], buffer, len)) { // fprintf(stderr, "checkETag: popping, len = %d, etag = '%s'\n", len, buffer); popTag(fsm); } else { pushETag(fsm); } }