~ubuntu-branches/ubuntu/wily/opencollada/wily-proposed

« back to all changes in this revision

Viewing changes to Externals/LibXML/xmlregexp.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2015-05-14 17:23:27 UTC
  • Revision ID: package-import@ubuntu.com-20150514172327-f862u8envms01fra
Tags: upstream-0.1.0~20140703.ddf8f47+dfsg1
ImportĀ upstreamĀ versionĀ 0.1.0~20140703.ddf8f47+dfsg1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * regexp.c: generic and extensible Regular Expression engine
 
3
 *
 
4
 * Basically designed with the purpose of compiling regexps for 
 
5
 * the variety of validation/shemas mechanisms now available in
 
6
 * XML related specifications these include:
 
7
 *    - XML-1.0 DTD validation
 
8
 *    - XML Schemas structure part 1
 
9
 *    - XML Schemas Datatypes part 2 especially Appendix F
 
10
 *    - RELAX-NG/TREX i.e. the counter proposal
 
11
 *
 
12
 * See Copyright for the status of this software.
 
13
 *
 
14
 * Daniel Veillard <veillard@redhat.com>
 
15
 */
 
16
 
 
17
#define IN_LIBXML
 
18
#include "libxml.h"
 
19
 
 
20
#ifdef LIBXML_REGEXP_ENABLED
 
21
 
 
22
/* #define DEBUG_ERR */
 
23
 
 
24
#include <stdio.h>
 
25
#include <string.h>
 
26
#ifdef HAVE_LIMITS_H
 
27
#include <limits.h>
 
28
#endif
 
29
 
 
30
#include <libxml/tree.h>
 
31
#include <libxml/parserInternals.h>
 
32
#include <libxml/xmlregexp.h>
 
33
#include <libxml/xmlautomata.h>
 
34
#include <libxml/xmlunicode.h>
 
35
 
 
36
#ifndef INT_MAX
 
37
#define INT_MAX 123456789 /* easy to flag and big enough for our needs */
 
38
#endif
 
39
 
 
40
/* #define DEBUG_REGEXP_GRAPH */
 
41
/* #define DEBUG_REGEXP_EXEC */
 
42
/* #define DEBUG_PUSH */
 
43
/* #define DEBUG_COMPACTION */
 
44
 
 
45
#define MAX_PUSH 10000000
 
46
 
 
47
#define ERROR(str)                                                      \
 
48
    ctxt->error = XML_REGEXP_COMPILE_ERROR;                             \
 
49
    xmlRegexpErrCompile(ctxt, str);
 
50
#define NEXT ctxt->cur++
 
51
#define CUR (*(ctxt->cur))
 
52
#define NXT(id) (ctxt->cur[id])
 
53
 
 
54
#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l)
 
55
#define NEXTL(l) ctxt->cur += l;
 
56
#define XML_REG_STRING_SEPARATOR '|'
 
57
/*
 
58
 * Need PREV to check on a '-' within a Character Group. May only be used
 
59
 * when it's guaranteed that cur is not at the beginning of ctxt->string!
 
60
 */
 
61
#define PREV (ctxt->cur[-1])
 
62
 
 
63
/**
 
64
 * TODO:
 
65
 *
 
66
 * macro to flag unimplemented blocks
 
67
 */
 
68
#define TODO                                                            \
 
69
    xmlGenericError(xmlGenericErrorContext,                             \
 
70
            "Unimplemented block at %s:%d\n",                           \
 
71
            __FILE__, __LINE__);
 
72
 
 
73
/************************************************************************
 
74
 *                                                                      *
 
75
 *                      Datatypes and structures                        *
 
76
 *                                                                      *
 
77
 ************************************************************************/
 
78
 
 
79
/*
 
80
 * Note: the order of the enums below is significant, do not shuffle
 
81
 */
 
82
typedef enum {
 
83
    XML_REGEXP_EPSILON = 1,
 
84
    XML_REGEXP_CHARVAL,
 
85
    XML_REGEXP_RANGES,
 
86
    XML_REGEXP_SUBREG,  /* used for () sub regexps */
 
87
    XML_REGEXP_STRING,
 
88
    XML_REGEXP_ANYCHAR, /* . */
 
89
    XML_REGEXP_ANYSPACE, /* \s */
 
90
    XML_REGEXP_NOTSPACE, /* \S */
 
91
    XML_REGEXP_INITNAME, /* \l */
 
92
    XML_REGEXP_NOTINITNAME, /* \L */
 
93
    XML_REGEXP_NAMECHAR, /* \c */
 
94
    XML_REGEXP_NOTNAMECHAR, /* \C */
 
95
    XML_REGEXP_DECIMAL, /* \d */
 
96
    XML_REGEXP_NOTDECIMAL, /* \D */
 
97
    XML_REGEXP_REALCHAR, /* \w */
 
98
    XML_REGEXP_NOTREALCHAR, /* \W */
 
99
    XML_REGEXP_LETTER = 100,
 
100
    XML_REGEXP_LETTER_UPPERCASE,
 
101
    XML_REGEXP_LETTER_LOWERCASE,
 
102
    XML_REGEXP_LETTER_TITLECASE,
 
103
    XML_REGEXP_LETTER_MODIFIER,
 
104
    XML_REGEXP_LETTER_OTHERS,
 
105
    XML_REGEXP_MARK,
 
106
    XML_REGEXP_MARK_NONSPACING,
 
107
    XML_REGEXP_MARK_SPACECOMBINING,
 
108
    XML_REGEXP_MARK_ENCLOSING,
 
109
    XML_REGEXP_NUMBER,
 
110
    XML_REGEXP_NUMBER_DECIMAL,
 
111
    XML_REGEXP_NUMBER_LETTER,
 
112
    XML_REGEXP_NUMBER_OTHERS,
 
113
    XML_REGEXP_PUNCT,
 
114
    XML_REGEXP_PUNCT_CONNECTOR,
 
115
    XML_REGEXP_PUNCT_DASH,
 
116
    XML_REGEXP_PUNCT_OPEN,
 
117
    XML_REGEXP_PUNCT_CLOSE,
 
118
    XML_REGEXP_PUNCT_INITQUOTE,
 
119
    XML_REGEXP_PUNCT_FINQUOTE,
 
120
    XML_REGEXP_PUNCT_OTHERS,
 
121
    XML_REGEXP_SEPAR,
 
122
    XML_REGEXP_SEPAR_SPACE,
 
123
    XML_REGEXP_SEPAR_LINE,
 
124
    XML_REGEXP_SEPAR_PARA,
 
125
    XML_REGEXP_SYMBOL,
 
126
    XML_REGEXP_SYMBOL_MATH,
 
127
    XML_REGEXP_SYMBOL_CURRENCY,
 
128
    XML_REGEXP_SYMBOL_MODIFIER,
 
129
    XML_REGEXP_SYMBOL_OTHERS,
 
130
    XML_REGEXP_OTHER,
 
131
    XML_REGEXP_OTHER_CONTROL,
 
132
    XML_REGEXP_OTHER_FORMAT,
 
133
    XML_REGEXP_OTHER_PRIVATE,
 
134
    XML_REGEXP_OTHER_NA,
 
135
    XML_REGEXP_BLOCK_NAME
 
136
} xmlRegAtomType;
 
137
 
 
138
typedef enum {
 
139
    XML_REGEXP_QUANT_EPSILON = 1,
 
140
    XML_REGEXP_QUANT_ONCE,
 
141
    XML_REGEXP_QUANT_OPT,
 
142
    XML_REGEXP_QUANT_MULT,
 
143
    XML_REGEXP_QUANT_PLUS,
 
144
    XML_REGEXP_QUANT_ONCEONLY,
 
145
    XML_REGEXP_QUANT_ALL,
 
146
    XML_REGEXP_QUANT_RANGE
 
147
} xmlRegQuantType;
 
148
 
 
149
typedef enum {
 
150
    XML_REGEXP_START_STATE = 1,
 
151
    XML_REGEXP_FINAL_STATE,
 
152
    XML_REGEXP_TRANS_STATE,
 
153
    XML_REGEXP_SINK_STATE,
 
154
    XML_REGEXP_UNREACH_STATE
 
155
} xmlRegStateType;
 
156
 
 
157
typedef enum {
 
158
    XML_REGEXP_MARK_NORMAL = 0,
 
159
    XML_REGEXP_MARK_START,
 
160
    XML_REGEXP_MARK_VISITED
 
161
} xmlRegMarkedType;
 
162
 
 
163
typedef struct _xmlRegRange xmlRegRange;
 
164
typedef xmlRegRange *xmlRegRangePtr;
 
165
 
 
166
struct _xmlRegRange {
 
167
    int neg;            /* 0 normal, 1 not, 2 exclude */
 
168
    xmlRegAtomType type;
 
169
    int start;
 
170
    int end;
 
171
    xmlChar *blockName;
 
172
};
 
173
 
 
174
typedef struct _xmlRegAtom xmlRegAtom;
 
175
typedef xmlRegAtom *xmlRegAtomPtr;
 
176
 
 
177
typedef struct _xmlAutomataState xmlRegState;
 
178
typedef xmlRegState *xmlRegStatePtr;
 
179
 
 
180
struct _xmlRegAtom {
 
181
    int no;
 
182
    xmlRegAtomType type;
 
183
    xmlRegQuantType quant;
 
184
    int min;
 
185
    int max;
 
186
 
 
187
    void *valuep;
 
188
    void *valuep2;
 
189
    int neg;
 
190
    int codepoint;
 
191
    xmlRegStatePtr start;
 
192
    xmlRegStatePtr start0;
 
193
    xmlRegStatePtr stop;
 
194
    int maxRanges;
 
195
    int nbRanges;
 
196
    xmlRegRangePtr *ranges;
 
197
    void *data;
 
198
};
 
199
 
 
200
typedef struct _xmlRegCounter xmlRegCounter;
 
201
typedef xmlRegCounter *xmlRegCounterPtr;
 
202
 
 
203
struct _xmlRegCounter {
 
204
    int min;
 
205
    int max;
 
206
};
 
207
 
 
208
typedef struct _xmlRegTrans xmlRegTrans;
 
209
typedef xmlRegTrans *xmlRegTransPtr;
 
210
 
 
211
struct _xmlRegTrans {
 
212
    xmlRegAtomPtr atom;
 
213
    int to;
 
214
    int counter;
 
215
    int count;
 
216
    int nd;
 
217
};
 
218
 
 
219
struct _xmlAutomataState {
 
220
    xmlRegStateType type;
 
221
    xmlRegMarkedType mark;
 
222
    xmlRegMarkedType reached;
 
223
    int no;
 
224
    int maxTrans;
 
225
    int nbTrans;
 
226
    xmlRegTrans *trans;
 
227
    /*  knowing states ponting to us can speed things up */
 
228
    int maxTransTo;
 
229
    int nbTransTo;
 
230
    int *transTo;
 
231
};
 
232
 
 
233
typedef struct _xmlAutomata xmlRegParserCtxt;
 
234
typedef xmlRegParserCtxt *xmlRegParserCtxtPtr;
 
235
 
 
236
struct _xmlAutomata {
 
237
    xmlChar *string;
 
238
    xmlChar *cur;
 
239
 
 
240
    int error;
 
241
    int neg;
 
242
 
 
243
    xmlRegStatePtr start;
 
244
    xmlRegStatePtr end;
 
245
    xmlRegStatePtr state;
 
246
 
 
247
    xmlRegAtomPtr atom;
 
248
 
 
249
    int maxAtoms;
 
250
    int nbAtoms;
 
251
    xmlRegAtomPtr *atoms;
 
252
 
 
253
    int maxStates;
 
254
    int nbStates;
 
255
    xmlRegStatePtr *states;
 
256
 
 
257
    int maxCounters;
 
258
    int nbCounters;
 
259
    xmlRegCounter *counters;
 
260
 
 
261
    int determinist;
 
262
    int negs;
 
263
};
 
264
 
 
265
struct _xmlRegexp {
 
266
    xmlChar *string;
 
267
    int nbStates;
 
268
    xmlRegStatePtr *states;
 
269
    int nbAtoms;
 
270
    xmlRegAtomPtr *atoms;
 
271
    int nbCounters;
 
272
    xmlRegCounter *counters;
 
273
    int determinist;
 
274
    /*
 
275
     * That's the compact form for determinists automatas
 
276
     */
 
277
    int nbstates;
 
278
    int *compact;
 
279
    void **transdata;
 
280
    int nbstrings;
 
281
    xmlChar **stringMap;
 
282
};
 
283
 
 
284
typedef struct _xmlRegExecRollback xmlRegExecRollback;
 
285
typedef xmlRegExecRollback *xmlRegExecRollbackPtr;
 
286
 
 
287
struct _xmlRegExecRollback {
 
288
    xmlRegStatePtr state;/* the current state */
 
289
    int index;          /* the index in the input stack */
 
290
    int nextbranch;     /* the next transition to explore in that state */
 
291
    int *counts;        /* save the automata state if it has some */
 
292
};
 
293
 
 
294
typedef struct _xmlRegInputToken xmlRegInputToken;
 
295
typedef xmlRegInputToken *xmlRegInputTokenPtr;
 
296
 
 
297
struct _xmlRegInputToken {
 
298
    xmlChar *value;
 
299
    void *data;
 
300
};
 
301
 
 
302
struct _xmlRegExecCtxt {
 
303
    int status;         /* execution status != 0 indicate an error */
 
304
    int determinist;    /* did we find an indeterministic behaviour */
 
305
    xmlRegexpPtr comp;  /* the compiled regexp */
 
306
    xmlRegExecCallbacks callback;
 
307
    void *data;
 
308
 
 
309
    xmlRegStatePtr state;/* the current state */
 
310
    int transno;        /* the current transition on that state */
 
311
    int transcount;     /* the number of chars in char counted transitions */
 
312
 
 
313
    /*
 
314
     * A stack of rollback states
 
315
     */
 
316
    int maxRollbacks;
 
317
    int nbRollbacks;
 
318
    xmlRegExecRollback *rollbacks;
 
319
 
 
320
    /*
 
321
     * The state of the automata if any
 
322
     */
 
323
    int *counts;
 
324
 
 
325
    /*
 
326
     * The input stack
 
327
     */
 
328
    int inputStackMax;
 
329
    int inputStackNr;
 
330
    int index;
 
331
    int *charStack;
 
332
    const xmlChar *inputString; /* when operating on characters */
 
333
    xmlRegInputTokenPtr inputStack;/* when operating on strings */
 
334
 
 
335
    /*
 
336
     * error handling
 
337
     */
 
338
    int errStateNo;             /* the error state number */
 
339
    xmlRegStatePtr errState;    /* the error state */
 
340
    xmlChar *errString;         /* the string raising the error */
 
341
    int *errCounts;             /* counters at the error state */
 
342
    int nbPush;
 
343
};
 
344
 
 
345
#define REGEXP_ALL_COUNTER      0x123456
 
346
#define REGEXP_ALL_LAX_COUNTER  0x123457
 
347
 
 
348
static void xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top);
 
349
static void xmlRegFreeState(xmlRegStatePtr state);
 
350
static void xmlRegFreeAtom(xmlRegAtomPtr atom);
 
351
static int xmlRegStrEqualWildcard(const xmlChar *expStr, const xmlChar *valStr);
 
352
static int xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint);
 
353
static int xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint,
 
354
                  int neg, int start, int end, const xmlChar *blockName);
 
355
 
 
356
/************************************************************************
 
357
 *                                                                      *
 
358
 *              Regexp memory error handler                             *
 
359
 *                                                                      *
 
360
 ************************************************************************/
 
361
/**
 
362
 * xmlRegexpErrMemory:
 
363
 * @extra:  extra information
 
364
 *
 
365
 * Handle an out of memory condition
 
366
 */
 
367
static void
 
368
xmlRegexpErrMemory(xmlRegParserCtxtPtr ctxt, const char *extra)
 
369
{
 
370
    const char *regexp = NULL;
 
371
    if (ctxt != NULL) {
 
372
        regexp = (const char *) ctxt->string;
 
373
        ctxt->error = XML_ERR_NO_MEMORY;
 
374
    }
 
375
    __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP,
 
376
                    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
 
377
                    regexp, NULL, 0, 0,
 
378
                    "Memory allocation failed : %s\n", extra);
 
379
}
 
380
 
 
381
/**
 
382
 * xmlRegexpErrCompile:
 
383
 * @extra:  extra information
 
384
 *
 
385
 * Handle a compilation failure
 
386
 */
 
387
static void
 
388
xmlRegexpErrCompile(xmlRegParserCtxtPtr ctxt, const char *extra)
 
389
{
 
390
    const char *regexp = NULL;
 
391
    int idx = 0;
 
392
 
 
393
    if (ctxt != NULL) {
 
394
        regexp = (const char *) ctxt->string;
 
395
        idx = ctxt->cur - ctxt->string;
 
396
        ctxt->error = XML_REGEXP_COMPILE_ERROR;
 
397
    }
 
398
    __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP,
 
399
                    XML_REGEXP_COMPILE_ERROR, XML_ERR_FATAL, NULL, 0, extra,
 
400
                    regexp, NULL, idx, 0,
 
401
                    "failed to compile: %s\n", extra);
 
402
}
 
403
 
 
404
/************************************************************************
 
405
 *                                                                      *
 
406
 *                      Allocation/Deallocation                         *
 
407
 *                                                                      *
 
408
 ************************************************************************/
 
409
 
 
410
static int xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt);
 
411
/**
 
412
 * xmlRegEpxFromParse:
 
413
 * @ctxt:  the parser context used to build it
 
414
 *
 
415
 * Allocate a new regexp and fill it with the result from the parser
 
416
 *
 
417
 * Returns the new regexp or NULL in case of error
 
418
 */
 
419
static xmlRegexpPtr
 
420
xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
 
421
    xmlRegexpPtr ret;
 
422
 
 
423
    ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp));
 
424
    if (ret == NULL) {
 
425
        xmlRegexpErrMemory(ctxt, "compiling regexp");
 
426
        return(NULL);
 
427
    }
 
428
    memset(ret, 0, sizeof(xmlRegexp));
 
429
    ret->string = ctxt->string;
 
430
    ret->nbStates = ctxt->nbStates;
 
431
    ret->states = ctxt->states;
 
432
    ret->nbAtoms = ctxt->nbAtoms;
 
433
    ret->atoms = ctxt->atoms;
 
434
    ret->nbCounters = ctxt->nbCounters;
 
435
    ret->counters = ctxt->counters;
 
436
    ret->determinist = ctxt->determinist;
 
437
    if (ret->determinist == -1) {
 
438
        xmlRegexpIsDeterminist(ret);
 
439
    }
 
440
 
 
441
    if ((ret->determinist != 0) &&
 
442
        (ret->nbCounters == 0) &&
 
443
        (ctxt->negs == 0) &&
 
444
        (ret->atoms != NULL) &&
 
445
        (ret->atoms[0] != NULL) &&
 
446
        (ret->atoms[0]->type == XML_REGEXP_STRING)) {
 
447
        int i, j, nbstates = 0, nbatoms = 0;
 
448
        int *stateRemap;
 
449
        int *stringRemap;
 
450
        int *transitions;
 
451
        void **transdata;
 
452
        xmlChar **stringMap;
 
453
        xmlChar *value;
 
454
 
 
455
        /*
 
456
         * Switch to a compact representation
 
457
         * 1/ counting the effective number of states left
 
458
         * 2/ counting the unique number of atoms, and check that
 
459
         *    they are all of the string type
 
460
         * 3/ build a table state x atom for the transitions
 
461
         */
 
462
 
 
463
        stateRemap = xmlMalloc(ret->nbStates * sizeof(int));
 
464
        if (stateRemap == NULL) {
 
465
            xmlRegexpErrMemory(ctxt, "compiling regexp");
 
466
            xmlFree(ret);
 
467
            return(NULL);
 
468
        }
 
469
        for (i = 0;i < ret->nbStates;i++) {
 
470
            if (ret->states[i] != NULL) {
 
471
                stateRemap[i] = nbstates;
 
472
                nbstates++;
 
473
            } else {
 
474
                stateRemap[i] = -1;
 
475
            }
 
476
        }
 
477
#ifdef DEBUG_COMPACTION
 
478
        printf("Final: %d states\n", nbstates);
 
479
#endif
 
480
        stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *));
 
481
        if (stringMap == NULL) {
 
482
            xmlRegexpErrMemory(ctxt, "compiling regexp");
 
483
            xmlFree(stateRemap);
 
484
            xmlFree(ret);
 
485
            return(NULL);
 
486
        }
 
487
        stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int));
 
488
        if (stringRemap == NULL) {
 
489
            xmlRegexpErrMemory(ctxt, "compiling regexp");
 
490
            xmlFree(stringMap);
 
491
            xmlFree(stateRemap);
 
492
            xmlFree(ret);
 
493
            return(NULL);
 
494
        }
 
495
        for (i = 0;i < ret->nbAtoms;i++) {
 
496
            if ((ret->atoms[i]->type == XML_REGEXP_STRING) &&
 
497
                (ret->atoms[i]->quant == XML_REGEXP_QUANT_ONCE)) {
 
498
                value = ret->atoms[i]->valuep;
 
499
                for (j = 0;j < nbatoms;j++) {
 
500
                    if (xmlStrEqual(stringMap[j], value)) {
 
501
                        stringRemap[i] = j;
 
502
                        break;
 
503
                    }
 
504
                }
 
505
                if (j >= nbatoms) {
 
506
                    stringRemap[i] = nbatoms;
 
507
                    stringMap[nbatoms] = xmlStrdup(value);
 
508
                    if (stringMap[nbatoms] == NULL) {
 
509
                        for (i = 0;i < nbatoms;i++)
 
510
                            xmlFree(stringMap[i]);
 
511
                        xmlFree(stringRemap);
 
512
                        xmlFree(stringMap);
 
513
                        xmlFree(stateRemap);
 
514
                        xmlFree(ret);
 
515
                        return(NULL);
 
516
                    }
 
517
                    nbatoms++;
 
518
                }
 
519
            } else {
 
520
                xmlFree(stateRemap);
 
521
                xmlFree(stringRemap);
 
522
                for (i = 0;i < nbatoms;i++)
 
523
                    xmlFree(stringMap[i]);
 
524
                xmlFree(stringMap);
 
525
                xmlFree(ret);
 
526
                return(NULL);
 
527
            }
 
528
        }
 
529
#ifdef DEBUG_COMPACTION
 
530
        printf("Final: %d atoms\n", nbatoms);
 
531
#endif
 
532
        transitions = (int *) xmlMalloc((nbstates + 1) *
 
533
                                        (nbatoms + 1) * sizeof(int));
 
534
        if (transitions == NULL) {
 
535
            xmlFree(stateRemap);
 
536
            xmlFree(stringRemap);
 
537
            xmlFree(stringMap);
 
538
            xmlFree(ret);
 
539
            return(NULL);
 
540
        }
 
541
        memset(transitions, 0, (nbstates + 1) * (nbatoms + 1) * sizeof(int));
 
542
 
 
543
        /*
 
544
         * Allocate the transition table. The first entry for each
 
545
         * state corresponds to the state type.
 
546
         */
 
547
        transdata = NULL;
 
548
 
 
549
        for (i = 0;i < ret->nbStates;i++) {
 
550
            int stateno, atomno, targetno, prev;
 
551
            xmlRegStatePtr state;
 
552
            xmlRegTransPtr trans;
 
553
 
 
554
            stateno = stateRemap[i];
 
555
            if (stateno == -1)
 
556
                continue;
 
557
            state = ret->states[i];
 
558
 
 
559
            transitions[stateno * (nbatoms + 1)] = state->type;
 
560
 
 
561
            for (j = 0;j < state->nbTrans;j++) {
 
562
                trans = &(state->trans[j]);
 
563
                if ((trans->to == -1) || (trans->atom == NULL))
 
564
                    continue;
 
565
                atomno = stringRemap[trans->atom->no];
 
566
                if ((trans->atom->data != NULL) && (transdata == NULL)) {
 
567
                    transdata = (void **) xmlMalloc(nbstates * nbatoms *
 
568
                                                    sizeof(void *));
 
569
                    if (transdata != NULL)
 
570
                        memset(transdata, 0,
 
571
                               nbstates * nbatoms * sizeof(void *));
 
572
                    else {
 
573
                        xmlRegexpErrMemory(ctxt, "compiling regexp");
 
574
                        break;
 
575
                    }
 
576
                }
 
577
                targetno = stateRemap[trans->to];
 
578
                /*
 
579
                 * if the same atom can generate transitions to 2 different
 
580
                 * states then it means the automata is not determinist and
 
581
                 * the compact form can't be used !
 
582
                 */
 
583
                prev = transitions[stateno * (nbatoms + 1) + atomno + 1];
 
584
                if (prev != 0) {
 
585
                    if (prev != targetno + 1) {
 
586
                        ret->determinist = 0;
 
587
#ifdef DEBUG_COMPACTION
 
588
                        printf("Indet: state %d trans %d, atom %d to %d : %d to %d\n",
 
589
                               i, j, trans->atom->no, trans->to, atomno, targetno);
 
590
                        printf("       previous to is %d\n", prev);
 
591
#endif
 
592
                        if (transdata != NULL)
 
593
                            xmlFree(transdata);
 
594
                        xmlFree(transitions);
 
595
                        xmlFree(stateRemap);
 
596
                        xmlFree(stringRemap);
 
597
                        for (i = 0;i < nbatoms;i++)
 
598
                            xmlFree(stringMap[i]);
 
599
                        xmlFree(stringMap);
 
600
                        goto not_determ;
 
601
                    }
 
602
                } else {
 
603
#if 0
 
604
                    printf("State %d trans %d: atom %d to %d : %d to %d\n",
 
605
                           i, j, trans->atom->no, trans->to, atomno, targetno);
 
606
#endif
 
607
                    transitions[stateno * (nbatoms + 1) + atomno + 1] =
 
608
                        targetno + 1; /* to avoid 0 */
 
609
                    if (transdata != NULL)
 
610
                        transdata[stateno * nbatoms + atomno] =
 
611
                            trans->atom->data;
 
612
                }
 
613
            }
 
614
        }
 
615
        ret->determinist = 1;
 
616
#ifdef DEBUG_COMPACTION
 
617
        /*
 
618
         * Debug
 
619
         */
 
620
        for (i = 0;i < nbstates;i++) {
 
621
            for (j = 0;j < nbatoms + 1;j++) {
 
622
                printf("%02d ", transitions[i * (nbatoms + 1) + j]);
 
623
            }
 
624
            printf("\n");
 
625
        }
 
626
        printf("\n");
 
627
#endif
 
628
        /*
 
629
         * Cleanup of the old data
 
630
         */
 
631
        if (ret->states != NULL) {
 
632
            for (i = 0;i < ret->nbStates;i++)
 
633
                xmlRegFreeState(ret->states[i]);
 
634
            xmlFree(ret->states);
 
635
        }
 
636
        ret->states = NULL;
 
637
        ret->nbStates = 0;
 
638
        if (ret->atoms != NULL) {
 
639
            for (i = 0;i < ret->nbAtoms;i++)
 
640
                xmlRegFreeAtom(ret->atoms[i]);
 
641
            xmlFree(ret->atoms);
 
642
        }
 
643
        ret->atoms = NULL;
 
644
        ret->nbAtoms = 0;
 
645
 
 
646
        ret->compact = transitions;
 
647
        ret->transdata = transdata;
 
648
        ret->stringMap = stringMap;
 
649
        ret->nbstrings = nbatoms;
 
650
        ret->nbstates = nbstates;
 
651
        xmlFree(stateRemap);
 
652
        xmlFree(stringRemap);
 
653
    }
 
654
not_determ:
 
655
    ctxt->string = NULL;
 
656
    ctxt->nbStates = 0;
 
657
    ctxt->states = NULL;
 
658
    ctxt->nbAtoms = 0;
 
659
    ctxt->atoms = NULL;
 
660
    ctxt->nbCounters = 0;
 
661
    ctxt->counters = NULL;
 
662
    return(ret);
 
663
}
 
664
 
 
665
/**
 
666
 * xmlRegNewParserCtxt:
 
667
 * @string:  the string to parse
 
668
 *
 
669
 * Allocate a new regexp parser context
 
670
 *
 
671
 * Returns the new context or NULL in case of error
 
672
 */
 
673
static xmlRegParserCtxtPtr
 
674
xmlRegNewParserCtxt(const xmlChar *string) {
 
675
    xmlRegParserCtxtPtr ret;
 
676
 
 
677
    ret = (xmlRegParserCtxtPtr) xmlMalloc(sizeof(xmlRegParserCtxt));
 
678
    if (ret == NULL)
 
679
        return(NULL);
 
680
    memset(ret, 0, sizeof(xmlRegParserCtxt));
 
681
    if (string != NULL)
 
682
        ret->string = xmlStrdup(string);
 
683
    ret->cur = ret->string;
 
684
    ret->neg = 0;
 
685
    ret->negs = 0;
 
686
    ret->error = 0;
 
687
    ret->determinist = -1;
 
688
    return(ret);
 
689
}
 
690
 
 
691
/**
 
692
 * xmlRegNewRange:
 
693
 * @ctxt:  the regexp parser context
 
694
 * @neg:  is that negative
 
695
 * @type:  the type of range
 
696
 * @start:  the start codepoint
 
697
 * @end:  the end codepoint
 
698
 *
 
699
 * Allocate a new regexp range
 
700
 *
 
701
 * Returns the new range or NULL in case of error
 
702
 */
 
703
static xmlRegRangePtr
 
704
xmlRegNewRange(xmlRegParserCtxtPtr ctxt,
 
705
               int neg, xmlRegAtomType type, int start, int end) {
 
706
    xmlRegRangePtr ret;
 
707
 
 
708
    ret = (xmlRegRangePtr) xmlMalloc(sizeof(xmlRegRange));
 
709
    if (ret == NULL) {
 
710
        xmlRegexpErrMemory(ctxt, "allocating range");
 
711
        return(NULL);
 
712
    }
 
713
    ret->neg = neg;
 
714
    ret->type = type;
 
715
    ret->start = start;
 
716
    ret->end = end;
 
717
    return(ret);
 
718
}
 
719
 
 
720
/**
 
721
 * xmlRegFreeRange:
 
722
 * @range:  the regexp range
 
723
 *
 
724
 * Free a regexp range
 
725
 */
 
726
static void
 
727
xmlRegFreeRange(xmlRegRangePtr range) {
 
728
    if (range == NULL)
 
729
        return;
 
730
 
 
731
    if (range->blockName != NULL)
 
732
        xmlFree(range->blockName);
 
733
    xmlFree(range);
 
734
}
 
735
 
 
736
/**
 
737
 * xmlRegCopyRange:
 
738
 * @range:  the regexp range
 
739
 *
 
740
 * Copy a regexp range
 
741
 *
 
742
 * Returns the new copy or NULL in case of error.
 
743
 */
 
744
static xmlRegRangePtr
 
745
xmlRegCopyRange(xmlRegParserCtxtPtr ctxt, xmlRegRangePtr range) {
 
746
    xmlRegRangePtr ret;
 
747
 
 
748
    if (range == NULL)
 
749
        return(NULL);
 
750
 
 
751
    ret = xmlRegNewRange(ctxt, range->neg, range->type, range->start,
 
752
                         range->end);
 
753
    if (ret == NULL)
 
754
        return(NULL);
 
755
    if (range->blockName != NULL) {
 
756
        ret->blockName = xmlStrdup(range->blockName);
 
757
        if (ret->blockName == NULL) {
 
758
            xmlRegexpErrMemory(ctxt, "allocating range");
 
759
            xmlRegFreeRange(ret);
 
760
            return(NULL);
 
761
        }
 
762
    }
 
763
    return(ret);
 
764
}
 
765
 
 
766
/**
 
767
 * xmlRegNewAtom:
 
768
 * @ctxt:  the regexp parser context
 
769
 * @type:  the type of atom
 
770
 *
 
771
 * Allocate a new atom
 
772
 *
 
773
 * Returns the new atom or NULL in case of error
 
774
 */
 
775
static xmlRegAtomPtr
 
776
xmlRegNewAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomType type) {
 
777
    xmlRegAtomPtr ret;
 
778
 
 
779
    ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom));
 
780
    if (ret == NULL) {
 
781
        xmlRegexpErrMemory(ctxt, "allocating atom");
 
782
        return(NULL);
 
783
    }
 
784
    memset(ret, 0, sizeof(xmlRegAtom));
 
785
    ret->type = type;
 
786
    ret->quant = XML_REGEXP_QUANT_ONCE;
 
787
    ret->min = 0;
 
788
    ret->max = 0;
 
789
    return(ret);
 
790
}
 
791
 
 
792
/**
 
793
 * xmlRegFreeAtom:
 
794
 * @atom:  the regexp atom
 
795
 *
 
796
 * Free a regexp atom
 
797
 */
 
798
static void
 
799
xmlRegFreeAtom(xmlRegAtomPtr atom) {
 
800
    int i;
 
801
 
 
802
    if (atom == NULL)
 
803
        return;
 
804
 
 
805
    for (i = 0;i < atom->nbRanges;i++)
 
806
        xmlRegFreeRange(atom->ranges[i]);
 
807
    if (atom->ranges != NULL)
 
808
        xmlFree(atom->ranges);
 
809
    if ((atom->type == XML_REGEXP_STRING) && (atom->valuep != NULL))
 
810
        xmlFree(atom->valuep);
 
811
    if ((atom->type == XML_REGEXP_STRING) && (atom->valuep2 != NULL))
 
812
        xmlFree(atom->valuep2);
 
813
    if ((atom->type == XML_REGEXP_BLOCK_NAME) && (atom->valuep != NULL))
 
814
        xmlFree(atom->valuep);
 
815
    xmlFree(atom);
 
816
}
 
817
 
 
818
/**
 
819
 * xmlRegCopyAtom:
 
820
 * @ctxt:  the regexp parser context
 
821
 * @atom:  the oiginal atom
 
822
 *
 
823
 * Allocate a new regexp range
 
824
 *
 
825
 * Returns the new atom or NULL in case of error
 
826
 */
 
827
static xmlRegAtomPtr
 
828
xmlRegCopyAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
 
829
    xmlRegAtomPtr ret;
 
830
 
 
831
    ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom));
 
832
    if (ret == NULL) {
 
833
        xmlRegexpErrMemory(ctxt, "copying atom");
 
834
        return(NULL);
 
835
    }
 
836
    memset(ret, 0, sizeof(xmlRegAtom));
 
837
    ret->type = atom->type;
 
838
    ret->quant = atom->quant;
 
839
    ret->min = atom->min;
 
840
    ret->max = atom->max;
 
841
    if (atom->nbRanges > 0) {
 
842
        int i;
 
843
 
 
844
        ret->ranges = (xmlRegRangePtr *) xmlMalloc(sizeof(xmlRegRangePtr) *
 
845
                                                   atom->nbRanges);
 
846
        if (ret->ranges == NULL) {
 
847
            xmlRegexpErrMemory(ctxt, "copying atom");
 
848
            goto error;
 
849
        }
 
850
        for (i = 0;i < atom->nbRanges;i++) {
 
851
            ret->ranges[i] = xmlRegCopyRange(ctxt, atom->ranges[i]);
 
852
            if (ret->ranges[i] == NULL)
 
853
                goto error;
 
854
            ret->nbRanges = i + 1;
 
855
        }
 
856
    }
 
857
    return(ret);
 
858
 
 
859
error:
 
860
    xmlRegFreeAtom(ret);
 
861
    return(NULL);
 
862
}
 
863
 
 
864
static xmlRegStatePtr
 
865
xmlRegNewState(xmlRegParserCtxtPtr ctxt) {
 
866
    xmlRegStatePtr ret;
 
867
 
 
868
    ret = (xmlRegStatePtr) xmlMalloc(sizeof(xmlRegState));
 
869
    if (ret == NULL) {
 
870
        xmlRegexpErrMemory(ctxt, "allocating state");
 
871
        return(NULL);
 
872
    }
 
873
    memset(ret, 0, sizeof(xmlRegState));
 
874
    ret->type = XML_REGEXP_TRANS_STATE;
 
875
    ret->mark = XML_REGEXP_MARK_NORMAL;
 
876
    return(ret);
 
877
}
 
878
 
 
879
/**
 
880
 * xmlRegFreeState:
 
881
 * @state:  the regexp state
 
882
 *
 
883
 * Free a regexp state
 
884
 */
 
885
static void
 
886
xmlRegFreeState(xmlRegStatePtr state) {
 
887
    if (state == NULL)
 
888
        return;
 
889
 
 
890
    if (state->trans != NULL)
 
891
        xmlFree(state->trans);
 
892
    if (state->transTo != NULL)
 
893
        xmlFree(state->transTo);
 
894
    xmlFree(state);
 
895
}
 
896
 
 
897
/**
 
898
 * xmlRegFreeParserCtxt:
 
899
 * @ctxt:  the regexp parser context
 
900
 *
 
901
 * Free a regexp parser context
 
902
 */
 
903
static void
 
904
xmlRegFreeParserCtxt(xmlRegParserCtxtPtr ctxt) {
 
905
    int i;
 
906
    if (ctxt == NULL)
 
907
        return;
 
908
 
 
909
    if (ctxt->string != NULL)
 
910
        xmlFree(ctxt->string);
 
911
    if (ctxt->states != NULL) {
 
912
        for (i = 0;i < ctxt->nbStates;i++)
 
913
            xmlRegFreeState(ctxt->states[i]);
 
914
        xmlFree(ctxt->states);
 
915
    }
 
916
    if (ctxt->atoms != NULL) {
 
917
        for (i = 0;i < ctxt->nbAtoms;i++)
 
918
            xmlRegFreeAtom(ctxt->atoms[i]);
 
919
        xmlFree(ctxt->atoms);
 
920
    }
 
921
    if (ctxt->counters != NULL)
 
922
        xmlFree(ctxt->counters);
 
923
    xmlFree(ctxt);
 
924
}
 
925
 
 
926
/************************************************************************
 
927
 *                                                                      *
 
928
 *                      Display of Data structures                      *
 
929
 *                                                                      *
 
930
 ************************************************************************/
 
931
 
 
932
static void
 
933
xmlRegPrintAtomType(FILE *output, xmlRegAtomType type) {
 
934
    switch (type) {
 
935
        case XML_REGEXP_EPSILON:
 
936
            fprintf(output, "epsilon "); break;
 
937
        case XML_REGEXP_CHARVAL:
 
938
            fprintf(output, "charval "); break;
 
939
        case XML_REGEXP_RANGES:
 
940
            fprintf(output, "ranges "); break;
 
941
        case XML_REGEXP_SUBREG:
 
942
            fprintf(output, "subexpr "); break;
 
943
        case XML_REGEXP_STRING:
 
944
            fprintf(output, "string "); break;
 
945
        case XML_REGEXP_ANYCHAR:
 
946
            fprintf(output, "anychar "); break;
 
947
        case XML_REGEXP_ANYSPACE:
 
948
            fprintf(output, "anyspace "); break;
 
949
        case XML_REGEXP_NOTSPACE:
 
950
            fprintf(output, "notspace "); break;
 
951
        case XML_REGEXP_INITNAME:
 
952
            fprintf(output, "initname "); break;
 
953
        case XML_REGEXP_NOTINITNAME:
 
954
            fprintf(output, "notinitname "); break;
 
955
        case XML_REGEXP_NAMECHAR:
 
956
            fprintf(output, "namechar "); break;
 
957
        case XML_REGEXP_NOTNAMECHAR:
 
958
            fprintf(output, "notnamechar "); break;
 
959
        case XML_REGEXP_DECIMAL:
 
960
            fprintf(output, "decimal "); break;
 
961
        case XML_REGEXP_NOTDECIMAL:
 
962
            fprintf(output, "notdecimal "); break;
 
963
        case XML_REGEXP_REALCHAR:
 
964
            fprintf(output, "realchar "); break;
 
965
        case XML_REGEXP_NOTREALCHAR:
 
966
            fprintf(output, "notrealchar "); break;
 
967
        case XML_REGEXP_LETTER:
 
968
            fprintf(output, "LETTER "); break;
 
969
        case XML_REGEXP_LETTER_UPPERCASE:
 
970
            fprintf(output, "LETTER_UPPERCASE "); break;
 
971
        case XML_REGEXP_LETTER_LOWERCASE:
 
972
            fprintf(output, "LETTER_LOWERCASE "); break;
 
973
        case XML_REGEXP_LETTER_TITLECASE:
 
974
            fprintf(output, "LETTER_TITLECASE "); break;
 
975
        case XML_REGEXP_LETTER_MODIFIER:
 
976
            fprintf(output, "LETTER_MODIFIER "); break;
 
977
        case XML_REGEXP_LETTER_OTHERS:
 
978
            fprintf(output, "LETTER_OTHERS "); break;
 
979
        case XML_REGEXP_MARK:
 
980
            fprintf(output, "MARK "); break;
 
981
        case XML_REGEXP_MARK_NONSPACING:
 
982
            fprintf(output, "MARK_NONSPACING "); break;
 
983
        case XML_REGEXP_MARK_SPACECOMBINING:
 
984
            fprintf(output, "MARK_SPACECOMBINING "); break;
 
985
        case XML_REGEXP_MARK_ENCLOSING:
 
986
            fprintf(output, "MARK_ENCLOSING "); break;
 
987
        case XML_REGEXP_NUMBER:
 
988
            fprintf(output, "NUMBER "); break;
 
989
        case XML_REGEXP_NUMBER_DECIMAL:
 
990
            fprintf(output, "NUMBER_DECIMAL "); break;
 
991
        case XML_REGEXP_NUMBER_LETTER:
 
992
            fprintf(output, "NUMBER_LETTER "); break;
 
993
        case XML_REGEXP_NUMBER_OTHERS:
 
994
            fprintf(output, "NUMBER_OTHERS "); break;
 
995
        case XML_REGEXP_PUNCT:
 
996
            fprintf(output, "PUNCT "); break;
 
997
        case XML_REGEXP_PUNCT_CONNECTOR:
 
998
            fprintf(output, "PUNCT_CONNECTOR "); break;
 
999
        case XML_REGEXP_PUNCT_DASH:
 
1000
            fprintf(output, "PUNCT_DASH "); break;
 
1001
        case XML_REGEXP_PUNCT_OPEN:
 
1002
            fprintf(output, "PUNCT_OPEN "); break;
 
1003
        case XML_REGEXP_PUNCT_CLOSE:
 
1004
            fprintf(output, "PUNCT_CLOSE "); break;
 
1005
        case XML_REGEXP_PUNCT_INITQUOTE:
 
1006
            fprintf(output, "PUNCT_INITQUOTE "); break;
 
1007
        case XML_REGEXP_PUNCT_FINQUOTE:
 
1008
            fprintf(output, "PUNCT_FINQUOTE "); break;
 
1009
        case XML_REGEXP_PUNCT_OTHERS:
 
1010
            fprintf(output, "PUNCT_OTHERS "); break;
 
1011
        case XML_REGEXP_SEPAR:
 
1012
            fprintf(output, "SEPAR "); break;
 
1013
        case XML_REGEXP_SEPAR_SPACE:
 
1014
            fprintf(output, "SEPAR_SPACE "); break;
 
1015
        case XML_REGEXP_SEPAR_LINE:
 
1016
            fprintf(output, "SEPAR_LINE "); break;
 
1017
        case XML_REGEXP_SEPAR_PARA:
 
1018
            fprintf(output, "SEPAR_PARA "); break;
 
1019
        case XML_REGEXP_SYMBOL:
 
1020
            fprintf(output, "SYMBOL "); break;
 
1021
        case XML_REGEXP_SYMBOL_MATH:
 
1022
            fprintf(output, "SYMBOL_MATH "); break;
 
1023
        case XML_REGEXP_SYMBOL_CURRENCY:
 
1024
            fprintf(output, "SYMBOL_CURRENCY "); break;
 
1025
        case XML_REGEXP_SYMBOL_MODIFIER:
 
1026
            fprintf(output, "SYMBOL_MODIFIER "); break;
 
1027
        case XML_REGEXP_SYMBOL_OTHERS:
 
1028
            fprintf(output, "SYMBOL_OTHERS "); break;
 
1029
        case XML_REGEXP_OTHER:
 
1030
            fprintf(output, "OTHER "); break;
 
1031
        case XML_REGEXP_OTHER_CONTROL:
 
1032
            fprintf(output, "OTHER_CONTROL "); break;
 
1033
        case XML_REGEXP_OTHER_FORMAT:
 
1034
            fprintf(output, "OTHER_FORMAT "); break;
 
1035
        case XML_REGEXP_OTHER_PRIVATE:
 
1036
            fprintf(output, "OTHER_PRIVATE "); break;
 
1037
        case XML_REGEXP_OTHER_NA:
 
1038
            fprintf(output, "OTHER_NA "); break;
 
1039
        case XML_REGEXP_BLOCK_NAME:
 
1040
            fprintf(output, "BLOCK "); break;
 
1041
    }
 
1042
}
 
1043
 
 
1044
static void
 
1045
xmlRegPrintQuantType(FILE *output, xmlRegQuantType type) {
 
1046
    switch (type) {
 
1047
        case XML_REGEXP_QUANT_EPSILON:
 
1048
            fprintf(output, "epsilon "); break;
 
1049
        case XML_REGEXP_QUANT_ONCE:
 
1050
            fprintf(output, "once "); break;
 
1051
        case XML_REGEXP_QUANT_OPT:
 
1052
            fprintf(output, "? "); break;
 
1053
        case XML_REGEXP_QUANT_MULT:
 
1054
            fprintf(output, "* "); break;
 
1055
        case XML_REGEXP_QUANT_PLUS:
 
1056
            fprintf(output, "+ "); break;
 
1057
        case XML_REGEXP_QUANT_RANGE:
 
1058
            fprintf(output, "range "); break;
 
1059
        case XML_REGEXP_QUANT_ONCEONLY:
 
1060
            fprintf(output, "onceonly "); break;
 
1061
        case XML_REGEXP_QUANT_ALL:
 
1062
            fprintf(output, "all "); break;
 
1063
    }
 
1064
}
 
1065
static void
 
1066
xmlRegPrintRange(FILE *output, xmlRegRangePtr range) {
 
1067
    fprintf(output, "  range: ");
 
1068
    if (range->neg)
 
1069
        fprintf(output, "negative ");
 
1070
    xmlRegPrintAtomType(output, range->type);
 
1071
    fprintf(output, "%c - %c\n", range->start, range->end);
 
1072
}
 
1073
 
 
1074
static void
 
1075
xmlRegPrintAtom(FILE *output, xmlRegAtomPtr atom) {
 
1076
    fprintf(output, " atom: ");
 
1077
    if (atom == NULL) {
 
1078
        fprintf(output, "NULL\n");
 
1079
        return;
 
1080
    }
 
1081
    if (atom->neg)
 
1082
        fprintf(output, "not ");
 
1083
    xmlRegPrintAtomType(output, atom->type);
 
1084
    xmlRegPrintQuantType(output, atom->quant);
 
1085
    if (atom->quant == XML_REGEXP_QUANT_RANGE)
 
1086
        fprintf(output, "%d-%d ", atom->min, atom->max);
 
1087
    if (atom->type == XML_REGEXP_STRING)
 
1088
        fprintf(output, "'%s' ", (char *) atom->valuep);
 
1089
    if (atom->type == XML_REGEXP_CHARVAL)
 
1090
        fprintf(output, "char %c\n", atom->codepoint);
 
1091
    else if (atom->type == XML_REGEXP_RANGES) {
 
1092
        int i;
 
1093
        fprintf(output, "%d entries\n", atom->nbRanges);
 
1094
        for (i = 0; i < atom->nbRanges;i++)
 
1095
            xmlRegPrintRange(output, atom->ranges[i]);
 
1096
    } else if (atom->type == XML_REGEXP_SUBREG) {
 
1097
        fprintf(output, "start %d end %d\n", atom->start->no, atom->stop->no);
 
1098
    } else {
 
1099
        fprintf(output, "\n");
 
1100
    }
 
1101
}
 
1102
 
 
1103
static void
 
1104
xmlRegPrintTrans(FILE *output, xmlRegTransPtr trans) {
 
1105
    fprintf(output, "  trans: ");
 
1106
    if (trans == NULL) {
 
1107
        fprintf(output, "NULL\n");
 
1108
        return;
 
1109
    }
 
1110
    if (trans->to < 0) {
 
1111
        fprintf(output, "removed\n");
 
1112
        return;
 
1113
    }
 
1114
    if (trans->nd != 0) {
 
1115
        if (trans->nd == 2)
 
1116
            fprintf(output, "last not determinist, ");
 
1117
        else
 
1118
            fprintf(output, "not determinist, ");
 
1119
    }
 
1120
    if (trans->counter >= 0) {
 
1121
        fprintf(output, "counted %d, ", trans->counter);
 
1122
    }
 
1123
    if (trans->count == REGEXP_ALL_COUNTER) {
 
1124
        fprintf(output, "all transition, ");
 
1125
    } else if (trans->count >= 0) {
 
1126
        fprintf(output, "count based %d, ", trans->count);
 
1127
    }
 
1128
    if (trans->atom == NULL) {
 
1129
        fprintf(output, "epsilon to %d\n", trans->to);
 
1130
        return;
 
1131
    }
 
1132
    if (trans->atom->type == XML_REGEXP_CHARVAL)
 
1133
        fprintf(output, "char %c ", trans->atom->codepoint);
 
1134
    fprintf(output, "atom %d, to %d\n", trans->atom->no, trans->to);
 
1135
}
 
1136
    
 
1137
static void
 
1138
xmlRegPrintState(FILE *output, xmlRegStatePtr state) {
 
1139
    int i;
 
1140
 
 
1141
    fprintf(output, " state: ");
 
1142
    if (state == NULL) {
 
1143
        fprintf(output, "NULL\n");
 
1144
        return;
 
1145
    }
 
1146
    if (state->type == XML_REGEXP_START_STATE)
 
1147
        fprintf(output, "START ");
 
1148
    if (state->type == XML_REGEXP_FINAL_STATE)
 
1149
        fprintf(output, "FINAL ");
 
1150
    
 
1151
    fprintf(output, "%d, %d transitions:\n", state->no, state->nbTrans);
 
1152
    for (i = 0;i < state->nbTrans; i++) {
 
1153
        xmlRegPrintTrans(output, &(state->trans[i]));
 
1154
    }
 
1155
}
 
1156
 
 
1157
#ifdef DEBUG_REGEXP_GRAPH
 
1158
static void
 
1159
xmlRegPrintCtxt(FILE *output, xmlRegParserCtxtPtr ctxt) {
 
1160
    int i;
 
1161
 
 
1162
    fprintf(output, " ctxt: ");
 
1163
    if (ctxt == NULL) {
 
1164
        fprintf(output, "NULL\n");
 
1165
        return;
 
1166
    }
 
1167
    fprintf(output, "'%s' ", ctxt->string);
 
1168
    if (ctxt->error)
 
1169
        fprintf(output, "error ");
 
1170
    if (ctxt->neg)
 
1171
        fprintf(output, "neg ");
 
1172
    fprintf(output, "\n");
 
1173
    fprintf(output, "%d atoms:\n", ctxt->nbAtoms);
 
1174
    for (i = 0;i < ctxt->nbAtoms; i++) {
 
1175
        fprintf(output, " %02d ", i);
 
1176
        xmlRegPrintAtom(output, ctxt->atoms[i]);
 
1177
    }
 
1178
    if (ctxt->atom != NULL) {
 
1179
        fprintf(output, "current atom:\n");
 
1180
        xmlRegPrintAtom(output, ctxt->atom);
 
1181
    }
 
1182
    fprintf(output, "%d states:", ctxt->nbStates);
 
1183
    if (ctxt->start != NULL)
 
1184
        fprintf(output, " start: %d", ctxt->start->no);
 
1185
    if (ctxt->end != NULL)
 
1186
        fprintf(output, " end: %d", ctxt->end->no);
 
1187
    fprintf(output, "\n");
 
1188
    for (i = 0;i < ctxt->nbStates; i++) {
 
1189
        xmlRegPrintState(output, ctxt->states[i]);
 
1190
    }
 
1191
    fprintf(output, "%d counters:\n", ctxt->nbCounters);
 
1192
    for (i = 0;i < ctxt->nbCounters; i++) {
 
1193
        fprintf(output, " %d: min %d max %d\n", i, ctxt->counters[i].min,
 
1194
                                                ctxt->counters[i].max);
 
1195
    }
 
1196
}
 
1197
#endif
 
1198
 
 
1199
/************************************************************************
 
1200
 *                                                                      *
 
1201
 *               Finite Automata structures manipulations               *
 
1202
 *                                                                      *
 
1203
 ************************************************************************/
 
1204
 
 
1205
static void 
 
1206
xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom,
 
1207
                   int neg, xmlRegAtomType type, int start, int end,
 
1208
                   xmlChar *blockName) {
 
1209
    xmlRegRangePtr range;
 
1210
 
 
1211
    if (atom == NULL) {
 
1212
        ERROR("add range: atom is NULL");
 
1213
        return;
 
1214
    }
 
1215
    if (atom->type != XML_REGEXP_RANGES) {
 
1216
        ERROR("add range: atom is not ranges");
 
1217
        return;
 
1218
    }
 
1219
    if (atom->maxRanges == 0) {
 
1220
        atom->maxRanges = 4;
 
1221
        atom->ranges = (xmlRegRangePtr *) xmlMalloc(atom->maxRanges *
 
1222
                                             sizeof(xmlRegRangePtr));
 
1223
        if (atom->ranges == NULL) {
 
1224
            xmlRegexpErrMemory(ctxt, "adding ranges");
 
1225
            atom->maxRanges = 0;
 
1226
            return;
 
1227
        }
 
1228
    } else if (atom->nbRanges >= atom->maxRanges) {
 
1229
        xmlRegRangePtr *tmp;
 
1230
        atom->maxRanges *= 2;
 
1231
        tmp = (xmlRegRangePtr *) xmlRealloc(atom->ranges, atom->maxRanges *
 
1232
                                             sizeof(xmlRegRangePtr));
 
1233
        if (tmp == NULL) {
 
1234
            xmlRegexpErrMemory(ctxt, "adding ranges");
 
1235
            atom->maxRanges /= 2;
 
1236
            return;
 
1237
        }
 
1238
        atom->ranges = tmp;
 
1239
    }
 
1240
    range = xmlRegNewRange(ctxt, neg, type, start, end);
 
1241
    if (range == NULL)
 
1242
        return;
 
1243
    range->blockName = blockName;
 
1244
    atom->ranges[atom->nbRanges++] = range;
 
1245
    
 
1246
}
 
1247
 
 
1248
static int
 
1249
xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) {
 
1250
    if (ctxt->maxCounters == 0) {
 
1251
        ctxt->maxCounters = 4;
 
1252
        ctxt->counters = (xmlRegCounter *) xmlMalloc(ctxt->maxCounters *
 
1253
                                             sizeof(xmlRegCounter));
 
1254
        if (ctxt->counters == NULL) {
 
1255
            xmlRegexpErrMemory(ctxt, "allocating counter");
 
1256
            ctxt->maxCounters = 0;
 
1257
            return(-1);
 
1258
        }
 
1259
    } else if (ctxt->nbCounters >= ctxt->maxCounters) {
 
1260
        xmlRegCounter *tmp;
 
1261
        ctxt->maxCounters *= 2;
 
1262
        tmp = (xmlRegCounter *) xmlRealloc(ctxt->counters, ctxt->maxCounters *
 
1263
                                           sizeof(xmlRegCounter));
 
1264
        if (tmp == NULL) {
 
1265
            xmlRegexpErrMemory(ctxt, "allocating counter");
 
1266
            ctxt->maxCounters /= 2;
 
1267
            return(-1);
 
1268
        }
 
1269
        ctxt->counters = tmp;
 
1270
    }
 
1271
    ctxt->counters[ctxt->nbCounters].min = -1;
 
1272
    ctxt->counters[ctxt->nbCounters].max = -1;
 
1273
    return(ctxt->nbCounters++);
 
1274
}
 
1275
 
 
1276
static int 
 
1277
xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
 
1278
    if (atom == NULL) {
 
1279
        ERROR("atom push: atom is NULL");
 
1280
        return(-1);
 
1281
    }
 
1282
    if (ctxt->maxAtoms == 0) {
 
1283
        ctxt->maxAtoms = 4;
 
1284
        ctxt->atoms = (xmlRegAtomPtr *) xmlMalloc(ctxt->maxAtoms *
 
1285
                                             sizeof(xmlRegAtomPtr));
 
1286
        if (ctxt->atoms == NULL) {
 
1287
            xmlRegexpErrMemory(ctxt, "pushing atom");
 
1288
            ctxt->maxAtoms = 0;
 
1289
            return(-1);
 
1290
        }
 
1291
    } else if (ctxt->nbAtoms >= ctxt->maxAtoms) {
 
1292
        xmlRegAtomPtr *tmp;
 
1293
        ctxt->maxAtoms *= 2;
 
1294
        tmp = (xmlRegAtomPtr *) xmlRealloc(ctxt->atoms, ctxt->maxAtoms *
 
1295
                                             sizeof(xmlRegAtomPtr));
 
1296
        if (tmp == NULL) {
 
1297
            xmlRegexpErrMemory(ctxt, "allocating counter");
 
1298
            ctxt->maxAtoms /= 2;
 
1299
            return(-1);
 
1300
        }
 
1301
        ctxt->atoms = tmp;
 
1302
    }
 
1303
    atom->no = ctxt->nbAtoms;
 
1304
    ctxt->atoms[ctxt->nbAtoms++] = atom;
 
1305
    return(0);
 
1306
}
 
1307
 
 
1308
static void 
 
1309
xmlRegStateAddTransTo(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr target,
 
1310
                      int from) {
 
1311
    if (target->maxTransTo == 0) {
 
1312
        target->maxTransTo = 8;
 
1313
        target->transTo = (int *) xmlMalloc(target->maxTransTo *
 
1314
                                             sizeof(int));
 
1315
        if (target->transTo == NULL) {
 
1316
            xmlRegexpErrMemory(ctxt, "adding transition");
 
1317
            target->maxTransTo = 0;
 
1318
            return;
 
1319
        }
 
1320
    } else if (target->nbTransTo >= target->maxTransTo) {
 
1321
        int *tmp;
 
1322
        target->maxTransTo *= 2;
 
1323
        tmp = (int *) xmlRealloc(target->transTo, target->maxTransTo *
 
1324
                                             sizeof(int));
 
1325
        if (tmp == NULL) {
 
1326
            xmlRegexpErrMemory(ctxt, "adding transition");
 
1327
            target->maxTransTo /= 2;
 
1328
            return;
 
1329
        }
 
1330
        target->transTo = tmp;
 
1331
    }
 
1332
    target->transTo[target->nbTransTo] = from;
 
1333
    target->nbTransTo++;
 
1334
}
 
1335
 
 
1336
static void 
 
1337
xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
 
1338
                    xmlRegAtomPtr atom, xmlRegStatePtr target,
 
1339
                    int counter, int count) {
 
1340
 
 
1341
    int nrtrans;
 
1342
 
 
1343
    if (state == NULL) {
 
1344
        ERROR("add state: state is NULL");
 
1345
        return;
 
1346
    }
 
1347
    if (target == NULL) {
 
1348
        ERROR("add state: target is NULL");
 
1349
        return;
 
1350
    }
 
1351
    /*
 
1352
     * Other routines follow the philosophy 'When in doubt, add a transition'
 
1353
     * so we check here whether such a transition is already present and, if
 
1354
     * so, silently ignore this request.
 
1355
     */
 
1356
 
 
1357
    for (nrtrans = state->nbTrans - 1; nrtrans >= 0; nrtrans--) {
 
1358
        xmlRegTransPtr trans = &(state->trans[nrtrans]);
 
1359
        if ((trans->atom == atom) &&
 
1360
            (trans->to == target->no) &&
 
1361
            (trans->counter == counter) &&
 
1362
            (trans->count == count)) {
 
1363
#ifdef DEBUG_REGEXP_GRAPH
 
1364
            printf("Ignoring duplicate transition from %d to %d\n",
 
1365
                    state->no, target->no);
 
1366
#endif
 
1367
            return;
 
1368
        }
 
1369
    }
 
1370
 
 
1371
    if (state->maxTrans == 0) {
 
1372
        state->maxTrans = 8;
 
1373
        state->trans = (xmlRegTrans *) xmlMalloc(state->maxTrans *
 
1374
                                             sizeof(xmlRegTrans));
 
1375
        if (state->trans == NULL) {
 
1376
            xmlRegexpErrMemory(ctxt, "adding transition");
 
1377
            state->maxTrans = 0;
 
1378
            return;
 
1379
        }
 
1380
    } else if (state->nbTrans >= state->maxTrans) {
 
1381
        xmlRegTrans *tmp;
 
1382
        state->maxTrans *= 2;
 
1383
        tmp = (xmlRegTrans *) xmlRealloc(state->trans, state->maxTrans *
 
1384
                                             sizeof(xmlRegTrans));
 
1385
        if (tmp == NULL) {
 
1386
            xmlRegexpErrMemory(ctxt, "adding transition");
 
1387
            state->maxTrans /= 2;
 
1388
            return;
 
1389
        }
 
1390
        state->trans = tmp;
 
1391
    }
 
1392
#ifdef DEBUG_REGEXP_GRAPH
 
1393
    printf("Add trans from %d to %d ", state->no, target->no);
 
1394
    if (count == REGEXP_ALL_COUNTER)
 
1395
        printf("all transition\n");
 
1396
    else if (count >= 0)
 
1397
        printf("count based %d\n", count);
 
1398
    else if (counter >= 0)
 
1399
        printf("counted %d\n", counter);
 
1400
    else if (atom == NULL)
 
1401
        printf("epsilon transition\n");
 
1402
    else if (atom != NULL) 
 
1403
        xmlRegPrintAtom(stdout, atom);
 
1404
#endif
 
1405
 
 
1406
    state->trans[state->nbTrans].atom = atom;
 
1407
    state->trans[state->nbTrans].to = target->no;
 
1408
    state->trans[state->nbTrans].counter = counter;
 
1409
    state->trans[state->nbTrans].count = count;
 
1410
    state->trans[state->nbTrans].nd = 0;
 
1411
    state->nbTrans++;
 
1412
    xmlRegStateAddTransTo(ctxt, target, state->no);
 
1413
}
 
1414
 
 
1415
static int
 
1416
xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) {
 
1417
    if (state == NULL) return(-1);
 
1418
    if (ctxt->maxStates == 0) {
 
1419
        ctxt->maxStates = 4;
 
1420
        ctxt->states = (xmlRegStatePtr *) xmlMalloc(ctxt->maxStates *
 
1421
                                             sizeof(xmlRegStatePtr));
 
1422
        if (ctxt->states == NULL) {
 
1423
            xmlRegexpErrMemory(ctxt, "adding state");
 
1424
            ctxt->maxStates = 0;
 
1425
            return(-1);
 
1426
        }
 
1427
    } else if (ctxt->nbStates >= ctxt->maxStates) {
 
1428
        xmlRegStatePtr *tmp;
 
1429
        ctxt->maxStates *= 2;
 
1430
        tmp = (xmlRegStatePtr *) xmlRealloc(ctxt->states, ctxt->maxStates *
 
1431
                                             sizeof(xmlRegStatePtr));
 
1432
        if (tmp == NULL) {
 
1433
            xmlRegexpErrMemory(ctxt, "adding state");
 
1434
            ctxt->maxStates /= 2;
 
1435
            return(-1);
 
1436
        }
 
1437
        ctxt->states = tmp;
 
1438
    }
 
1439
    state->no = ctxt->nbStates;
 
1440
    ctxt->states[ctxt->nbStates++] = state;
 
1441
    return(0);
 
1442
}
 
1443
 
 
1444
/**
 
1445
 * xmlFAGenerateAllTransition:
 
1446
 * @ctxt:  a regexp parser context
 
1447
 * @from:  the from state
 
1448
 * @to:  the target state or NULL for building a new one
 
1449
 * @lax:
 
1450
 *
 
1451
 */
 
1452
static void
 
1453
xmlFAGenerateAllTransition(xmlRegParserCtxtPtr ctxt,
 
1454
                           xmlRegStatePtr from, xmlRegStatePtr to,
 
1455
                           int lax) {
 
1456
    if (to == NULL) {
 
1457
        to = xmlRegNewState(ctxt);
 
1458
        xmlRegStatePush(ctxt, to);
 
1459
        ctxt->state = to;
 
1460
    }
 
1461
    if (lax)
 
1462
        xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_LAX_COUNTER);
 
1463
    else
 
1464
        xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_COUNTER);
 
1465
}
 
1466
 
 
1467
/**
 
1468
 * xmlFAGenerateEpsilonTransition:
 
1469
 * @ctxt:  a regexp parser context
 
1470
 * @from:  the from state
 
1471
 * @to:  the target state or NULL for building a new one
 
1472
 *
 
1473
 */
 
1474
static void
 
1475
xmlFAGenerateEpsilonTransition(xmlRegParserCtxtPtr ctxt,
 
1476
                               xmlRegStatePtr from, xmlRegStatePtr to) {
 
1477
    if (to == NULL) {
 
1478
        to = xmlRegNewState(ctxt);
 
1479
        xmlRegStatePush(ctxt, to);
 
1480
        ctxt->state = to;
 
1481
    }
 
1482
    xmlRegStateAddTrans(ctxt, from, NULL, to, -1, -1);
 
1483
}
 
1484
 
 
1485
/**
 
1486
 * xmlFAGenerateCountedEpsilonTransition:
 
1487
 * @ctxt:  a regexp parser context
 
1488
 * @from:  the from state
 
1489
 * @to:  the target state or NULL for building a new one
 
1490
 * counter:  the counter for that transition
 
1491
 *
 
1492
 */
 
1493
static void
 
1494
xmlFAGenerateCountedEpsilonTransition(xmlRegParserCtxtPtr ctxt,
 
1495
            xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
 
1496
    if (to == NULL) {
 
1497
        to = xmlRegNewState(ctxt);
 
1498
        xmlRegStatePush(ctxt, to);
 
1499
        ctxt->state = to;
 
1500
    }
 
1501
    xmlRegStateAddTrans(ctxt, from, NULL, to, counter, -1);
 
1502
}
 
1503
 
 
1504
/**
 
1505
 * xmlFAGenerateCountedTransition:
 
1506
 * @ctxt:  a regexp parser context
 
1507
 * @from:  the from state
 
1508
 * @to:  the target state or NULL for building a new one
 
1509
 * counter:  the counter for that transition
 
1510
 *
 
1511
 */
 
1512
static void
 
1513
xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt,
 
1514
            xmlRegStatePtr from, xmlRegStatePtr to, int counter) {
 
1515
    if (to == NULL) {
 
1516
        to = xmlRegNewState(ctxt);
 
1517
        xmlRegStatePush(ctxt, to);
 
1518
        ctxt->state = to;
 
1519
    }
 
1520
    xmlRegStateAddTrans(ctxt, from, NULL, to, -1, counter);
 
1521
}
 
1522
 
 
1523
/**
 
1524
 * xmlFAGenerateTransitions:
 
1525
 * @ctxt:  a regexp parser context
 
1526
 * @from:  the from state
 
1527
 * @to:  the target state or NULL for building a new one
 
1528
 * @atom:  the atom generating the transition
 
1529
 *
 
1530
 * Returns 0 if success and -1 in case of error.
 
1531
 */
 
1532
static int
 
1533
xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from,
 
1534
                         xmlRegStatePtr to, xmlRegAtomPtr atom) {
 
1535
    xmlRegStatePtr end;
 
1536
 
 
1537
    if (atom == NULL) {
 
1538
        ERROR("genrate transition: atom == NULL");
 
1539
        return(-1);
 
1540
    }
 
1541
    if (atom->type == XML_REGEXP_SUBREG) {
 
1542
        /*
 
1543
         * this is a subexpression handling one should not need to
 
1544
         * create a new node except for XML_REGEXP_QUANT_RANGE.
 
1545
         */
 
1546
        if (xmlRegAtomPush(ctxt, atom) < 0) {
 
1547
            return(-1);
 
1548
        }
 
1549
        if ((to != NULL) && (atom->stop != to) &&
 
1550
            (atom->quant != XML_REGEXP_QUANT_RANGE)) {
 
1551
            /*
 
1552
             * Generate an epsilon transition to link to the target
 
1553
             */
 
1554
            xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to);
 
1555
#ifdef DV
 
1556
        } else if ((to == NULL) && (atom->quant != XML_REGEXP_QUANT_RANGE) && 
 
1557
                   (atom->quant != XML_REGEXP_QUANT_ONCE)) {
 
1558
            to = xmlRegNewState(ctxt);
 
1559
            xmlRegStatePush(ctxt, to);
 
1560
            ctxt->state = to;
 
1561
            xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to);
 
1562
#endif
 
1563
        }
 
1564
        switch (atom->quant) {
 
1565
            case XML_REGEXP_QUANT_OPT:
 
1566
                atom->quant = XML_REGEXP_QUANT_ONCE;
 
1567
                /*
 
1568
                 * transition done to the state after end of atom.
 
1569
                 *      1. set transition from atom start to new state
 
1570
                 *      2. set transition from atom end to this state. 
 
1571
                 */
 
1572
                xmlFAGenerateEpsilonTransition(ctxt, atom->start, 0);
 
1573
                xmlFAGenerateEpsilonTransition(ctxt, atom->stop, ctxt->state);
 
1574
                break;
 
1575
            case XML_REGEXP_QUANT_MULT:
 
1576
                atom->quant = XML_REGEXP_QUANT_ONCE;
 
1577
                xmlFAGenerateEpsilonTransition(ctxt, atom->start, atom->stop);
 
1578
                xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
 
1579
                break;
 
1580
            case XML_REGEXP_QUANT_PLUS:
 
1581
                atom->quant = XML_REGEXP_QUANT_ONCE;
 
1582
                xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start);
 
1583
                break;
 
1584
            case XML_REGEXP_QUANT_RANGE: {
 
1585
                int counter;
 
1586
                xmlRegStatePtr inter, newstate;
 
1587
 
 
1588
                /*
 
1589
                 * create the final state now if needed
 
1590
                 */
 
1591
                if (to != NULL) {
 
1592
                    newstate = to;
 
1593
                } else {
 
1594
                    newstate = xmlRegNewState(ctxt);
 
1595
                    xmlRegStatePush(ctxt, newstate);
 
1596
                }
 
1597
 
 
1598
                /*
 
1599
                 * The principle here is to use counted transition
 
1600
                 * to avoid explosion in the number of states in the
 
1601
                 * graph. This is clearly more complex but should not
 
1602
                 * be exploitable at runtime.
 
1603
                 */
 
1604
                if ((atom->min == 0) && (atom->start0 == NULL)) {
 
1605
                    xmlRegAtomPtr copy;
 
1606
                    /*
 
1607
                     * duplicate a transition based on atom to count next
 
1608
                     * occurences after 1. We cannot loop to atom->start
 
1609
                     * directly because we need an epsilon transition to 
 
1610
                     * newstate.
 
1611
                     */
 
1612
                     /* ???? For some reason it seems we never reach that
 
1613
                        case, I suppose this got optimized out before when
 
1614
                        building the automata */
 
1615
                    copy = xmlRegCopyAtom(ctxt, atom);
 
1616
                    if (copy == NULL)
 
1617
                        return(-1);
 
1618
                    copy->quant = XML_REGEXP_QUANT_ONCE;
 
1619
                    copy->min = 0;
 
1620
                    copy->max = 0;
 
1621
 
 
1622
                    if (xmlFAGenerateTransitions(ctxt, atom->start, NULL, copy)
 
1623
                        < 0)
 
1624
                        return(-1);
 
1625
                    inter = ctxt->state;
 
1626
                    counter = xmlRegGetCounter(ctxt);
 
1627
                    ctxt->counters[counter].min = atom->min - 1;
 
1628
                    ctxt->counters[counter].max = atom->max - 1;
 
1629
                    /* count the number of times we see it again */
 
1630
                    xmlFAGenerateCountedEpsilonTransition(ctxt, inter,
 
1631
                                                   atom->stop, counter);
 
1632
                    /* allow a way out based on the count */
 
1633
                    xmlFAGenerateCountedTransition(ctxt, inter,
 
1634
                                                   newstate, counter);
 
1635
                    /* and also allow a direct exit for 0 */
 
1636
                    xmlFAGenerateEpsilonTransition(ctxt, atom->start,
 
1637
                                                   newstate);
 
1638
                } else {
 
1639
                    /*
 
1640
                     * either we need the atom at least once or there
 
1641
                     * is an atom->start0 allowing to easilly plug the
 
1642
                     * epsilon transition.
 
1643
                     */
 
1644
                    counter = xmlRegGetCounter(ctxt);
 
1645
                    ctxt->counters[counter].min = atom->min - 1;
 
1646
                    ctxt->counters[counter].max = atom->max - 1;
 
1647
                    /* count the number of times we see it again */
 
1648
                    xmlFAGenerateCountedEpsilonTransition(ctxt, atom->stop,
 
1649
                                                   atom->start, counter);
 
1650
                    /* allow a way out based on the count */
 
1651
                    xmlFAGenerateCountedTransition(ctxt, atom->stop,
 
1652
                                                   newstate, counter);
 
1653
                    /* and if needed allow a direct exit for 0 */
 
1654
                    if (atom->min == 0)
 
1655
                        xmlFAGenerateEpsilonTransition(ctxt, atom->start0,
 
1656
                                                       newstate);
 
1657
 
 
1658
                }
 
1659
                atom->min = 0;
 
1660
                atom->max = 0;
 
1661
                atom->quant = XML_REGEXP_QUANT_ONCE;
 
1662
                ctxt->state = newstate;
 
1663
            }
 
1664
            default:
 
1665
                break;
 
1666
        }
 
1667
        return(0);
 
1668
    } 
 
1669
    if ((atom->min == 0) && (atom->max == 0) &&
 
1670
               (atom->quant == XML_REGEXP_QUANT_RANGE)) {
 
1671
        /*
 
1672
         * we can discard the atom and generate an epsilon transition instead
 
1673
         */
 
1674
        if (to == NULL) {
 
1675
            to = xmlRegNewState(ctxt);
 
1676
            if (to != NULL)
 
1677
                xmlRegStatePush(ctxt, to);
 
1678
            else {
 
1679
                return(-1);
 
1680
            }
 
1681
        }
 
1682
        xmlFAGenerateEpsilonTransition(ctxt, from, to);
 
1683
        ctxt->state = to;
 
1684
        xmlRegFreeAtom(atom);
 
1685
        return(0);
 
1686
    }
 
1687
    if (to == NULL) {
 
1688
        to = xmlRegNewState(ctxt);
 
1689
        if (to != NULL)
 
1690
            xmlRegStatePush(ctxt, to);
 
1691
        else {
 
1692
            return(-1);
 
1693
        }
 
1694
    } 
 
1695
    end = to;
 
1696
    if ((atom->quant == XML_REGEXP_QUANT_MULT) || 
 
1697
        (atom->quant == XML_REGEXP_QUANT_PLUS)) {
 
1698
        /*
 
1699
         * Do not pollute the target state by adding transitions from
 
1700
         * it as it is likely to be the shared target of multiple branches.
 
1701
         * So isolate with an epsilon transition.
 
1702
         */
 
1703
        xmlRegStatePtr tmp;
 
1704
        
 
1705
        tmp = xmlRegNewState(ctxt);
 
1706
        if (tmp != NULL)
 
1707
            xmlRegStatePush(ctxt, tmp);
 
1708
        else {
 
1709
            return(-1);
 
1710
        }
 
1711
        xmlFAGenerateEpsilonTransition(ctxt, tmp, to);
 
1712
        to = tmp;
 
1713
    }
 
1714
    if (xmlRegAtomPush(ctxt, atom) < 0) {
 
1715
        return(-1);
 
1716
    }
 
1717
    xmlRegStateAddTrans(ctxt, from, atom, to, -1, -1);
 
1718
    ctxt->state = end;
 
1719
    switch (atom->quant) {
 
1720
        case XML_REGEXP_QUANT_OPT:
 
1721
            atom->quant = XML_REGEXP_QUANT_ONCE;
 
1722
            xmlFAGenerateEpsilonTransition(ctxt, from, to);
 
1723
            break;
 
1724
        case XML_REGEXP_QUANT_MULT:
 
1725
            atom->quant = XML_REGEXP_QUANT_ONCE;
 
1726
            xmlFAGenerateEpsilonTransition(ctxt, from, to);
 
1727
            xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
 
1728
            break;
 
1729
        case XML_REGEXP_QUANT_PLUS:
 
1730
            atom->quant = XML_REGEXP_QUANT_ONCE;
 
1731
            xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1);
 
1732
            break;
 
1733
        case XML_REGEXP_QUANT_RANGE: 
 
1734
#if DV_test
 
1735
            if (atom->min == 0) {
 
1736
                xmlFAGenerateEpsilonTransition(ctxt, from, to);
 
1737
            }
 
1738
#endif
 
1739
            break;
 
1740
        default:
 
1741
            break;
 
1742
    }
 
1743
    return(0);
 
1744
}
 
1745
 
 
1746
/**
 
1747
 * xmlFAReduceEpsilonTransitions:
 
1748
 * @ctxt:  a regexp parser context
 
1749
 * @fromnr:  the from state
 
1750
 * @tonr:  the to state 
 
1751
 * @counter:  should that transition be associated to a counted
 
1752
 *
 
1753
 */
 
1754
static void
 
1755
xmlFAReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int fromnr,
 
1756
                              int tonr, int counter) {
 
1757
    int transnr;
 
1758
    xmlRegStatePtr from;
 
1759
    xmlRegStatePtr to;
 
1760
 
 
1761
#ifdef DEBUG_REGEXP_GRAPH
 
1762
    printf("xmlFAReduceEpsilonTransitions(%d, %d)\n", fromnr, tonr);
 
1763
#endif
 
1764
    from = ctxt->states[fromnr];
 
1765
    if (from == NULL)
 
1766
        return;
 
1767
    to = ctxt->states[tonr];
 
1768
    if (to == NULL)
 
1769
        return;
 
1770
    if ((to->mark == XML_REGEXP_MARK_START) ||
 
1771
        (to->mark == XML_REGEXP_MARK_VISITED))
 
1772
        return;
 
1773
 
 
1774
    to->mark = XML_REGEXP_MARK_VISITED;
 
1775
    if (to->type == XML_REGEXP_FINAL_STATE) {
 
1776
#ifdef DEBUG_REGEXP_GRAPH
 
1777
        printf("State %d is final, so %d becomes final\n", tonr, fromnr);
 
1778
#endif
 
1779
        from->type = XML_REGEXP_FINAL_STATE;
 
1780
    }
 
1781
    for (transnr = 0;transnr < to->nbTrans;transnr++) {
 
1782
        if (to->trans[transnr].to < 0)
 
1783
            continue;
 
1784
        if (to->trans[transnr].atom == NULL) {
 
1785
            /*
 
1786
             * Don't remove counted transitions
 
1787
             * Don't loop either
 
1788
             */
 
1789
            if (to->trans[transnr].to != fromnr) {
 
1790
                if (to->trans[transnr].count >= 0) {
 
1791
                    int newto = to->trans[transnr].to;
 
1792
 
 
1793
                    xmlRegStateAddTrans(ctxt, from, NULL,
 
1794
                                        ctxt->states[newto], 
 
1795
                                        -1, to->trans[transnr].count);
 
1796
                } else {
 
1797
#ifdef DEBUG_REGEXP_GRAPH
 
1798
                    printf("Found epsilon trans %d from %d to %d\n",
 
1799
                           transnr, tonr, to->trans[transnr].to);
 
1800
#endif
 
1801
                    if (to->trans[transnr].counter >= 0) {
 
1802
                        xmlFAReduceEpsilonTransitions(ctxt, fromnr,
 
1803
                                              to->trans[transnr].to,
 
1804
                                              to->trans[transnr].counter);
 
1805
                    } else {
 
1806
                        xmlFAReduceEpsilonTransitions(ctxt, fromnr,
 
1807
                                              to->trans[transnr].to,
 
1808
                                              counter);
 
1809
                    }
 
1810
                }
 
1811
            }
 
1812
        } else {
 
1813
            int newto = to->trans[transnr].to;
 
1814
 
 
1815
            if (to->trans[transnr].counter >= 0) {
 
1816
                xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, 
 
1817
                                    ctxt->states[newto], 
 
1818
                                    to->trans[transnr].counter, -1);
 
1819
            } else {
 
1820
                xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, 
 
1821
                                    ctxt->states[newto], counter, -1);
 
1822
            }
 
1823
        }
 
1824
    }
 
1825
    to->mark = XML_REGEXP_MARK_NORMAL;
 
1826
}
 
1827
 
 
1828
/**
 
1829
 * xmlFAEliminateSimpleEpsilonTransitions:
 
1830
 * @ctxt:  a regexp parser context
 
1831
 *
 
1832
 * Eliminating general epsilon transitions can get costly in the general 
 
1833
 * algorithm due to the large amount of generated new transitions and
 
1834
 * associated comparisons. However for simple epsilon transition used just
 
1835
 * to separate building blocks when generating the automata this can be
 
1836
 * reduced to state elimination:
 
1837
 *    - if there exists an epsilon from X to Y
 
1838
 *    - if there is no other transition from X
 
1839
 * then X and Y are semantically equivalent and X can be eliminated
 
1840
 * If X is the start state then make Y the start state, else replace the
 
1841
 * target of all transitions to X by transitions to Y.
 
1842
 */
 
1843
static void
 
1844
xmlFAEliminateSimpleEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
 
1845
    int statenr, i, j, newto;
 
1846
    xmlRegStatePtr state, tmp;
 
1847
 
 
1848
    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
 
1849
        state = ctxt->states[statenr];
 
1850
        if (state == NULL)
 
1851
            continue;
 
1852
        if (state->nbTrans != 1)
 
1853
            continue;
 
1854
        if (state->type == XML_REGEXP_UNREACH_STATE)
 
1855
            continue;
 
1856
        /* is the only transition out a basic transition */
 
1857
        if ((state->trans[0].atom == NULL) &&
 
1858
            (state->trans[0].to >= 0) &&
 
1859
            (state->trans[0].to != statenr) &&
 
1860
            (state->trans[0].counter < 0) &&
 
1861
            (state->trans[0].count < 0)) {
 
1862
            newto = state->trans[0].to;
 
1863
 
 
1864
            if (state->type == XML_REGEXP_START_STATE) {
 
1865
#ifdef DEBUG_REGEXP_GRAPH
 
1866
                printf("Found simple epsilon trans from start %d to %d\n",
 
1867
                       statenr, newto);
 
1868
#endif     
 
1869
            } else {
 
1870
#ifdef DEBUG_REGEXP_GRAPH
 
1871
                printf("Found simple epsilon trans from %d to %d\n",
 
1872
                       statenr, newto);
 
1873
#endif     
 
1874
                for (i = 0;i < state->nbTransTo;i++) {
 
1875
                    tmp = ctxt->states[state->transTo[i]];
 
1876
                    for (j = 0;j < tmp->nbTrans;j++) {
 
1877
                        if (tmp->trans[j].to == statenr) {
 
1878
#ifdef DEBUG_REGEXP_GRAPH
 
1879
                            printf("Changed transition %d on %d to go to %d\n",
 
1880
                                   j, tmp->no, newto);
 
1881
#endif     
 
1882
                            tmp->trans[j].to = -1;
 
1883
                            xmlRegStateAddTrans(ctxt, tmp, tmp->trans[j].atom,
 
1884
                                                ctxt->states[newto],
 
1885
                                                tmp->trans[j].counter,
 
1886
                                                tmp->trans[j].count);
 
1887
                        }
 
1888
                    }
 
1889
                }
 
1890
                if (state->type == XML_REGEXP_FINAL_STATE)
 
1891
                    ctxt->states[newto]->type = XML_REGEXP_FINAL_STATE;
 
1892
                /* eliminate the transition completely */
 
1893
                state->nbTrans = 0;
 
1894
 
 
1895
                state->type = XML_REGEXP_UNREACH_STATE;
 
1896
 
 
1897
            }
 
1898
            
 
1899
        }
 
1900
    }
 
1901
}
 
1902
/**
 
1903
 * xmlFAEliminateEpsilonTransitions:
 
1904
 * @ctxt:  a regexp parser context
 
1905
 *
 
1906
 */
 
1907
static void
 
1908
xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) {
 
1909
    int statenr, transnr;
 
1910
    xmlRegStatePtr state;
 
1911
    int has_epsilon;
 
1912
 
 
1913
    if (ctxt->states == NULL) return;
 
1914
 
 
1915
    /*
 
1916
     * Eliminate simple epsilon transition and the associated unreachable
 
1917
     * states.
 
1918
     */
 
1919
    xmlFAEliminateSimpleEpsilonTransitions(ctxt);
 
1920
    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
 
1921
        state = ctxt->states[statenr];
 
1922
        if ((state != NULL) && (state->type == XML_REGEXP_UNREACH_STATE)) {
 
1923
#ifdef DEBUG_REGEXP_GRAPH
 
1924
            printf("Removed unreachable state %d\n", statenr);
 
1925
#endif
 
1926
            xmlRegFreeState(state);
 
1927
            ctxt->states[statenr] = NULL;
 
1928
        }
 
1929
    }
 
1930
 
 
1931
    has_epsilon = 0;
 
1932
 
 
1933
    /*
 
1934
     * Build the completed transitions bypassing the epsilons
 
1935
     * Use a marking algorithm to avoid loops
 
1936
     * Mark sink states too.
 
1937
     * Process from the latests states backward to the start when
 
1938
     * there is long cascading epsilon chains this minimize the
 
1939
     * recursions and transition compares when adding the new ones
 
1940
     */
 
1941
    for (statenr = ctxt->nbStates - 1;statenr >= 0;statenr--) {
 
1942
        state = ctxt->states[statenr];
 
1943
        if (state == NULL)
 
1944
            continue;
 
1945
        if ((state->nbTrans == 0) &&
 
1946
            (state->type != XML_REGEXP_FINAL_STATE)) {
 
1947
            state->type = XML_REGEXP_SINK_STATE;
 
1948
        }
 
1949
        for (transnr = 0;transnr < state->nbTrans;transnr++) {
 
1950
            if ((state->trans[transnr].atom == NULL) &&
 
1951
                (state->trans[transnr].to >= 0)) {
 
1952
                if (state->trans[transnr].to == statenr) {
 
1953
                    state->trans[transnr].to = -1;
 
1954
#ifdef DEBUG_REGEXP_GRAPH
 
1955
                    printf("Removed loopback epsilon trans %d on %d\n",
 
1956
                           transnr, statenr);
 
1957
#endif
 
1958
                } else if (state->trans[transnr].count < 0) {
 
1959
                    int newto = state->trans[transnr].to;
 
1960
 
 
1961
#ifdef DEBUG_REGEXP_GRAPH
 
1962
                    printf("Found epsilon trans %d from %d to %d\n",
 
1963
                           transnr, statenr, newto);
 
1964
#endif
 
1965
                    has_epsilon = 1;
 
1966
                    state->trans[transnr].to = -2;
 
1967
                    state->mark = XML_REGEXP_MARK_START;
 
1968
                    xmlFAReduceEpsilonTransitions(ctxt, statenr,
 
1969
                                      newto, state->trans[transnr].counter);
 
1970
                    state->mark = XML_REGEXP_MARK_NORMAL;
 
1971
#ifdef DEBUG_REGEXP_GRAPH
 
1972
                } else {
 
1973
                    printf("Found counted transition %d on %d\n",
 
1974
                           transnr, statenr);
 
1975
#endif
 
1976
                }
 
1977
            }
 
1978
        }
 
1979
    }
 
1980
    /*
 
1981
     * Eliminate the epsilon transitions
 
1982
     */
 
1983
    if (has_epsilon) {
 
1984
        for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
 
1985
            state = ctxt->states[statenr];
 
1986
            if (state == NULL)
 
1987
                continue;
 
1988
            for (transnr = 0;transnr < state->nbTrans;transnr++) {
 
1989
                xmlRegTransPtr trans = &(state->trans[transnr]);
 
1990
                if ((trans->atom == NULL) &&
 
1991
                    (trans->count < 0) &&
 
1992
                    (trans->to >= 0)) {
 
1993
                    trans->to = -1;
 
1994
                }
 
1995
            }
 
1996
        }
 
1997
    }
 
1998
 
 
1999
    /*
 
2000
     * Use this pass to detect unreachable states too
 
2001
     */
 
2002
    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
 
2003
        state = ctxt->states[statenr];
 
2004
        if (state != NULL)
 
2005
            state->reached = XML_REGEXP_MARK_NORMAL;
 
2006
    }
 
2007
    state = ctxt->states[0];
 
2008
    if (state != NULL)
 
2009
        state->reached = XML_REGEXP_MARK_START;
 
2010
    while (state != NULL) {
 
2011
        xmlRegStatePtr target = NULL;
 
2012
        state->reached = XML_REGEXP_MARK_VISITED;
 
2013
        /*
 
2014
         * Mark all states reachable from the current reachable state
 
2015
         */
 
2016
        for (transnr = 0;transnr < state->nbTrans;transnr++) {
 
2017
            if ((state->trans[transnr].to >= 0) &&
 
2018
                ((state->trans[transnr].atom != NULL) ||
 
2019
                 (state->trans[transnr].count >= 0))) {
 
2020
                int newto = state->trans[transnr].to;
 
2021
 
 
2022
                if (ctxt->states[newto] == NULL)
 
2023
                    continue;
 
2024
                if (ctxt->states[newto]->reached == XML_REGEXP_MARK_NORMAL) {
 
2025
                    ctxt->states[newto]->reached = XML_REGEXP_MARK_START;
 
2026
                    target = ctxt->states[newto];
 
2027
                }
 
2028
            }
 
2029
        }
 
2030
 
 
2031
        /*
 
2032
         * find the next accessible state not explored
 
2033
         */
 
2034
        if (target == NULL) {
 
2035
            for (statenr = 1;statenr < ctxt->nbStates;statenr++) {
 
2036
                state = ctxt->states[statenr];
 
2037
                if ((state != NULL) && (state->reached ==
 
2038
                        XML_REGEXP_MARK_START)) {
 
2039
                    target = state;
 
2040
                    break;
 
2041
                }
 
2042
            }
 
2043
        }
 
2044
        state = target;
 
2045
    }
 
2046
    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
 
2047
        state = ctxt->states[statenr];
 
2048
        if ((state != NULL) && (state->reached == XML_REGEXP_MARK_NORMAL)) {
 
2049
#ifdef DEBUG_REGEXP_GRAPH
 
2050
            printf("Removed unreachable state %d\n", statenr);
 
2051
#endif
 
2052
            xmlRegFreeState(state);
 
2053
            ctxt->states[statenr] = NULL;
 
2054
        }
 
2055
    }
 
2056
 
 
2057
}
 
2058
 
 
2059
static int
 
2060
xmlFACompareRanges(xmlRegRangePtr range1, xmlRegRangePtr range2) {
 
2061
    int ret = 0;
 
2062
 
 
2063
    if ((range1->type == XML_REGEXP_RANGES) ||
 
2064
        (range2->type == XML_REGEXP_RANGES) ||
 
2065
        (range2->type == XML_REGEXP_SUBREG) ||
 
2066
        (range1->type == XML_REGEXP_SUBREG) ||
 
2067
        (range1->type == XML_REGEXP_STRING) ||
 
2068
        (range2->type == XML_REGEXP_STRING))
 
2069
        return(-1);
 
2070
 
 
2071
    /* put them in order */
 
2072
    if (range1->type > range2->type) {
 
2073
        xmlRegRangePtr tmp;
 
2074
 
 
2075
        tmp = range1;
 
2076
        range1 = range2;
 
2077
        range2 = tmp;
 
2078
    }
 
2079
    if ((range1->type == XML_REGEXP_ANYCHAR) ||
 
2080
        (range2->type == XML_REGEXP_ANYCHAR)) {
 
2081
        ret = 1;
 
2082
    } else if ((range1->type == XML_REGEXP_EPSILON) ||
 
2083
               (range2->type == XML_REGEXP_EPSILON)) {
 
2084
        return(0);
 
2085
    } else if (range1->type == range2->type) {
 
2086
        if ((range1->type != XML_REGEXP_CHARVAL) ||
 
2087
            (range1->end < range2->start) ||
 
2088
            (range2->end < range1->start))
 
2089
            ret = 1;
 
2090
        else
 
2091
            ret = 0;
 
2092
    } else if (range1->type == XML_REGEXP_CHARVAL) {
 
2093
        int codepoint;
 
2094
        int neg = 0;
 
2095
 
 
2096
        /*
 
2097
         * just check all codepoints in the range for acceptance,
 
2098
         * this is usually way cheaper since done only once at
 
2099
         * compilation than testing over and over at runtime or 
 
2100
         * pushing too many states when evaluating.
 
2101
         */
 
2102
        if (((range1->neg == 0) && (range2->neg != 0)) ||
 
2103
            ((range1->neg != 0) && (range2->neg == 0)))
 
2104
            neg = 1;
 
2105
 
 
2106
        for (codepoint = range1->start;codepoint <= range1->end ;codepoint++) {
 
2107
            ret = xmlRegCheckCharacterRange(range2->type, codepoint,
 
2108
                                            0, range2->start, range2->end,
 
2109
                                            range2->blockName);
 
2110
            if (ret < 0)
 
2111
                return(-1);
 
2112
            if (((neg == 1) && (ret == 0)) ||
 
2113
                ((neg == 0) && (ret == 1)))
 
2114
                return(1);
 
2115
        }
 
2116
        return(0);
 
2117
    } else if ((range1->type == XML_REGEXP_BLOCK_NAME) ||
 
2118
               (range2->type == XML_REGEXP_BLOCK_NAME)) {
 
2119
        if (range1->type == range2->type) {
 
2120
            ret = xmlStrEqual(range1->blockName, range2->blockName);
 
2121
        } else {
 
2122
            /*
 
2123
             * comparing a block range with anything else is way
 
2124
             * too costly, and maintining the table is like too much
 
2125
             * memory too, so let's force the automata to save state
 
2126
             * here.
 
2127
             */
 
2128
            return(1);
 
2129
        }
 
2130
    } else if ((range1->type < XML_REGEXP_LETTER) ||
 
2131
               (range2->type < XML_REGEXP_LETTER)) {
 
2132
        if ((range1->type == XML_REGEXP_ANYSPACE) &&
 
2133
            (range2->type == XML_REGEXP_NOTSPACE))
 
2134
            ret = 0;
 
2135
        else if ((range1->type == XML_REGEXP_INITNAME) &&
 
2136
                 (range2->type == XML_REGEXP_NOTINITNAME))
 
2137
            ret = 0;
 
2138
        else if ((range1->type == XML_REGEXP_NAMECHAR) &&
 
2139
                 (range2->type == XML_REGEXP_NOTNAMECHAR))
 
2140
            ret = 0;
 
2141
        else if ((range1->type == XML_REGEXP_DECIMAL) &&
 
2142
                 (range2->type == XML_REGEXP_NOTDECIMAL))
 
2143
            ret = 0;
 
2144
        else if ((range1->type == XML_REGEXP_REALCHAR) &&
 
2145
                 (range2->type == XML_REGEXP_NOTREALCHAR))
 
2146
            ret = 0;
 
2147
        else {
 
2148
            /* same thing to limit complexity */
 
2149
            return(1);
 
2150
        }
 
2151
    } else {
 
2152
        ret = 0;
 
2153
        /* range1->type < range2->type here */
 
2154
        switch (range1->type) {
 
2155
            case XML_REGEXP_LETTER:
 
2156
                 /* all disjoint except in the subgroups */
 
2157
                 if ((range2->type == XML_REGEXP_LETTER_UPPERCASE) ||
 
2158
                     (range2->type == XML_REGEXP_LETTER_LOWERCASE) ||
 
2159
                     (range2->type == XML_REGEXP_LETTER_TITLECASE) ||
 
2160
                     (range2->type == XML_REGEXP_LETTER_MODIFIER) ||
 
2161
                     (range2->type == XML_REGEXP_LETTER_OTHERS))
 
2162
                     ret = 1;
 
2163
                 break;
 
2164
            case XML_REGEXP_MARK:
 
2165
                 if ((range2->type == XML_REGEXP_MARK_NONSPACING) ||
 
2166
                     (range2->type == XML_REGEXP_MARK_SPACECOMBINING) ||
 
2167
                     (range2->type == XML_REGEXP_MARK_ENCLOSING))
 
2168
                     ret = 1;
 
2169
                 break;
 
2170
            case XML_REGEXP_NUMBER:
 
2171
                 if ((range2->type == XML_REGEXP_NUMBER_DECIMAL) ||
 
2172
                     (range2->type == XML_REGEXP_NUMBER_LETTER) ||
 
2173
                     (range2->type == XML_REGEXP_NUMBER_OTHERS))
 
2174
                     ret = 1;
 
2175
                 break;
 
2176
            case XML_REGEXP_PUNCT:
 
2177
                 if ((range2->type == XML_REGEXP_PUNCT_CONNECTOR) ||
 
2178
                     (range2->type == XML_REGEXP_PUNCT_DASH) ||
 
2179
                     (range2->type == XML_REGEXP_PUNCT_OPEN) ||
 
2180
                     (range2->type == XML_REGEXP_PUNCT_CLOSE) ||
 
2181
                     (range2->type == XML_REGEXP_PUNCT_INITQUOTE) ||
 
2182
                     (range2->type == XML_REGEXP_PUNCT_FINQUOTE) ||
 
2183
                     (range2->type == XML_REGEXP_PUNCT_OTHERS))
 
2184
                     ret = 1;
 
2185
                 break;
 
2186
            case XML_REGEXP_SEPAR:
 
2187
                 if ((range2->type == XML_REGEXP_SEPAR_SPACE) ||
 
2188
                     (range2->type == XML_REGEXP_SEPAR_LINE) ||
 
2189
                     (range2->type == XML_REGEXP_SEPAR_PARA))
 
2190
                     ret = 1;
 
2191
                 break;
 
2192
            case XML_REGEXP_SYMBOL:
 
2193
                 if ((range2->type == XML_REGEXP_SYMBOL_MATH) ||
 
2194
                     (range2->type == XML_REGEXP_SYMBOL_CURRENCY) ||
 
2195
                     (range2->type == XML_REGEXP_SYMBOL_MODIFIER) ||
 
2196
                     (range2->type == XML_REGEXP_SYMBOL_OTHERS))
 
2197
                     ret = 1;
 
2198
                 break;
 
2199
            case XML_REGEXP_OTHER:
 
2200
                 if ((range2->type == XML_REGEXP_OTHER_CONTROL) ||
 
2201
                     (range2->type == XML_REGEXP_OTHER_FORMAT) ||
 
2202
                     (range2->type == XML_REGEXP_OTHER_PRIVATE))
 
2203
                     ret = 1;
 
2204
                 break;
 
2205
            default:
 
2206
                 if ((range2->type >= XML_REGEXP_LETTER) &&
 
2207
                     (range2->type < XML_REGEXP_BLOCK_NAME))
 
2208
                     ret = 0;
 
2209
                 else {
 
2210
                     /* safety net ! */
 
2211
                     return(1);
 
2212
                 }
 
2213
        }
 
2214
    }
 
2215
    if (((range1->neg == 0) && (range2->neg != 0)) ||
 
2216
        ((range1->neg != 0) && (range2->neg == 0)))
 
2217
        ret = !ret;
 
2218
    return(1);
 
2219
}
 
2220
 
 
2221
/**
 
2222
 * xmlFACompareAtomTypes:
 
2223
 * @type1:  an atom type
 
2224
 * @type2:  an atom type
 
2225
 *
 
2226
 * Compares two atoms type to check whether they intersect in some ways,
 
2227
 * this is used by xmlFACompareAtoms only
 
2228
 *
 
2229
 * Returns 1 if they may intersect and 0 otherwise
 
2230
 */
 
2231
static int
 
2232
xmlFACompareAtomTypes(xmlRegAtomType type1, xmlRegAtomType type2) {
 
2233
    if ((type1 == XML_REGEXP_EPSILON) ||
 
2234
        (type1 == XML_REGEXP_CHARVAL) ||
 
2235
        (type1 == XML_REGEXP_RANGES) ||
 
2236
        (type1 == XML_REGEXP_SUBREG) ||
 
2237
        (type1 == XML_REGEXP_STRING) ||
 
2238
        (type1 == XML_REGEXP_ANYCHAR))
 
2239
        return(1);
 
2240
    if ((type2 == XML_REGEXP_EPSILON) ||
 
2241
        (type2 == XML_REGEXP_CHARVAL) ||
 
2242
        (type2 == XML_REGEXP_RANGES) ||
 
2243
        (type2 == XML_REGEXP_SUBREG) ||
 
2244
        (type2 == XML_REGEXP_STRING) ||
 
2245
        (type2 == XML_REGEXP_ANYCHAR))
 
2246
        return(1);
 
2247
 
 
2248
    if (type1 == type2) return(1);
 
2249
 
 
2250
    /* simplify subsequent compares by making sure type1 < type2 */
 
2251
    if (type1 > type2) {
 
2252
        xmlRegAtomType tmp = type1;
 
2253
        type1 = type2;
 
2254
        type2 = tmp;
 
2255
    }
 
2256
    switch (type1) {
 
2257
        case XML_REGEXP_ANYSPACE: /* \s */
 
2258
            /* can't be a letter, number, mark, pontuation, symbol */
 
2259
            if ((type2 == XML_REGEXP_NOTSPACE) ||
 
2260
                ((type2 >= XML_REGEXP_LETTER) &&
 
2261
                 (type2 <= XML_REGEXP_LETTER_OTHERS)) ||
 
2262
                ((type2 >= XML_REGEXP_NUMBER) &&
 
2263
                 (type2 <= XML_REGEXP_NUMBER_OTHERS)) ||
 
2264
                ((type2 >= XML_REGEXP_MARK) &&
 
2265
                 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
 
2266
                ((type2 >= XML_REGEXP_PUNCT) &&
 
2267
                 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
 
2268
                ((type2 >= XML_REGEXP_SYMBOL) &&
 
2269
                 (type2 <= XML_REGEXP_SYMBOL_OTHERS))
 
2270
                ) return(0);
 
2271
            break;
 
2272
        case XML_REGEXP_NOTSPACE: /* \S */
 
2273
            break;
 
2274
        case XML_REGEXP_INITNAME: /* \l */
 
2275
            /* can't be a number, mark, separator, pontuation, symbol or other */
 
2276
            if ((type2 == XML_REGEXP_NOTINITNAME) ||
 
2277
                ((type2 >= XML_REGEXP_NUMBER) &&
 
2278
                 (type2 <= XML_REGEXP_NUMBER_OTHERS)) ||
 
2279
                ((type2 >= XML_REGEXP_MARK) &&
 
2280
                 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
 
2281
                ((type2 >= XML_REGEXP_SEPAR) &&
 
2282
                 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
 
2283
                ((type2 >= XML_REGEXP_PUNCT) &&
 
2284
                 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
 
2285
                ((type2 >= XML_REGEXP_SYMBOL) &&
 
2286
                 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
 
2287
                ((type2 >= XML_REGEXP_OTHER) &&
 
2288
                 (type2 <= XML_REGEXP_OTHER_NA))
 
2289
                ) return(0);
 
2290
            break;
 
2291
        case XML_REGEXP_NOTINITNAME: /* \L */
 
2292
            break;
 
2293
        case XML_REGEXP_NAMECHAR: /* \c */
 
2294
            /* can't be a mark, separator, pontuation, symbol or other */
 
2295
            if ((type2 == XML_REGEXP_NOTNAMECHAR) ||
 
2296
                ((type2 >= XML_REGEXP_MARK) &&
 
2297
                 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
 
2298
                ((type2 >= XML_REGEXP_PUNCT) &&
 
2299
                 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
 
2300
                ((type2 >= XML_REGEXP_SEPAR) &&
 
2301
                 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
 
2302
                ((type2 >= XML_REGEXP_SYMBOL) &&
 
2303
                 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
 
2304
                ((type2 >= XML_REGEXP_OTHER) &&
 
2305
                 (type2 <= XML_REGEXP_OTHER_NA))
 
2306
                ) return(0);
 
2307
            break;
 
2308
        case XML_REGEXP_NOTNAMECHAR: /* \C */
 
2309
            break;
 
2310
        case XML_REGEXP_DECIMAL: /* \d */
 
2311
            /* can't be a letter, mark, separator, pontuation, symbol or other */
 
2312
            if ((type2 == XML_REGEXP_NOTDECIMAL) ||
 
2313
                (type2 == XML_REGEXP_REALCHAR) ||
 
2314
                ((type2 >= XML_REGEXP_LETTER) &&
 
2315
                 (type2 <= XML_REGEXP_LETTER_OTHERS)) ||
 
2316
                ((type2 >= XML_REGEXP_MARK) &&
 
2317
                 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
 
2318
                ((type2 >= XML_REGEXP_PUNCT) &&
 
2319
                 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
 
2320
                ((type2 >= XML_REGEXP_SEPAR) &&
 
2321
                 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
 
2322
                ((type2 >= XML_REGEXP_SYMBOL) &&
 
2323
                 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
 
2324
                ((type2 >= XML_REGEXP_OTHER) &&
 
2325
                 (type2 <= XML_REGEXP_OTHER_NA))
 
2326
                )return(0);
 
2327
            break;
 
2328
        case XML_REGEXP_NOTDECIMAL: /* \D */
 
2329
            break;
 
2330
        case XML_REGEXP_REALCHAR: /* \w */
 
2331
            /* can't be a mark, separator, pontuation, symbol or other */
 
2332
            if ((type2 == XML_REGEXP_NOTDECIMAL) ||
 
2333
                ((type2 >= XML_REGEXP_MARK) &&
 
2334
                 (type2 <= XML_REGEXP_MARK_ENCLOSING)) ||
 
2335
                ((type2 >= XML_REGEXP_PUNCT) &&
 
2336
                 (type2 <= XML_REGEXP_PUNCT_OTHERS)) ||
 
2337
                ((type2 >= XML_REGEXP_SEPAR) &&
 
2338
                 (type2 <= XML_REGEXP_SEPAR_PARA)) ||
 
2339
                ((type2 >= XML_REGEXP_SYMBOL) &&
 
2340
                 (type2 <= XML_REGEXP_SYMBOL_OTHERS)) ||
 
2341
                ((type2 >= XML_REGEXP_OTHER) &&
 
2342
                 (type2 <= XML_REGEXP_OTHER_NA))
 
2343
                )return(0);
 
2344
            break;
 
2345
        case XML_REGEXP_NOTREALCHAR: /* \W */
 
2346
            break;
 
2347
        /*
 
2348
         * at that point we know both type 1 and type2 are from
 
2349
         * character categories are ordered and are different,
 
2350
         * it becomes simple because this is a partition
 
2351
         */
 
2352
        case XML_REGEXP_LETTER:
 
2353
            if (type2 <= XML_REGEXP_LETTER_OTHERS)
 
2354
                return(1);
 
2355
            return(0);
 
2356
        case XML_REGEXP_LETTER_UPPERCASE:
 
2357
        case XML_REGEXP_LETTER_LOWERCASE:
 
2358
        case XML_REGEXP_LETTER_TITLECASE:
 
2359
        case XML_REGEXP_LETTER_MODIFIER:
 
2360
        case XML_REGEXP_LETTER_OTHERS:
 
2361
            return(0);
 
2362
        case XML_REGEXP_MARK:
 
2363
            if (type2 <= XML_REGEXP_MARK_ENCLOSING)
 
2364
                return(1);
 
2365
            return(0);
 
2366
        case XML_REGEXP_MARK_NONSPACING:
 
2367
        case XML_REGEXP_MARK_SPACECOMBINING:
 
2368
        case XML_REGEXP_MARK_ENCLOSING:
 
2369
            return(0);
 
2370
        case XML_REGEXP_NUMBER:
 
2371
            if (type2 <= XML_REGEXP_NUMBER_OTHERS)
 
2372
                return(1);
 
2373
            return(0);
 
2374
        case XML_REGEXP_NUMBER_DECIMAL:
 
2375
        case XML_REGEXP_NUMBER_LETTER:
 
2376
        case XML_REGEXP_NUMBER_OTHERS:
 
2377
            return(0);
 
2378
        case XML_REGEXP_PUNCT:
 
2379
            if (type2 <= XML_REGEXP_PUNCT_OTHERS)
 
2380
                return(1);
 
2381
            return(0);
 
2382
        case XML_REGEXP_PUNCT_CONNECTOR:
 
2383
        case XML_REGEXP_PUNCT_DASH:
 
2384
        case XML_REGEXP_PUNCT_OPEN:
 
2385
        case XML_REGEXP_PUNCT_CLOSE:
 
2386
        case XML_REGEXP_PUNCT_INITQUOTE:
 
2387
        case XML_REGEXP_PUNCT_FINQUOTE:
 
2388
        case XML_REGEXP_PUNCT_OTHERS:
 
2389
            return(0);
 
2390
        case XML_REGEXP_SEPAR:
 
2391
            if (type2 <= XML_REGEXP_SEPAR_PARA)
 
2392
                return(1);
 
2393
            return(0);
 
2394
        case XML_REGEXP_SEPAR_SPACE:
 
2395
        case XML_REGEXP_SEPAR_LINE:
 
2396
        case XML_REGEXP_SEPAR_PARA:
 
2397
            return(0);
 
2398
        case XML_REGEXP_SYMBOL:
 
2399
            if (type2 <= XML_REGEXP_SYMBOL_OTHERS)
 
2400
                return(1);
 
2401
            return(0);
 
2402
        case XML_REGEXP_SYMBOL_MATH:
 
2403
        case XML_REGEXP_SYMBOL_CURRENCY:
 
2404
        case XML_REGEXP_SYMBOL_MODIFIER:
 
2405
        case XML_REGEXP_SYMBOL_OTHERS:
 
2406
            return(0);
 
2407
        case XML_REGEXP_OTHER:
 
2408
            if (type2 <= XML_REGEXP_OTHER_NA)
 
2409
                return(1);
 
2410
            return(0);
 
2411
        case XML_REGEXP_OTHER_CONTROL:
 
2412
        case XML_REGEXP_OTHER_FORMAT:
 
2413
        case XML_REGEXP_OTHER_PRIVATE:
 
2414
        case XML_REGEXP_OTHER_NA:
 
2415
            return(0);
 
2416
        default:
 
2417
            break;
 
2418
    }
 
2419
    return(1);
 
2420
}
 
2421
 
 
2422
/**
 
2423
 * xmlFAEqualAtoms:
 
2424
 * @atom1:  an atom
 
2425
 * @atom2:  an atom
 
2426
 *
 
2427
 * Compares two atoms to check whether they are the same exactly
 
2428
 * this is used to remove equivalent transitions
 
2429
 *
 
2430
 * Returns 1 if same and 0 otherwise
 
2431
 */
 
2432
static int
 
2433
xmlFAEqualAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2) {
 
2434
    int ret = 0;
 
2435
 
 
2436
    if (atom1 == atom2)
 
2437
        return(1);
 
2438
    if ((atom1 == NULL) || (atom2 == NULL))
 
2439
        return(0);
 
2440
 
 
2441
    if (atom1->type != atom2->type)
 
2442
        return(0);
 
2443
    switch (atom1->type) {
 
2444
        case XML_REGEXP_EPSILON:
 
2445
            ret = 0;
 
2446
            break;
 
2447
        case XML_REGEXP_STRING:
 
2448
            ret = xmlStrEqual((xmlChar *)atom1->valuep,
 
2449
                              (xmlChar *)atom2->valuep);
 
2450
            break;
 
2451
        case XML_REGEXP_CHARVAL:
 
2452
            ret = (atom1->codepoint == atom2->codepoint);
 
2453
            break;
 
2454
        case XML_REGEXP_RANGES:
 
2455
            /* too hard to do in the general case */
 
2456
            ret = 0;
 
2457
        default:
 
2458
            break;
 
2459
    }
 
2460
    return(ret);
 
2461
}
 
2462
 
 
2463
/**
 
2464
 * xmlFACompareAtoms:
 
2465
 * @atom1:  an atom
 
2466
 * @atom2:  an atom
 
2467
 *
 
2468
 * Compares two atoms to check whether they intersect in some ways,
 
2469
 * this is used by xmlFAComputesDeterminism and xmlFARecurseDeterminism only
 
2470
 *
 
2471
 * Returns 1 if yes and 0 otherwise
 
2472
 */
 
2473
static int
 
2474
xmlFACompareAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2) {
 
2475
    int ret = 1;
 
2476
 
 
2477
    if (atom1 == atom2)
 
2478
        return(1);
 
2479
    if ((atom1 == NULL) || (atom2 == NULL))
 
2480
        return(0);
 
2481
 
 
2482
    if ((atom1->type == XML_REGEXP_ANYCHAR) ||
 
2483
        (atom2->type == XML_REGEXP_ANYCHAR))
 
2484
        return(1);
 
2485
 
 
2486
    if (atom1->type > atom2->type) {
 
2487
        xmlRegAtomPtr tmp;
 
2488
        tmp = atom1;
 
2489
        atom1 = atom2;
 
2490
        atom2 = tmp;
 
2491
    }
 
2492
    if (atom1->type != atom2->type) {
 
2493
        ret = xmlFACompareAtomTypes(atom1->type, atom2->type);
 
2494
        /* if they can't intersect at the type level break now */
 
2495
        if (ret == 0)
 
2496
            return(0);
 
2497
    }
 
2498
    switch (atom1->type) {
 
2499
        case XML_REGEXP_STRING:
 
2500
            ret = xmlRegStrEqualWildcard((xmlChar *)atom1->valuep,
 
2501
                                         (xmlChar *)atom2->valuep);
 
2502
            break;
 
2503
        case XML_REGEXP_EPSILON:
 
2504
            goto not_determinist;
 
2505
        case XML_REGEXP_CHARVAL:
 
2506
            if (atom2->type == XML_REGEXP_CHARVAL) {
 
2507
                ret = (atom1->codepoint == atom2->codepoint);
 
2508
            } else {
 
2509
                ret = xmlRegCheckCharacter(atom2, atom1->codepoint);
 
2510
                if (ret < 0)
 
2511
                    ret = 1;
 
2512
            }
 
2513
            break;
 
2514
        case XML_REGEXP_RANGES:
 
2515
            if (atom2->type == XML_REGEXP_RANGES) {
 
2516
                int i, j, res;
 
2517
                xmlRegRangePtr r1, r2;
 
2518
 
 
2519
                /*
 
2520
                 * need to check that none of the ranges eventually matches
 
2521
                 */
 
2522
                for (i = 0;i < atom1->nbRanges;i++) {
 
2523
                    for (j = 0;j < atom2->nbRanges;j++) {
 
2524
                        r1 = atom1->ranges[i];
 
2525
                        r2 = atom2->ranges[j];
 
2526
                        res = xmlFACompareRanges(r1, r2);
 
2527
                        if (res == 1) {
 
2528
                            ret = 1;
 
2529
                            goto done;
 
2530
                        }
 
2531
                    }
 
2532
                }
 
2533
                ret = 0;
 
2534
            }
 
2535
            break;
 
2536
        default:
 
2537
            goto not_determinist;
 
2538
    }
 
2539
done:
 
2540
    if (atom1->neg != atom2->neg) {
 
2541
        ret = !ret;
 
2542
    }
 
2543
    if (ret == 0)
 
2544
        return(0);
 
2545
not_determinist:
 
2546
    return(1);
 
2547
}
 
2548
 
 
2549
/**
 
2550
 * xmlFARecurseDeterminism:
 
2551
 * @ctxt:  a regexp parser context
 
2552
 *
 
2553
 * Check whether the associated regexp is determinist,
 
2554
 * should be called after xmlFAEliminateEpsilonTransitions()
 
2555
 *
 
2556
 */
 
2557
static int
 
2558
xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state,
 
2559
                         int to, xmlRegAtomPtr atom) {
 
2560
    int ret = 1;
 
2561
    int res;
 
2562
    int transnr, nbTrans;
 
2563
    xmlRegTransPtr t1;
 
2564
 
 
2565
    if (state == NULL)
 
2566
        return(ret);
 
2567
    /*
 
2568
     * don't recurse on transitions potentially added in the course of
 
2569
     * the elimination.
 
2570
     */
 
2571
    nbTrans = state->nbTrans;
 
2572
    for (transnr = 0;transnr < nbTrans;transnr++) {
 
2573
        t1 = &(state->trans[transnr]);
 
2574
        /*
 
2575
         * check transitions conflicting with the one looked at
 
2576
         */
 
2577
        if (t1->atom == NULL) {
 
2578
            if (t1->to < 0)
 
2579
                continue;
 
2580
            res = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
 
2581
                                           to, atom);
 
2582
            if (res == 0) {
 
2583
                ret = 0;
 
2584
                /* t1->nd = 1; */
 
2585
            }
 
2586
            continue;
 
2587
        }
 
2588
        if (t1->to != to)
 
2589
            continue;
 
2590
        if (xmlFACompareAtoms(t1->atom, atom)) {
 
2591
            ret = 0;
 
2592
            /* mark the transition as non-deterministic */
 
2593
            t1->nd = 1;
 
2594
        }
 
2595
    }
 
2596
    return(ret);
 
2597
}
 
2598
 
 
2599
/**
 
2600
 * xmlFAComputesDeterminism:
 
2601
 * @ctxt:  a regexp parser context
 
2602
 *
 
2603
 * Check whether the associated regexp is determinist,
 
2604
 * should be called after xmlFAEliminateEpsilonTransitions()
 
2605
 *
 
2606
 */
 
2607
static int
 
2608
xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) {
 
2609
    int statenr, transnr;
 
2610
    xmlRegStatePtr state;
 
2611
    xmlRegTransPtr t1, t2, last;
 
2612
    int i;
 
2613
    int ret = 1;
 
2614
 
 
2615
#ifdef DEBUG_REGEXP_GRAPH
 
2616
    printf("xmlFAComputesDeterminism\n");
 
2617
    xmlRegPrintCtxt(stdout, ctxt);
 
2618
#endif
 
2619
    if (ctxt->determinist != -1)
 
2620
        return(ctxt->determinist);
 
2621
 
 
2622
    /*
 
2623
     * First cleanup the automata removing cancelled transitions
 
2624
     */
 
2625
    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
 
2626
        state = ctxt->states[statenr];
 
2627
        if (state == NULL)
 
2628
            continue;
 
2629
        if (state->nbTrans < 2)
 
2630
            continue;
 
2631
        for (transnr = 0;transnr < state->nbTrans;transnr++) {
 
2632
            t1 = &(state->trans[transnr]);
 
2633
            /*
 
2634
             * Determinism checks in case of counted or all transitions
 
2635
             * will have to be handled separately
 
2636
             */
 
2637
            if (t1->atom == NULL) {
 
2638
                /* t1->nd = 1; */
 
2639
                continue;
 
2640
            }
 
2641
            if (t1->to == -1) /* eliminated */
 
2642
                continue;
 
2643
            for (i = 0;i < transnr;i++) {
 
2644
                t2 = &(state->trans[i]);
 
2645
                if (t2->to == -1) /* eliminated */
 
2646
                    continue;
 
2647
                if (t2->atom != NULL) {
 
2648
                    if (t1->to == t2->to) {
 
2649
                        if (xmlFAEqualAtoms(t1->atom, t2->atom))
 
2650
                            t2->to = -1; /* eliminated */
 
2651
                    }
 
2652
                }
 
2653
            }
 
2654
        }
 
2655
    }
 
2656
 
 
2657
    /*
 
2658
     * Check for all states that there aren't 2 transitions
 
2659
     * with the same atom and a different target.
 
2660
     */
 
2661
    for (statenr = 0;statenr < ctxt->nbStates;statenr++) {
 
2662
        state = ctxt->states[statenr];
 
2663
        if (state == NULL)
 
2664
            continue;
 
2665
        if (state->nbTrans < 2)
 
2666
            continue;
 
2667
        last = NULL;
 
2668
        for (transnr = 0;transnr < state->nbTrans;transnr++) {
 
2669
            t1 = &(state->trans[transnr]);
 
2670
            /*
 
2671
             * Determinism checks in case of counted or all transitions
 
2672
             * will have to be handled separately
 
2673
             */
 
2674
            if (t1->atom == NULL) {
 
2675
                continue;
 
2676
            }
 
2677
            if (t1->to == -1) /* eliminated */
 
2678
                continue;
 
2679
            for (i = 0;i < transnr;i++) {
 
2680
                t2 = &(state->trans[i]);
 
2681
                if (t2->to == -1) /* eliminated */
 
2682
                    continue;
 
2683
                if (t2->atom != NULL) {
 
2684
                    /* not determinist ! */
 
2685
                    if (xmlFACompareAtoms(t1->atom, t2->atom)) {
 
2686
                        ret = 0;
 
2687
                        /* mark the transitions as non-deterministic ones */
 
2688
                        t1->nd = 1;
 
2689
                        t2->nd = 1;
 
2690
                        last = t1;
 
2691
                    }
 
2692
                } else if (t1->to != -1) {
 
2693
                    /*
 
2694
                     * do the closure in case of remaining specific
 
2695
                     * epsilon transitions like choices or all
 
2696
                     */
 
2697
                    ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to],
 
2698
                                                   t2->to, t2->atom);
 
2699
                    /* don't shortcut the computation so all non deterministic
 
2700
                       transition get marked down
 
2701
                    if (ret == 0)
 
2702
                        return(0);
 
2703
                     */
 
2704
                    if (ret == 0) {
 
2705
                        t1->nd = 1;
 
2706
                        /* t2->nd = 1; */
 
2707
                        last = t1;
 
2708
                    }
 
2709
                }
 
2710
            }
 
2711
            /* don't shortcut the computation so all non deterministic
 
2712
               transition get marked down
 
2713
            if (ret == 0)
 
2714
                break; */
 
2715
        }
 
2716
 
 
2717
        /*
 
2718
         * mark specifically the last non-deterministic transition
 
2719
         * from a state since there is no need to set-up rollback
 
2720
         * from it
 
2721
         */
 
2722
        if (last != NULL) {
 
2723
            last->nd = 2;
 
2724
        }
 
2725
 
 
2726
        /* don't shortcut the computation so all non deterministic
 
2727
           transition get marked down
 
2728
        if (ret == 0)
 
2729
            break; */
 
2730
    }
 
2731
 
 
2732
    ctxt->determinist = ret;
 
2733
    return(ret);
 
2734
}
 
2735
 
 
2736
/************************************************************************
 
2737
 *                                                                      *
 
2738
 *      Routines to check input against transition atoms                *
 
2739
 *                                                                      *
 
2740
 ************************************************************************/
 
2741
 
 
2742
static int
 
2743
xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint, int neg,
 
2744
                          int start, int end, const xmlChar *blockName) {
 
2745
    int ret = 0;
 
2746
 
 
2747
    switch (type) {
 
2748
        case XML_REGEXP_STRING:
 
2749
        case XML_REGEXP_SUBREG:
 
2750
        case XML_REGEXP_RANGES:
 
2751
        case XML_REGEXP_EPSILON:
 
2752
            return(-1);
 
2753
        case XML_REGEXP_ANYCHAR:
 
2754
            ret = ((codepoint != '\n') && (codepoint != '\r'));
 
2755
            break;
 
2756
        case XML_REGEXP_CHARVAL:
 
2757
            ret = ((codepoint >= start) && (codepoint <= end));
 
2758
            break;
 
2759
        case XML_REGEXP_NOTSPACE:
 
2760
            neg = !neg;
 
2761
        case XML_REGEXP_ANYSPACE:
 
2762
            ret = ((codepoint == '\n') || (codepoint == '\r') ||
 
2763
                   (codepoint == '\t') || (codepoint == ' '));
 
2764
            break;
 
2765
        case XML_REGEXP_NOTINITNAME:
 
2766
            neg = !neg;
 
2767
        case XML_REGEXP_INITNAME:
 
2768
            ret = (IS_LETTER(codepoint) || 
 
2769
                   (codepoint == '_') || (codepoint == ':'));
 
2770
            break;
 
2771
        case XML_REGEXP_NOTNAMECHAR:
 
2772
            neg = !neg;
 
2773
        case XML_REGEXP_NAMECHAR:
 
2774
            ret = (IS_LETTER(codepoint) || IS_DIGIT(codepoint) ||
 
2775
                   (codepoint == '.') || (codepoint == '-') ||
 
2776
                   (codepoint == '_') || (codepoint == ':') ||
 
2777
                   IS_COMBINING(codepoint) || IS_EXTENDER(codepoint));
 
2778
            break;
 
2779
        case XML_REGEXP_NOTDECIMAL:
 
2780
            neg = !neg;
 
2781
        case XML_REGEXP_DECIMAL:
 
2782
            ret = xmlUCSIsCatNd(codepoint);
 
2783
            break;
 
2784
        case XML_REGEXP_REALCHAR:
 
2785
            neg = !neg;
 
2786
        case XML_REGEXP_NOTREALCHAR:
 
2787
            ret = xmlUCSIsCatP(codepoint);
 
2788
            if (ret == 0)
 
2789
                ret = xmlUCSIsCatZ(codepoint);
 
2790
            if (ret == 0)
 
2791
                ret = xmlUCSIsCatC(codepoint);
 
2792
            break;
 
2793
        case XML_REGEXP_LETTER:
 
2794
            ret = xmlUCSIsCatL(codepoint);
 
2795
            break;
 
2796
        case XML_REGEXP_LETTER_UPPERCASE:
 
2797
            ret = xmlUCSIsCatLu(codepoint);
 
2798
            break;
 
2799
        case XML_REGEXP_LETTER_LOWERCASE:
 
2800
            ret = xmlUCSIsCatLl(codepoint);
 
2801
            break;
 
2802
        case XML_REGEXP_LETTER_TITLECASE:
 
2803
            ret = xmlUCSIsCatLt(codepoint);
 
2804
            break;
 
2805
        case XML_REGEXP_LETTER_MODIFIER:
 
2806
            ret = xmlUCSIsCatLm(codepoint);
 
2807
            break;
 
2808
        case XML_REGEXP_LETTER_OTHERS:
 
2809
            ret = xmlUCSIsCatLo(codepoint);
 
2810
            break;
 
2811
        case XML_REGEXP_MARK:
 
2812
            ret = xmlUCSIsCatM(codepoint);
 
2813
            break;
 
2814
        case XML_REGEXP_MARK_NONSPACING:
 
2815
            ret = xmlUCSIsCatMn(codepoint);
 
2816
            break;
 
2817
        case XML_REGEXP_MARK_SPACECOMBINING:
 
2818
            ret = xmlUCSIsCatMc(codepoint);
 
2819
            break;
 
2820
        case XML_REGEXP_MARK_ENCLOSING:
 
2821
            ret = xmlUCSIsCatMe(codepoint);
 
2822
            break;
 
2823
        case XML_REGEXP_NUMBER:
 
2824
            ret = xmlUCSIsCatN(codepoint);
 
2825
            break;
 
2826
        case XML_REGEXP_NUMBER_DECIMAL:
 
2827
            ret = xmlUCSIsCatNd(codepoint);
 
2828
            break;
 
2829
        case XML_REGEXP_NUMBER_LETTER:
 
2830
            ret = xmlUCSIsCatNl(codepoint);
 
2831
            break;
 
2832
        case XML_REGEXP_NUMBER_OTHERS:
 
2833
            ret = xmlUCSIsCatNo(codepoint);
 
2834
            break;
 
2835
        case XML_REGEXP_PUNCT:
 
2836
            ret = xmlUCSIsCatP(codepoint);
 
2837
            break;
 
2838
        case XML_REGEXP_PUNCT_CONNECTOR:
 
2839
            ret = xmlUCSIsCatPc(codepoint);
 
2840
            break;
 
2841
        case XML_REGEXP_PUNCT_DASH:
 
2842
            ret = xmlUCSIsCatPd(codepoint);
 
2843
            break;
 
2844
        case XML_REGEXP_PUNCT_OPEN:
 
2845
            ret = xmlUCSIsCatPs(codepoint);
 
2846
            break;
 
2847
        case XML_REGEXP_PUNCT_CLOSE:
 
2848
            ret = xmlUCSIsCatPe(codepoint);
 
2849
            break;
 
2850
        case XML_REGEXP_PUNCT_INITQUOTE:
 
2851
            ret = xmlUCSIsCatPi(codepoint);
 
2852
            break;
 
2853
        case XML_REGEXP_PUNCT_FINQUOTE:
 
2854
            ret = xmlUCSIsCatPf(codepoint);
 
2855
            break;
 
2856
        case XML_REGEXP_PUNCT_OTHERS:
 
2857
            ret = xmlUCSIsCatPo(codepoint);
 
2858
            break;
 
2859
        case XML_REGEXP_SEPAR:
 
2860
            ret = xmlUCSIsCatZ(codepoint);
 
2861
            break;
 
2862
        case XML_REGEXP_SEPAR_SPACE:
 
2863
            ret = xmlUCSIsCatZs(codepoint);
 
2864
            break;
 
2865
        case XML_REGEXP_SEPAR_LINE:
 
2866
            ret = xmlUCSIsCatZl(codepoint);
 
2867
            break;
 
2868
        case XML_REGEXP_SEPAR_PARA:
 
2869
            ret = xmlUCSIsCatZp(codepoint);
 
2870
            break;
 
2871
        case XML_REGEXP_SYMBOL:
 
2872
            ret = xmlUCSIsCatS(codepoint);
 
2873
            break;
 
2874
        case XML_REGEXP_SYMBOL_MATH:
 
2875
            ret = xmlUCSIsCatSm(codepoint);
 
2876
            break;
 
2877
        case XML_REGEXP_SYMBOL_CURRENCY:
 
2878
            ret = xmlUCSIsCatSc(codepoint);
 
2879
            break;
 
2880
        case XML_REGEXP_SYMBOL_MODIFIER:
 
2881
            ret = xmlUCSIsCatSk(codepoint);
 
2882
            break;
 
2883
        case XML_REGEXP_SYMBOL_OTHERS:
 
2884
            ret = xmlUCSIsCatSo(codepoint);
 
2885
            break;
 
2886
        case XML_REGEXP_OTHER:
 
2887
            ret = xmlUCSIsCatC(codepoint);
 
2888
            break;
 
2889
        case XML_REGEXP_OTHER_CONTROL:
 
2890
            ret = xmlUCSIsCatCc(codepoint);
 
2891
            break;
 
2892
        case XML_REGEXP_OTHER_FORMAT:
 
2893
            ret = xmlUCSIsCatCf(codepoint);
 
2894
            break;
 
2895
        case XML_REGEXP_OTHER_PRIVATE:
 
2896
            ret = xmlUCSIsCatCo(codepoint);
 
2897
            break;
 
2898
        case XML_REGEXP_OTHER_NA:
 
2899
            /* ret = xmlUCSIsCatCn(codepoint); */
 
2900
            /* Seems it doesn't exist anymore in recent Unicode releases */
 
2901
            ret = 0;
 
2902
            break;
 
2903
        case XML_REGEXP_BLOCK_NAME:
 
2904
            ret = xmlUCSIsBlock(codepoint, (const char *) blockName);
 
2905
            break;
 
2906
    }
 
2907
    if (neg)
 
2908
        return(!ret);
 
2909
    return(ret);
 
2910
}
 
2911
 
 
2912
static int
 
2913
xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint) {
 
2914
    int i, ret = 0;
 
2915
    xmlRegRangePtr range;
 
2916
 
 
2917
    if ((atom == NULL) || (!IS_CHAR(codepoint)))
 
2918
        return(-1);
 
2919
 
 
2920
    switch (atom->type) {
 
2921
        case XML_REGEXP_SUBREG:
 
2922
        case XML_REGEXP_EPSILON:
 
2923
            return(-1);
 
2924
        case XML_REGEXP_CHARVAL:
 
2925
            return(codepoint == atom->codepoint);
 
2926
        case XML_REGEXP_RANGES: {
 
2927
            int accept = 0;
 
2928
 
 
2929
            for (i = 0;i < atom->nbRanges;i++) {
 
2930
                range = atom->ranges[i];
 
2931
                if (range->neg == 2) {
 
2932
                    ret = xmlRegCheckCharacterRange(range->type, codepoint,
 
2933
                                                0, range->start, range->end,
 
2934
                                                range->blockName);
 
2935
                    if (ret != 0)
 
2936
                        return(0); /* excluded char */
 
2937
                } else if (range->neg) {
 
2938
                    ret = xmlRegCheckCharacterRange(range->type, codepoint,
 
2939
                                                0, range->start, range->end,
 
2940
                                                range->blockName);
 
2941
                    if (ret == 0)
 
2942
                        accept = 1;
 
2943
                    else
 
2944
                        return(0);
 
2945
                } else {
 
2946
                    ret = xmlRegCheckCharacterRange(range->type, codepoint,
 
2947
                                                0, range->start, range->end,
 
2948
                                                range->blockName);
 
2949
                    if (ret != 0)
 
2950
                        accept = 1; /* might still be excluded */
 
2951
                }
 
2952
            }
 
2953
            return(accept);
 
2954
        }
 
2955
        case XML_REGEXP_STRING:
 
2956
            printf("TODO: XML_REGEXP_STRING\n");
 
2957
            return(-1);
 
2958
        case XML_REGEXP_ANYCHAR:
 
2959
        case XML_REGEXP_ANYSPACE:
 
2960
        case XML_REGEXP_NOTSPACE:
 
2961
        case XML_REGEXP_INITNAME:
 
2962
        case XML_REGEXP_NOTINITNAME:
 
2963
        case XML_REGEXP_NAMECHAR:
 
2964
        case XML_REGEXP_NOTNAMECHAR:
 
2965
        case XML_REGEXP_DECIMAL:
 
2966
        case XML_REGEXP_NOTDECIMAL:
 
2967
        case XML_REGEXP_REALCHAR:
 
2968
        case XML_REGEXP_NOTREALCHAR:
 
2969
        case XML_REGEXP_LETTER:
 
2970
        case XML_REGEXP_LETTER_UPPERCASE:
 
2971
        case XML_REGEXP_LETTER_LOWERCASE:
 
2972
        case XML_REGEXP_LETTER_TITLECASE:
 
2973
        case XML_REGEXP_LETTER_MODIFIER:
 
2974
        case XML_REGEXP_LETTER_OTHERS:
 
2975
        case XML_REGEXP_MARK:
 
2976
        case XML_REGEXP_MARK_NONSPACING:
 
2977
        case XML_REGEXP_MARK_SPACECOMBINING:
 
2978
        case XML_REGEXP_MARK_ENCLOSING:
 
2979
        case XML_REGEXP_NUMBER:
 
2980
        case XML_REGEXP_NUMBER_DECIMAL:
 
2981
        case XML_REGEXP_NUMBER_LETTER:
 
2982
        case XML_REGEXP_NUMBER_OTHERS:
 
2983
        case XML_REGEXP_PUNCT:
 
2984
        case XML_REGEXP_PUNCT_CONNECTOR:
 
2985
        case XML_REGEXP_PUNCT_DASH:
 
2986
        case XML_REGEXP_PUNCT_OPEN:
 
2987
        case XML_REGEXP_PUNCT_CLOSE:
 
2988
        case XML_REGEXP_PUNCT_INITQUOTE:
 
2989
        case XML_REGEXP_PUNCT_FINQUOTE:
 
2990
        case XML_REGEXP_PUNCT_OTHERS:
 
2991
        case XML_REGEXP_SEPAR:
 
2992
        case XML_REGEXP_SEPAR_SPACE:
 
2993
        case XML_REGEXP_SEPAR_LINE:
 
2994
        case XML_REGEXP_SEPAR_PARA:
 
2995
        case XML_REGEXP_SYMBOL:
 
2996
        case XML_REGEXP_SYMBOL_MATH:
 
2997
        case XML_REGEXP_SYMBOL_CURRENCY:
 
2998
        case XML_REGEXP_SYMBOL_MODIFIER:
 
2999
        case XML_REGEXP_SYMBOL_OTHERS:
 
3000
        case XML_REGEXP_OTHER:
 
3001
        case XML_REGEXP_OTHER_CONTROL:
 
3002
        case XML_REGEXP_OTHER_FORMAT:
 
3003
        case XML_REGEXP_OTHER_PRIVATE:
 
3004
        case XML_REGEXP_OTHER_NA:
 
3005
        case XML_REGEXP_BLOCK_NAME:
 
3006
            ret = xmlRegCheckCharacterRange(atom->type, codepoint, 0, 0, 0,
 
3007
                                            (const xmlChar *)atom->valuep);
 
3008
            if (atom->neg)
 
3009
                ret = !ret;
 
3010
            break;
 
3011
    }
 
3012
    return(ret);
 
3013
}
 
3014
 
 
3015
/************************************************************************
 
3016
 *                                                                      *
 
3017
 *      Saving and restoring state of an execution context              *
 
3018
 *                                                                      *
 
3019
 ************************************************************************/
 
3020
 
 
3021
#ifdef DEBUG_REGEXP_EXEC
 
3022
static void
 
3023
xmlFARegDebugExec(xmlRegExecCtxtPtr exec) {
 
3024
    printf("state: %d:%d:idx %d", exec->state->no, exec->transno, exec->index);
 
3025
    if (exec->inputStack != NULL) {
 
3026
        int i;
 
3027
        printf(": ");
 
3028
        for (i = 0;(i < 3) && (i < exec->inputStackNr);i++)
 
3029
            printf("%s ", (const char *)
 
3030
                   exec->inputStack[exec->inputStackNr - (i + 1)].value);
 
3031
    } else {
 
3032
        printf(": %s", &(exec->inputString[exec->index]));
 
3033
    }
 
3034
    printf("\n");
 
3035
}
 
3036
#endif
 
3037
 
 
3038
static void
 
3039
xmlFARegExecSave(xmlRegExecCtxtPtr exec) {
 
3040
#ifdef DEBUG_REGEXP_EXEC
 
3041
    printf("saving ");
 
3042
    exec->transno++;
 
3043
    xmlFARegDebugExec(exec);
 
3044
    exec->transno--;
 
3045
#endif
 
3046
#ifdef MAX_PUSH
 
3047
    if (exec->nbPush > MAX_PUSH) {
 
3048
        return;
 
3049
    }
 
3050
    exec->nbPush++;
 
3051
#endif
 
3052
 
 
3053
    if (exec->maxRollbacks == 0) {
 
3054
        exec->maxRollbacks = 4;
 
3055
        exec->rollbacks = (xmlRegExecRollback *) xmlMalloc(exec->maxRollbacks *
 
3056
                                             sizeof(xmlRegExecRollback));
 
3057
        if (exec->rollbacks == NULL) {
 
3058
            xmlRegexpErrMemory(NULL, "saving regexp");
 
3059
            exec->maxRollbacks = 0;
 
3060
            return;
 
3061
        }
 
3062
        memset(exec->rollbacks, 0,
 
3063
               exec->maxRollbacks * sizeof(xmlRegExecRollback));
 
3064
    } else if (exec->nbRollbacks >= exec->maxRollbacks) {
 
3065
        xmlRegExecRollback *tmp;
 
3066
        int len = exec->maxRollbacks;
 
3067
 
 
3068
        exec->maxRollbacks *= 2;
 
3069
        tmp = (xmlRegExecRollback *) xmlRealloc(exec->rollbacks,
 
3070
                        exec->maxRollbacks * sizeof(xmlRegExecRollback));
 
3071
        if (tmp == NULL) {
 
3072
            xmlRegexpErrMemory(NULL, "saving regexp");
 
3073
            exec->maxRollbacks /= 2;
 
3074
            return;
 
3075
        }
 
3076
        exec->rollbacks = tmp;
 
3077
        tmp = &exec->rollbacks[len];
 
3078
        memset(tmp, 0, (exec->maxRollbacks - len) * sizeof(xmlRegExecRollback));
 
3079
    }
 
3080
    exec->rollbacks[exec->nbRollbacks].state = exec->state;
 
3081
    exec->rollbacks[exec->nbRollbacks].index = exec->index;
 
3082
    exec->rollbacks[exec->nbRollbacks].nextbranch = exec->transno + 1;
 
3083
    if (exec->comp->nbCounters > 0) {
 
3084
        if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
 
3085
            exec->rollbacks[exec->nbRollbacks].counts = (int *)
 
3086
                xmlMalloc(exec->comp->nbCounters * sizeof(int));
 
3087
            if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
 
3088
                xmlRegexpErrMemory(NULL, "saving regexp");
 
3089
                exec->status = -5;
 
3090
                return;
 
3091
            }
 
3092
        }
 
3093
        memcpy(exec->rollbacks[exec->nbRollbacks].counts, exec->counts,
 
3094
               exec->comp->nbCounters * sizeof(int));
 
3095
    }
 
3096
    exec->nbRollbacks++;
 
3097
}
 
3098
 
 
3099
static void
 
3100
xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) {
 
3101
    if (exec->nbRollbacks <= 0) {
 
3102
        exec->status = -1;
 
3103
#ifdef DEBUG_REGEXP_EXEC
 
3104
        printf("rollback failed on empty stack\n");
 
3105
#endif
 
3106
        return;
 
3107
    }
 
3108
    exec->nbRollbacks--;
 
3109
    exec->state = exec->rollbacks[exec->nbRollbacks].state;
 
3110
    exec->index = exec->rollbacks[exec->nbRollbacks].index;
 
3111
    exec->transno = exec->rollbacks[exec->nbRollbacks].nextbranch;
 
3112
    if (exec->comp->nbCounters > 0) {
 
3113
        if (exec->rollbacks[exec->nbRollbacks].counts == NULL) {
 
3114
            fprintf(stderr, "exec save: allocation failed");
 
3115
            exec->status = -6;
 
3116
            return;
 
3117
        }
 
3118
        memcpy(exec->counts, exec->rollbacks[exec->nbRollbacks].counts,
 
3119
               exec->comp->nbCounters * sizeof(int));
 
3120
    }
 
3121
 
 
3122
#ifdef DEBUG_REGEXP_EXEC
 
3123
    printf("restored ");
 
3124
    xmlFARegDebugExec(exec);
 
3125
#endif
 
3126
}
 
3127
 
 
3128
/************************************************************************
 
3129
 *                                                                      *
 
3130
 *      Verifier, running an input against a compiled regexp            *
 
3131
 *                                                                      *
 
3132
 ************************************************************************/
 
3133
 
 
3134
static int
 
3135
xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) {
 
3136
    xmlRegExecCtxt execval;
 
3137
    xmlRegExecCtxtPtr exec = &execval;
 
3138
    int ret, codepoint = 0, len, deter;
 
3139
 
 
3140
    exec->inputString = content;
 
3141
    exec->index = 0;
 
3142
    exec->nbPush = 0;
 
3143
    exec->determinist = 1;
 
3144
    exec->maxRollbacks = 0;
 
3145
    exec->nbRollbacks = 0;
 
3146
    exec->rollbacks = NULL;
 
3147
    exec->status = 0;
 
3148
    exec->comp = comp;
 
3149
    exec->state = comp->states[0];
 
3150
    exec->transno = 0;
 
3151
    exec->transcount = 0;
 
3152
    exec->inputStack = NULL;
 
3153
    exec->inputStackMax = 0;
 
3154
    if (comp->nbCounters > 0) {
 
3155
        exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int));
 
3156
        if (exec->counts == NULL) {
 
3157
            xmlRegexpErrMemory(NULL, "running regexp");
 
3158
            return(-1);
 
3159
        }
 
3160
        memset(exec->counts, 0, comp->nbCounters * sizeof(int));
 
3161
    } else
 
3162
        exec->counts = NULL;
 
3163
    while ((exec->status == 0) &&
 
3164
           ((exec->inputString[exec->index] != 0) ||
 
3165
            (exec->state->type != XML_REGEXP_FINAL_STATE))) {
 
3166
        xmlRegTransPtr trans;
 
3167
        xmlRegAtomPtr atom;
 
3168
 
 
3169
        /*
 
3170
         * If end of input on non-terminal state, rollback, however we may
 
3171
         * still have epsilon like transition for counted transitions
 
3172
         * on counters, in that case don't break too early.  Additionally,
 
3173
         * if we are working on a range like "AB{0,2}", where B is not present,
 
3174
         * we don't want to break.
 
3175
         */
 
3176
        len = 1;
 
3177
        if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL)) {
 
3178
            /*
 
3179
             * if there is a transition, we must check if
 
3180
             *  atom allows minOccurs of 0
 
3181
             */
 
3182
            if (exec->transno < exec->state->nbTrans) {
 
3183
                trans = &exec->state->trans[exec->transno];
 
3184
                if (trans->to >=0) {
 
3185
                    atom = trans->atom;
 
3186
                    if (!((atom->min == 0) && (atom->max > 0)))
 
3187
                        goto rollback;
 
3188
                }
 
3189
            } else
 
3190
                goto rollback;
 
3191
        }
 
3192
 
 
3193
        exec->transcount = 0;
 
3194
        for (;exec->transno < exec->state->nbTrans;exec->transno++) {
 
3195
            trans = &exec->state->trans[exec->transno];
 
3196
            if (trans->to < 0)
 
3197
                continue;
 
3198
            atom = trans->atom;
 
3199
            ret = 0;
 
3200
            deter = 1;
 
3201
            if (trans->count >= 0) {
 
3202
                int count;
 
3203
                xmlRegCounterPtr counter;
 
3204
 
 
3205
                if (exec->counts == NULL) {
 
3206
                    exec->status = -1;
 
3207
                    goto error;
 
3208
                }
 
3209
                /*
 
3210
                 * A counted transition.
 
3211
                 */
 
3212
 
 
3213
                count = exec->counts[trans->count];
 
3214
                counter = &exec->comp->counters[trans->count];
 
3215
#ifdef DEBUG_REGEXP_EXEC
 
3216
                printf("testing count %d: val %d, min %d, max %d\n",
 
3217
                       trans->count, count, counter->min,  counter->max);
 
3218
#endif
 
3219
                ret = ((count >= counter->min) && (count <= counter->max));
 
3220
                if ((ret) && (counter->min != counter->max))
 
3221
                    deter = 0;
 
3222
            } else if (atom == NULL) {
 
3223
                fprintf(stderr, "epsilon transition left at runtime\n");
 
3224
                exec->status = -2;
 
3225
                break;
 
3226
            } else if (exec->inputString[exec->index] != 0) {
 
3227
                codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
 
3228
                ret = xmlRegCheckCharacter(atom, codepoint);
 
3229
                if ((ret == 1) && (atom->min >= 0) && (atom->max > 0)) {
 
3230
                    xmlRegStatePtr to = comp->states[trans->to];
 
3231
 
 
3232
                    /*
 
3233
                     * this is a multiple input sequence
 
3234
                     * If there is a counter associated increment it now.
 
3235
                     * before potentially saving and rollback
 
3236
                     * do not increment if the counter is already over the
 
3237
                     * maximum limit in which case get to next transition
 
3238
                     */
 
3239
                    if (trans->counter >= 0) {
 
3240
                        xmlRegCounterPtr counter;
 
3241
 
 
3242
                        if ((exec->counts == NULL) ||
 
3243
                            (exec->comp == NULL) ||
 
3244
                            (exec->comp->counters == NULL)) {
 
3245
                            exec->status = -1;
 
3246
                            goto error;
 
3247
                        }
 
3248
                        counter = &exec->comp->counters[trans->counter];
 
3249
                        if (exec->counts[trans->counter] >= counter->max)
 
3250
                            continue; /* for loop on transitions */
 
3251
 
 
3252
#ifdef DEBUG_REGEXP_EXEC
 
3253
                        printf("Increasing count %d\n", trans->counter);
 
3254
#endif
 
3255
                        exec->counts[trans->counter]++;
 
3256
                    }
 
3257
                    if (exec->state->nbTrans > exec->transno + 1) {
 
3258
                        xmlFARegExecSave(exec);
 
3259
                    }
 
3260
                    exec->transcount = 1;
 
3261
                    do {
 
3262
                        /*
 
3263
                         * Try to progress as much as possible on the input
 
3264
                         */
 
3265
                        if (exec->transcount == atom->max) {
 
3266
                            break;
 
3267
                        }
 
3268
                        exec->index += len;
 
3269
                        /*
 
3270
                         * End of input: stop here
 
3271
                         */
 
3272
                        if (exec->inputString[exec->index] == 0) {
 
3273
                            exec->index -= len;
 
3274
                            break;
 
3275
                        }
 
3276
                        if (exec->transcount >= atom->min) {
 
3277
                            int transno = exec->transno;
 
3278
                            xmlRegStatePtr state = exec->state;
 
3279
 
 
3280
                            /*
 
3281
                             * The transition is acceptable save it
 
3282
                             */
 
3283
                            exec->transno = -1; /* trick */
 
3284
                            exec->state = to;
 
3285
                            xmlFARegExecSave(exec);
 
3286
                            exec->transno = transno;
 
3287
                            exec->state = state;
 
3288
                        }
 
3289
                        codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
 
3290
                                              len);
 
3291
                        ret = xmlRegCheckCharacter(atom, codepoint);
 
3292
                        exec->transcount++;
 
3293
                    } while (ret == 1);
 
3294
                    if (exec->transcount < atom->min)
 
3295
                        ret = 0;
 
3296
 
 
3297
                    /*
 
3298
                     * If the last check failed but one transition was found
 
3299
                     * possible, rollback
 
3300
                     */
 
3301
                    if (ret < 0)
 
3302
                        ret = 0;
 
3303
                    if (ret == 0) {
 
3304
                        goto rollback;
 
3305
                    }
 
3306
                    if (trans->counter >= 0) {
 
3307
                        if (exec->counts == NULL) {
 
3308
                            exec->status = -1;
 
3309
                            goto error;
 
3310
                        }
 
3311
#ifdef DEBUG_REGEXP_EXEC
 
3312
                        printf("Decreasing count %d\n", trans->counter);
 
3313
#endif
 
3314
                        exec->counts[trans->counter]--;
 
3315
                    }
 
3316
                } else if ((ret == 0) && (atom->min == 0) && (atom->max > 0)) {
 
3317
                    /*
 
3318
                     * we don't match on the codepoint, but minOccurs of 0
 
3319
                     * says that's ok.  Setting len to 0 inhibits stepping
 
3320
                     * over the codepoint.
 
3321
                     */
 
3322
                    exec->transcount = 1;
 
3323
                    len = 0;
 
3324
                    ret = 1;
 
3325
                }
 
3326
            } else if ((atom->min == 0) && (atom->max > 0)) {
 
3327
                /* another spot to match when minOccurs is 0 */
 
3328
                exec->transcount = 1;
 
3329
                len = 0;
 
3330
                ret = 1;
 
3331
            }
 
3332
            if (ret == 1) {
 
3333
                if ((trans->nd == 1) ||
 
3334
                    ((trans->count >= 0) && (deter == 0) &&
 
3335
                     (exec->state->nbTrans > exec->transno + 1))) {
 
3336
#ifdef DEBUG_REGEXP_EXEC
 
3337
                    if (trans->nd == 1)
 
3338
                        printf("Saving on nd transition atom %d for %c at %d\n",
 
3339
                               trans->atom->no, codepoint, exec->index);
 
3340
                    else
 
3341
                        printf("Saving on counted transition count %d for %c at %d\n",
 
3342
                               trans->count, codepoint, exec->index);
 
3343
#endif
 
3344
                    xmlFARegExecSave(exec);
 
3345
                }
 
3346
                if (trans->counter >= 0) {
 
3347
                    xmlRegCounterPtr counter;
 
3348
 
 
3349
                    /* make sure we don't go over the counter maximum value */
 
3350
                    if ((exec->counts == NULL) ||
 
3351
                        (exec->comp == NULL) ||
 
3352
                        (exec->comp->counters == NULL)) {
 
3353
                        exec->status = -1;
 
3354
                        goto error;
 
3355
                    }
 
3356
                    counter = &exec->comp->counters[trans->counter];
 
3357
                    if (exec->counts[trans->counter] >= counter->max)
 
3358
                        continue; /* for loop on transitions */
 
3359
#ifdef DEBUG_REGEXP_EXEC
 
3360
                    printf("Increasing count %d\n", trans->counter);
 
3361
#endif
 
3362
                    exec->counts[trans->counter]++;
 
3363
                }
 
3364
                if ((trans->count >= 0) &&
 
3365
                    (trans->count < REGEXP_ALL_COUNTER)) {
 
3366
                    if (exec->counts == NULL) {
 
3367
                        exec->status = -1;
 
3368
                        goto error;
 
3369
                    }
 
3370
#ifdef DEBUG_REGEXP_EXEC
 
3371
                    printf("resetting count %d on transition\n",
 
3372
                           trans->count);
 
3373
#endif
 
3374
                    exec->counts[trans->count] = 0;
 
3375
                }
 
3376
#ifdef DEBUG_REGEXP_EXEC
 
3377
                printf("entering state %d\n", trans->to);
 
3378
#endif
 
3379
                exec->state = comp->states[trans->to];
 
3380
                exec->transno = 0;
 
3381
                if (trans->atom != NULL) {
 
3382
                    exec->index += len;
 
3383
                }
 
3384
                goto progress;
 
3385
            } else if (ret < 0) {
 
3386
                exec->status = -4;
 
3387
                break;
 
3388
            }
 
3389
        }
 
3390
        if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
 
3391
rollback:
 
3392
            /*
 
3393
             * Failed to find a way out
 
3394
             */
 
3395
            exec->determinist = 0;
 
3396
#ifdef DEBUG_REGEXP_EXEC
 
3397
            printf("rollback from state %d on %d:%c\n", exec->state->no,
 
3398
                   codepoint,codepoint);
 
3399
#endif
 
3400
            xmlFARegExecRollBack(exec);
 
3401
        }
 
3402
progress:
 
3403
        continue;
 
3404
    }
 
3405
error:
 
3406
    if (exec->rollbacks != NULL) {
 
3407
        if (exec->counts != NULL) {
 
3408
            int i;
 
3409
 
 
3410
            for (i = 0;i < exec->maxRollbacks;i++)
 
3411
                if (exec->rollbacks[i].counts != NULL)
 
3412
                    xmlFree(exec->rollbacks[i].counts);
 
3413
        }
 
3414
        xmlFree(exec->rollbacks);
 
3415
    }
 
3416
    if (exec->counts != NULL)
 
3417
        xmlFree(exec->counts);
 
3418
    if (exec->status == 0)
 
3419
        return(1);
 
3420
    if (exec->status == -1) {
 
3421
        if (exec->nbPush > MAX_PUSH)
 
3422
            return(-1);
 
3423
        return(0);
 
3424
    }
 
3425
    return(exec->status);
 
3426
}
 
3427
 
 
3428
/************************************************************************
 
3429
 *                                                                      *
 
3430
 *      Progressive interface to the verifier one atom at a time        *
 
3431
 *                                                                      *
 
3432
 ************************************************************************/
 
3433
#ifdef DEBUG_ERR
 
3434
static void testerr(xmlRegExecCtxtPtr exec);
 
3435
#endif
 
3436
 
 
3437
/**
 
3438
 * xmlRegNewExecCtxt:
 
3439
 * @comp: a precompiled regular expression
 
3440
 * @callback: a callback function used for handling progresses in the
 
3441
 *            automata matching phase
 
3442
 * @data: the context data associated to the callback in this context
 
3443
 *
 
3444
 * Build a context used for progressive evaluation of a regexp.
 
3445
 *
 
3446
 * Returns the new context
 
3447
 */
 
3448
xmlRegExecCtxtPtr
 
3449
xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) {
 
3450
    xmlRegExecCtxtPtr exec;
 
3451
 
 
3452
    if (comp == NULL)
 
3453
        return(NULL);
 
3454
    if ((comp->compact == NULL) && (comp->states == NULL))
 
3455
        return(NULL);
 
3456
    exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt));
 
3457
    if (exec == NULL) {
 
3458
        xmlRegexpErrMemory(NULL, "creating execution context");
 
3459
        return(NULL);
 
3460
    }
 
3461
    memset(exec, 0, sizeof(xmlRegExecCtxt));
 
3462
    exec->inputString = NULL;
 
3463
    exec->index = 0;
 
3464
    exec->determinist = 1;
 
3465
    exec->maxRollbacks = 0;
 
3466
    exec->nbRollbacks = 0;
 
3467
    exec->rollbacks = NULL;
 
3468
    exec->status = 0;
 
3469
    exec->comp = comp;
 
3470
    if (comp->compact == NULL)
 
3471
        exec->state = comp->states[0];
 
3472
    exec->transno = 0;
 
3473
    exec->transcount = 0;
 
3474
    exec->callback = callback;
 
3475
    exec->data = data;
 
3476
    if (comp->nbCounters > 0) {
 
3477
        /*
 
3478
         * For error handling, exec->counts is allocated twice the size
 
3479
         * the second half is used to store the data in case of rollback
 
3480
         */
 
3481
        exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int)
 
3482
                                         * 2);
 
3483
        if (exec->counts == NULL) {
 
3484
            xmlRegexpErrMemory(NULL, "creating execution context");
 
3485
            xmlFree(exec);
 
3486
            return(NULL);
 
3487
        }
 
3488
        memset(exec->counts, 0, comp->nbCounters * sizeof(int) * 2);
 
3489
        exec->errCounts = &exec->counts[comp->nbCounters];
 
3490
    } else {
 
3491
        exec->counts = NULL;
 
3492
        exec->errCounts = NULL;
 
3493
    }
 
3494
    exec->inputStackMax = 0;
 
3495
    exec->inputStackNr = 0;
 
3496
    exec->inputStack = NULL;
 
3497
    exec->errStateNo = -1;
 
3498
    exec->errString = NULL;
 
3499
    exec->nbPush = 0;
 
3500
    return(exec);
 
3501
}
 
3502
 
 
3503
/**
 
3504
 * xmlRegFreeExecCtxt:
 
3505
 * @exec: a regular expression evaulation context
 
3506
 *
 
3507
 * Free the structures associated to a regular expression evaulation context.
 
3508
 */
 
3509
void
 
3510
xmlRegFreeExecCtxt(xmlRegExecCtxtPtr exec) {
 
3511
    if (exec == NULL)
 
3512
        return;
 
3513
 
 
3514
    if (exec->rollbacks != NULL) {
 
3515
        if (exec->counts != NULL) {
 
3516
            int i;
 
3517
 
 
3518
            for (i = 0;i < exec->maxRollbacks;i++)
 
3519
                if (exec->rollbacks[i].counts != NULL)
 
3520
                    xmlFree(exec->rollbacks[i].counts);
 
3521
        }
 
3522
        xmlFree(exec->rollbacks);
 
3523
    }
 
3524
    if (exec->counts != NULL)
 
3525
        xmlFree(exec->counts);
 
3526
    if (exec->inputStack != NULL) {
 
3527
        int i;
 
3528
 
 
3529
        for (i = 0;i < exec->inputStackNr;i++) {
 
3530
            if (exec->inputStack[i].value != NULL)
 
3531
                xmlFree(exec->inputStack[i].value);
 
3532
        }
 
3533
        xmlFree(exec->inputStack);
 
3534
    }
 
3535
    if (exec->errString != NULL)
 
3536
        xmlFree(exec->errString);
 
3537
    xmlFree(exec);
 
3538
}
 
3539
 
 
3540
static void
 
3541
xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value,
 
3542
                            void *data) {
 
3543
#ifdef DEBUG_PUSH
 
3544
    printf("saving value: %d:%s\n", exec->inputStackNr, value);
 
3545
#endif
 
3546
    if (exec->inputStackMax == 0) {
 
3547
        exec->inputStackMax = 4;
 
3548
        exec->inputStack = (xmlRegInputTokenPtr) 
 
3549
            xmlMalloc(exec->inputStackMax * sizeof(xmlRegInputToken));
 
3550
        if (exec->inputStack == NULL) {
 
3551
            xmlRegexpErrMemory(NULL, "pushing input string");
 
3552
            exec->inputStackMax = 0;
 
3553
            return;
 
3554
        }
 
3555
    } else if (exec->inputStackNr + 1 >= exec->inputStackMax) {
 
3556
        xmlRegInputTokenPtr tmp;
 
3557
 
 
3558
        exec->inputStackMax *= 2;
 
3559
        tmp = (xmlRegInputTokenPtr) xmlRealloc(exec->inputStack,
 
3560
                        exec->inputStackMax * sizeof(xmlRegInputToken));
 
3561
        if (tmp == NULL) {
 
3562
            xmlRegexpErrMemory(NULL, "pushing input string");
 
3563
            exec->inputStackMax /= 2;
 
3564
            return;
 
3565
        }
 
3566
        exec->inputStack = tmp;
 
3567
    }
 
3568
    exec->inputStack[exec->inputStackNr].value = xmlStrdup(value);
 
3569
    exec->inputStack[exec->inputStackNr].data = data;
 
3570
    exec->inputStackNr++;
 
3571
    exec->inputStack[exec->inputStackNr].value = NULL;
 
3572
    exec->inputStack[exec->inputStackNr].data = NULL;
 
3573
}
 
3574
 
 
3575
/**
 
3576
 * xmlRegStrEqualWildcard:
 
3577
 * @expStr:  the string to be evaluated 
 
3578
 * @valStr:  the validation string
 
3579
 *
 
3580
 * Checks if both strings are equal or have the same content. "*"
 
3581
 * can be used as a wildcard in @valStr; "|" is used as a seperator of 
 
3582
 * substrings in both @expStr and @valStr.
 
3583
 *
 
3584
 * Returns 1 if the comparison is satisfied and the number of substrings
 
3585
 * is equal, 0 otherwise.
 
3586
 */
 
3587
 
 
3588
static int
 
3589
xmlRegStrEqualWildcard(const xmlChar *expStr, const xmlChar *valStr) {
 
3590
    if (expStr == valStr) return(1);
 
3591
    if (expStr == NULL) return(0);
 
3592
    if (valStr == NULL) return(0);
 
3593
    do {
 
3594
        /*
 
3595
        * Eval if we have a wildcard for the current item.
 
3596
        */
 
3597
        if (*expStr != *valStr) {
 
3598
            /* if one of them starts with a wildcard make valStr be it */
 
3599
            if (*valStr == '*') {
 
3600
                const xmlChar *tmp;
 
3601
 
 
3602
                tmp = valStr;
 
3603
                valStr = expStr;
 
3604
                expStr = tmp;
 
3605
            }
 
3606
            if ((*valStr != 0) && (*expStr != 0) && (*expStr++ == '*')) {
 
3607
                do {
 
3608
                    if (*valStr == XML_REG_STRING_SEPARATOR)
 
3609
                        break;
 
3610
                    valStr++;
 
3611
                } while (*valStr != 0);
 
3612
                continue;
 
3613
            } else
 
3614
                return(0);
 
3615
        }
 
3616
        expStr++;
 
3617
        valStr++;
 
3618
    } while (*valStr != 0);
 
3619
    if (*expStr != 0)
 
3620
        return (0);
 
3621
    else
 
3622
        return (1);
 
3623
}
 
3624
 
 
3625
/**
 
3626
 * xmlRegCompactPushString:
 
3627
 * @exec: a regexp execution context
 
3628
 * @comp:  the precompiled exec with a compact table
 
3629
 * @value: a string token input
 
3630
 * @data: data associated to the token to reuse in callbacks
 
3631
 *
 
3632
 * Push one input token in the execution context
 
3633
 *
 
3634
 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
 
3635
 *     a negative value in case of error.
 
3636
 */
 
3637
static int
 
3638
xmlRegCompactPushString(xmlRegExecCtxtPtr exec,
 
3639
                        xmlRegexpPtr comp,
 
3640
                        const xmlChar *value,
 
3641
                        void *data) {
 
3642
    int state = exec->index;
 
3643
    int i, target;
 
3644
 
 
3645
    if ((comp == NULL) || (comp->compact == NULL) || (comp->stringMap == NULL))
 
3646
        return(-1);
 
3647
    
 
3648
    if (value == NULL) {
 
3649
        /*
 
3650
         * are we at a final state ?
 
3651
         */
 
3652
        if (comp->compact[state * (comp->nbstrings + 1)] ==
 
3653
            XML_REGEXP_FINAL_STATE)
 
3654
            return(1);
 
3655
        return(0);
 
3656
    }
 
3657
 
 
3658
#ifdef DEBUG_PUSH
 
3659
    printf("value pushed: %s\n", value);
 
3660
#endif
 
3661
 
 
3662
    /*
 
3663
     * Examine all outside transitions from current state
 
3664
     */
 
3665
    for (i = 0;i < comp->nbstrings;i++) {
 
3666
        target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
 
3667
        if ((target > 0) && (target <= comp->nbstates)) {
 
3668
            target--; /* to avoid 0 */    
 
3669
            if (xmlRegStrEqualWildcard(comp->stringMap[i], value)) {
 
3670
                exec->index = target;           
 
3671
                if ((exec->callback != NULL) && (comp->transdata != NULL)) {
 
3672
                    exec->callback(exec->data, value,
 
3673
                          comp->transdata[state * comp->nbstrings + i], data);
 
3674
                }
 
3675
#ifdef DEBUG_PUSH
 
3676
                printf("entering state %d\n", target);
 
3677
#endif
 
3678
                if (comp->compact[target * (comp->nbstrings + 1)] ==
 
3679
                    XML_REGEXP_SINK_STATE)
 
3680
                    goto error;
 
3681
 
 
3682
                if (comp->compact[target * (comp->nbstrings + 1)] ==
 
3683
                    XML_REGEXP_FINAL_STATE)
 
3684
                    return(1);
 
3685
                return(0);
 
3686
            }
 
3687
        }
 
3688
    }
 
3689
    /*
 
3690
     * Failed to find an exit transition out from current state for the
 
3691
     * current token
 
3692
     */
 
3693
#ifdef DEBUG_PUSH
 
3694
    printf("failed to find a transition for %s on state %d\n", value, state);
 
3695
#endif
 
3696
error:
 
3697
    if (exec->errString != NULL)
 
3698
        xmlFree(exec->errString);
 
3699
    exec->errString = xmlStrdup(value);
 
3700
    exec->errStateNo = state;
 
3701
    exec->status = -1;
 
3702
#ifdef DEBUG_ERR
 
3703
    testerr(exec);
 
3704
#endif
 
3705
    return(-1);
 
3706
}
 
3707
 
 
3708
/**
 
3709
 * xmlRegExecPushStringInternal:
 
3710
 * @exec: a regexp execution context or NULL to indicate the end
 
3711
 * @value: a string token input
 
3712
 * @data: data associated to the token to reuse in callbacks
 
3713
 * @compound: value was assembled from 2 strings
 
3714
 *
 
3715
 * Push one input token in the execution context
 
3716
 *
 
3717
 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
 
3718
 *     a negative value in case of error.
 
3719
 */
 
3720
static int
 
3721
xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value,
 
3722
                             void *data, int compound) {
 
3723
    xmlRegTransPtr trans;
 
3724
    xmlRegAtomPtr atom;
 
3725
    int ret;
 
3726
    int final = 0;
 
3727
    int progress = 1;
 
3728
 
 
3729
    if (exec == NULL)
 
3730
        return(-1);
 
3731
    if (exec->comp == NULL)
 
3732
        return(-1);
 
3733
    if (exec->status != 0)
 
3734
        return(exec->status);
 
3735
 
 
3736
    if (exec->comp->compact != NULL)
 
3737
        return(xmlRegCompactPushString(exec, exec->comp, value, data));
 
3738
 
 
3739
    if (value == NULL) {
 
3740
        if (exec->state->type == XML_REGEXP_FINAL_STATE)
 
3741
            return(1);
 
3742
        final = 1;
 
3743
    }
 
3744
 
 
3745
#ifdef DEBUG_PUSH
 
3746
    printf("value pushed: %s\n", value);
 
3747
#endif
 
3748
    /*
 
3749
     * If we have an active rollback stack push the new value there
 
3750
     * and get back to where we were left
 
3751
     */
 
3752
    if ((value != NULL) && (exec->inputStackNr > 0)) {
 
3753
        xmlFARegExecSaveInputString(exec, value, data);
 
3754
        value = exec->inputStack[exec->index].value;
 
3755
        data = exec->inputStack[exec->index].data;
 
3756
#ifdef DEBUG_PUSH
 
3757
        printf("value loaded: %s\n", value);
 
3758
#endif
 
3759
    }
 
3760
 
 
3761
    while ((exec->status == 0) &&
 
3762
           ((value != NULL) ||
 
3763
            ((final == 1) &&
 
3764
             (exec->state->type != XML_REGEXP_FINAL_STATE)))) {
 
3765
 
 
3766
        /*
 
3767
         * End of input on non-terminal state, rollback, however we may
 
3768
         * still have epsilon like transition for counted transitions
 
3769
         * on counters, in that case don't break too early.
 
3770
         */
 
3771
        if ((value == NULL) && (exec->counts == NULL))
 
3772
            goto rollback;
 
3773
 
 
3774
        exec->transcount = 0;
 
3775
        for (;exec->transno < exec->state->nbTrans;exec->transno++) {
 
3776
            trans = &exec->state->trans[exec->transno];
 
3777
            if (trans->to < 0)
 
3778
                continue;
 
3779
            atom = trans->atom;
 
3780
            ret = 0;
 
3781
            if (trans->count == REGEXP_ALL_LAX_COUNTER) {
 
3782
                int i;
 
3783
                int count;
 
3784
                xmlRegTransPtr t;
 
3785
                xmlRegCounterPtr counter;
 
3786
 
 
3787
                ret = 0;
 
3788
 
 
3789
#ifdef DEBUG_PUSH
 
3790
                printf("testing all lax %d\n", trans->count);
 
3791
#endif
 
3792
                /*
 
3793
                 * Check all counted transitions from the current state
 
3794
                 */
 
3795
                if ((value == NULL) && (final)) {
 
3796
                    ret = 1;
 
3797
                } else if (value != NULL) {
 
3798
                    for (i = 0;i < exec->state->nbTrans;i++) {
 
3799
                        t = &exec->state->trans[i];
 
3800
                        if ((t->counter < 0) || (t == trans))
 
3801
                            continue;
 
3802
                        counter = &exec->comp->counters[t->counter];
 
3803
                        count = exec->counts[t->counter];
 
3804
                        if ((count < counter->max) && 
 
3805
                            (t->atom != NULL) &&
 
3806
                            (xmlStrEqual(value, t->atom->valuep))) {
 
3807
                            ret = 0;
 
3808
                            break;
 
3809
                        }
 
3810
                        if ((count >= counter->min) &&
 
3811
                            (count < counter->max) &&
 
3812
                            (t->atom != NULL) &&
 
3813
                            (xmlStrEqual(value, t->atom->valuep))) {
 
3814
                            ret = 1;
 
3815
                            break;
 
3816
                        }
 
3817
                    }
 
3818
                }
 
3819
            } else if (trans->count == REGEXP_ALL_COUNTER) {
 
3820
                int i;
 
3821
                int count;
 
3822
                xmlRegTransPtr t;
 
3823
                xmlRegCounterPtr counter;
 
3824
 
 
3825
                ret = 1;
 
3826
 
 
3827
#ifdef DEBUG_PUSH
 
3828
                printf("testing all %d\n", trans->count);
 
3829
#endif
 
3830
                /*
 
3831
                 * Check all counted transitions from the current state
 
3832
                 */
 
3833
                for (i = 0;i < exec->state->nbTrans;i++) {
 
3834
                    t = &exec->state->trans[i];
 
3835
                    if ((t->counter < 0) || (t == trans))
 
3836
                        continue;
 
3837
                    counter = &exec->comp->counters[t->counter];
 
3838
                    count = exec->counts[t->counter];
 
3839
                    if ((count < counter->min) || (count > counter->max)) {
 
3840
                        ret = 0;
 
3841
                        break;
 
3842
                    }
 
3843
                }
 
3844
            } else if (trans->count >= 0) {
 
3845
                int count;
 
3846
                xmlRegCounterPtr counter;
 
3847
 
 
3848
                /*
 
3849
                 * A counted transition.
 
3850
                 */
 
3851
 
 
3852
                count = exec->counts[trans->count];
 
3853
                counter = &exec->comp->counters[trans->count];
 
3854
#ifdef DEBUG_PUSH
 
3855
                printf("testing count %d: val %d, min %d, max %d\n",
 
3856
                       trans->count, count, counter->min,  counter->max);
 
3857
#endif
 
3858
                ret = ((count >= counter->min) && (count <= counter->max));
 
3859
            } else if (atom == NULL) {
 
3860
                fprintf(stderr, "epsilon transition left at runtime\n");
 
3861
                exec->status = -2;
 
3862
                break;
 
3863
            } else if (value != NULL) {
 
3864
                ret = xmlRegStrEqualWildcard(atom->valuep, value);
 
3865
                if (atom->neg) {
 
3866
                    ret = !ret;
 
3867
                    if (!compound)
 
3868
                        ret = 0;
 
3869
                }
 
3870
                if ((ret == 1) && (trans->counter >= 0)) {
 
3871
                    xmlRegCounterPtr counter;
 
3872
                    int count;
 
3873
 
 
3874
                    count = exec->counts[trans->counter];
 
3875
                    counter = &exec->comp->counters[trans->counter];
 
3876
                    if (count >= counter->max)
 
3877
                        ret = 0;
 
3878
                }
 
3879
 
 
3880
                if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
 
3881
                    xmlRegStatePtr to = exec->comp->states[trans->to];
 
3882
 
 
3883
                    /*
 
3884
                     * this is a multiple input sequence
 
3885
                     */
 
3886
                    if (exec->state->nbTrans > exec->transno + 1) {
 
3887
                        if (exec->inputStackNr <= 0) {
 
3888
                            xmlFARegExecSaveInputString(exec, value, data);
 
3889
                        }
 
3890
                        xmlFARegExecSave(exec);
 
3891
                    }
 
3892
                    exec->transcount = 1;
 
3893
                    do {
 
3894
                        /*
 
3895
                         * Try to progress as much as possible on the input
 
3896
                         */
 
3897
                        if (exec->transcount == atom->max) {
 
3898
                            break;
 
3899
                        }
 
3900
                        exec->index++;
 
3901
                        value = exec->inputStack[exec->index].value;
 
3902
                        data = exec->inputStack[exec->index].data;
 
3903
#ifdef DEBUG_PUSH
 
3904
                        printf("value loaded: %s\n", value);
 
3905
#endif
 
3906
 
 
3907
                        /*
 
3908
                         * End of input: stop here
 
3909
                         */
 
3910
                        if (value == NULL) {
 
3911
                            exec->index --;
 
3912
                            break;
 
3913
                        }
 
3914
                        if (exec->transcount >= atom->min) {
 
3915
                            int transno = exec->transno;
 
3916
                            xmlRegStatePtr state = exec->state;
 
3917
 
 
3918
                            /*
 
3919
                             * The transition is acceptable save it
 
3920
                             */
 
3921
                            exec->transno = -1; /* trick */
 
3922
                            exec->state = to;
 
3923
                            if (exec->inputStackNr <= 0) {
 
3924
                                xmlFARegExecSaveInputString(exec, value, data);
 
3925
                            }
 
3926
                            xmlFARegExecSave(exec);
 
3927
                            exec->transno = transno;
 
3928
                            exec->state = state;
 
3929
                        }
 
3930
                        ret = xmlStrEqual(value, atom->valuep);
 
3931
                        exec->transcount++;
 
3932
                    } while (ret == 1);
 
3933
                    if (exec->transcount < atom->min)
 
3934
                        ret = 0;
 
3935
 
 
3936
                    /*
 
3937
                     * If the last check failed but one transition was found
 
3938
                     * possible, rollback
 
3939
                     */
 
3940
                    if (ret < 0)
 
3941
                        ret = 0;
 
3942
                    if (ret == 0) {
 
3943
                        goto rollback;
 
3944
                    }
 
3945
                }
 
3946
            }
 
3947
            if (ret == 1) {
 
3948
                if ((exec->callback != NULL) && (atom != NULL) &&
 
3949
                        (data != NULL)) {
 
3950
                    exec->callback(exec->data, atom->valuep,
 
3951
                                   atom->data, data);
 
3952
                }
 
3953
                if (exec->state->nbTrans > exec->transno + 1) {
 
3954
                    if (exec->inputStackNr <= 0) {
 
3955
                        xmlFARegExecSaveInputString(exec, value, data);
 
3956
                    }
 
3957
                    xmlFARegExecSave(exec);
 
3958
                }
 
3959
                if (trans->counter >= 0) {
 
3960
#ifdef DEBUG_PUSH
 
3961
                    printf("Increasing count %d\n", trans->counter);
 
3962
#endif
 
3963
                    exec->counts[trans->counter]++;
 
3964
                }
 
3965
                if ((trans->count >= 0) &&
 
3966
                    (trans->count < REGEXP_ALL_COUNTER)) {
 
3967
#ifdef DEBUG_REGEXP_EXEC
 
3968
                    printf("resetting count %d on transition\n",
 
3969
                           trans->count);
 
3970
#endif
 
3971
                    exec->counts[trans->count] = 0;
 
3972
                }
 
3973
#ifdef DEBUG_PUSH
 
3974
                printf("entering state %d\n", trans->to);
 
3975
#endif
 
3976
                if ((exec->comp->states[trans->to] != NULL) &&
 
3977
                    (exec->comp->states[trans->to]->type ==
 
3978
                     XML_REGEXP_SINK_STATE)) {
 
3979
                    /*
 
3980
                     * entering a sink state, save the current state as error
 
3981
                     * state.
 
3982
                     */
 
3983
                    if (exec->errString != NULL)
 
3984
                        xmlFree(exec->errString);
 
3985
                    exec->errString = xmlStrdup(value);
 
3986
                    exec->errState = exec->state;
 
3987
                    memcpy(exec->errCounts, exec->counts,
 
3988
                           exec->comp->nbCounters * sizeof(int));
 
3989
                }
 
3990
                exec->state = exec->comp->states[trans->to];
 
3991
                exec->transno = 0;
 
3992
                if (trans->atom != NULL) {
 
3993
                    if (exec->inputStack != NULL) {
 
3994
                        exec->index++;
 
3995
                        if (exec->index < exec->inputStackNr) {
 
3996
                            value = exec->inputStack[exec->index].value;
 
3997
                            data = exec->inputStack[exec->index].data;
 
3998
#ifdef DEBUG_PUSH
 
3999
                            printf("value loaded: %s\n", value);
 
4000
#endif
 
4001
                        } else {
 
4002
                            value = NULL;
 
4003
                            data = NULL;
 
4004
#ifdef DEBUG_PUSH
 
4005
                            printf("end of input\n");
 
4006
#endif
 
4007
                        }
 
4008
                    } else {
 
4009
                        value = NULL;
 
4010
                        data = NULL;
 
4011
#ifdef DEBUG_PUSH
 
4012
                        printf("end of input\n");
 
4013
#endif
 
4014
                    }
 
4015
                }
 
4016
                goto progress;
 
4017
            } else if (ret < 0) {
 
4018
                exec->status = -4;
 
4019
                break;
 
4020
            }
 
4021
        }
 
4022
        if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
 
4023
rollback:
 
4024
            /*
 
4025
             * if we didn't yet rollback on the current input
 
4026
             * store the current state as the error state.
 
4027
             */
 
4028
            if ((progress) && (exec->state != NULL) &&
 
4029
                (exec->state->type != XML_REGEXP_SINK_STATE)) {
 
4030
                progress = 0;
 
4031
                if (exec->errString != NULL)
 
4032
                    xmlFree(exec->errString);
 
4033
                exec->errString = xmlStrdup(value);
 
4034
                exec->errState = exec->state;
 
4035
                memcpy(exec->errCounts, exec->counts,
 
4036
                       exec->comp->nbCounters * sizeof(int));
 
4037
            }
 
4038
 
 
4039
            /*
 
4040
             * Failed to find a way out
 
4041
             */
 
4042
            exec->determinist = 0;
 
4043
            xmlFARegExecRollBack(exec);
 
4044
            if (exec->status == 0) {
 
4045
                value = exec->inputStack[exec->index].value;
 
4046
                data = exec->inputStack[exec->index].data;
 
4047
#ifdef DEBUG_PUSH
 
4048
                printf("value loaded: %s\n", value);
 
4049
#endif
 
4050
            }
 
4051
        }
 
4052
        continue;
 
4053
progress:
 
4054
        progress = 1;
 
4055
        continue;
 
4056
    }
 
4057
    if (exec->status == 0) {
 
4058
        return(exec->state->type == XML_REGEXP_FINAL_STATE);
 
4059
    }
 
4060
#ifdef DEBUG_ERR
 
4061
    if (exec->status < 0) {
 
4062
        testerr(exec);
 
4063
    }
 
4064
#endif
 
4065
    return(exec->status);
 
4066
}
 
4067
 
 
4068
/**
 
4069
 * xmlRegExecPushString:
 
4070
 * @exec: a regexp execution context or NULL to indicate the end
 
4071
 * @value: a string token input
 
4072
 * @data: data associated to the token to reuse in callbacks
 
4073
 *
 
4074
 * Push one input token in the execution context
 
4075
 *
 
4076
 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
 
4077
 *     a negative value in case of error.
 
4078
 */
 
4079
int
 
4080
xmlRegExecPushString(xmlRegExecCtxtPtr exec, const xmlChar *value,
 
4081
                     void *data) {
 
4082
    return(xmlRegExecPushStringInternal(exec, value, data, 0));
 
4083
}
 
4084
 
 
4085
/**
 
4086
 * xmlRegExecPushString2:
 
4087
 * @exec: a regexp execution context or NULL to indicate the end
 
4088
 * @value: the first string token input
 
4089
 * @value2: the second string token input
 
4090
 * @data: data associated to the token to reuse in callbacks
 
4091
 *
 
4092
 * Push one input token in the execution context
 
4093
 *
 
4094
 * Returns: 1 if the regexp reached a final state, 0 if non-final, and
 
4095
 *     a negative value in case of error.
 
4096
 */
 
4097
int
 
4098
xmlRegExecPushString2(xmlRegExecCtxtPtr exec, const xmlChar *value,
 
4099
                      const xmlChar *value2, void *data) {
 
4100
    xmlChar buf[150];
 
4101
    int lenn, lenp, ret;
 
4102
    xmlChar *str;
 
4103
 
 
4104
    if (exec == NULL)
 
4105
        return(-1);
 
4106
    if (exec->comp == NULL)
 
4107
        return(-1);
 
4108
    if (exec->status != 0)
 
4109
        return(exec->status);
 
4110
 
 
4111
    if (value2 == NULL)
 
4112
        return(xmlRegExecPushString(exec, value, data));
 
4113
 
 
4114
    lenn = strlen((char *) value2);
 
4115
    lenp = strlen((char *) value);
 
4116
 
 
4117
    if (150 < lenn + lenp + 2) {
 
4118
        str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
 
4119
        if (str == NULL) {
 
4120
            exec->status = -1;
 
4121
            return(-1);
 
4122
        }
 
4123
    } else {
 
4124
        str = buf;
 
4125
    }
 
4126
    memcpy(&str[0], value, lenp);
 
4127
    str[lenp] = XML_REG_STRING_SEPARATOR;
 
4128
    memcpy(&str[lenp + 1], value2, lenn);
 
4129
    str[lenn + lenp + 1] = 0;
 
4130
 
 
4131
    if (exec->comp->compact != NULL)
 
4132
        ret = xmlRegCompactPushString(exec, exec->comp, str, data);
 
4133
    else
 
4134
        ret = xmlRegExecPushStringInternal(exec, str, data, 1);
 
4135
 
 
4136
    if (str != buf)
 
4137
        xmlFree(str);
 
4138
    return(ret);
 
4139
}
 
4140
 
 
4141
/**
 
4142
 * xmlRegExecGetValues:
 
4143
 * @exec: a regexp execution context
 
4144
 * @err: error extraction or normal one
 
4145
 * @nbval: pointer to the number of accepted values IN/OUT
 
4146
 * @nbneg: return number of negative transitions
 
4147
 * @values: pointer to the array of acceptable values
 
4148
 * @terminal: return value if this was a terminal state
 
4149
 *
 
4150
 * Extract informations from the regexp execution, internal routine to
 
4151
 * implement xmlRegExecNextValues() and xmlRegExecErrInfo()
 
4152
 *
 
4153
 * Returns: 0 in case of success or -1 in case of error.
 
4154
 */
 
4155
static int
 
4156
xmlRegExecGetValues(xmlRegExecCtxtPtr exec, int err,
 
4157
                    int *nbval, int *nbneg,
 
4158
                    xmlChar **values, int *terminal) {
 
4159
    int maxval;
 
4160
    int nb = 0;
 
4161
 
 
4162
    if ((exec == NULL) || (nbval == NULL) || (nbneg == NULL) || 
 
4163
        (values == NULL) || (*nbval <= 0))
 
4164
        return(-1);
 
4165
 
 
4166
    maxval = *nbval;
 
4167
    *nbval = 0;
 
4168
    *nbneg = 0;
 
4169
    if ((exec->comp != NULL) && (exec->comp->compact != NULL)) {
 
4170
        xmlRegexpPtr comp;
 
4171
        int target, i, state;
 
4172
 
 
4173
        comp = exec->comp;
 
4174
 
 
4175
        if (err) {
 
4176
            if (exec->errStateNo == -1) return(-1);
 
4177
            state = exec->errStateNo;
 
4178
        } else {
 
4179
            state = exec->index;
 
4180
        }
 
4181
        if (terminal != NULL) {
 
4182
            if (comp->compact[state * (comp->nbstrings + 1)] ==
 
4183
                XML_REGEXP_FINAL_STATE)
 
4184
                *terminal = 1;
 
4185
            else
 
4186
                *terminal = 0;
 
4187
        }
 
4188
        for (i = 0;(i < comp->nbstrings) && (nb < maxval);i++) {
 
4189
            target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
 
4190
            if ((target > 0) && (target <= comp->nbstates) &&
 
4191
                (comp->compact[(target - 1) * (comp->nbstrings + 1)] !=
 
4192
                 XML_REGEXP_SINK_STATE)) {
 
4193
                values[nb++] = comp->stringMap[i];
 
4194
                (*nbval)++;
 
4195
            }
 
4196
        }
 
4197
        for (i = 0;(i < comp->nbstrings) && (nb < maxval);i++) {
 
4198
            target = comp->compact[state * (comp->nbstrings + 1) + i + 1];
 
4199
            if ((target > 0) && (target <= comp->nbstates) &&
 
4200
                (comp->compact[(target - 1) * (comp->nbstrings + 1)] ==
 
4201
                 XML_REGEXP_SINK_STATE)) {
 
4202
                values[nb++] = comp->stringMap[i];
 
4203
                (*nbneg)++;
 
4204
            }
 
4205
        }
 
4206
    } else {
 
4207
        int transno;
 
4208
        xmlRegTransPtr trans;
 
4209
        xmlRegAtomPtr atom;
 
4210
        xmlRegStatePtr state;
 
4211
 
 
4212
        if (terminal != NULL) {
 
4213
            if (exec->state->type == XML_REGEXP_FINAL_STATE)
 
4214
                *terminal = 1;
 
4215
            else
 
4216
                *terminal = 0;
 
4217
        }
 
4218
 
 
4219
        if (err) {
 
4220
            if (exec->errState == NULL) return(-1);
 
4221
            state = exec->errState;
 
4222
        } else {
 
4223
            if (exec->state == NULL) return(-1);
 
4224
            state = exec->state;
 
4225
        }
 
4226
        for (transno = 0;
 
4227
             (transno < state->nbTrans) && (nb < maxval);
 
4228
             transno++) {
 
4229
            trans = &state->trans[transno];
 
4230
            if (trans->to < 0)
 
4231
                continue;
 
4232
            atom = trans->atom;
 
4233
            if ((atom == NULL) || (atom->valuep == NULL))
 
4234
                continue;
 
4235
            if (trans->count == REGEXP_ALL_LAX_COUNTER) {
 
4236
                /* this should not be reached but ... */
 
4237
                TODO;
 
4238
            } else if (trans->count == REGEXP_ALL_COUNTER) {
 
4239
                /* this should not be reached but ... */
 
4240
                TODO;
 
4241
            } else if (trans->counter >= 0) {
 
4242
                xmlRegCounterPtr counter = NULL;
 
4243
                int count;
 
4244
 
 
4245
                if (err)
 
4246
                    count = exec->errCounts[trans->counter];
 
4247
                else
 
4248
                    count = exec->counts[trans->counter];
 
4249
                if (exec->comp != NULL)
 
4250
                    counter = &exec->comp->counters[trans->counter];
 
4251
                if ((counter == NULL) || (count < counter->max)) {
 
4252
                    if (atom->neg)
 
4253
                        values[nb++] = (xmlChar *) atom->valuep2;
 
4254
                    else
 
4255
                        values[nb++] = (xmlChar *) atom->valuep;
 
4256
                    (*nbval)++;
 
4257
                }
 
4258
            } else {
 
4259
                if ((exec->comp->states[trans->to] != NULL) &&
 
4260
                    (exec->comp->states[trans->to]->type !=
 
4261
                     XML_REGEXP_SINK_STATE)) {
 
4262
                    if (atom->neg)
 
4263
                        values[nb++] = (xmlChar *) atom->valuep2;
 
4264
                    else
 
4265
                        values[nb++] = (xmlChar *) atom->valuep;
 
4266
                    (*nbval)++;
 
4267
                }
 
4268
            } 
 
4269
        }
 
4270
        for (transno = 0;
 
4271
             (transno < state->nbTrans) && (nb < maxval);
 
4272
             transno++) {
 
4273
            trans = &state->trans[transno];
 
4274
            if (trans->to < 0)
 
4275
                continue;
 
4276
            atom = trans->atom;
 
4277
            if ((atom == NULL) || (atom->valuep == NULL))
 
4278
                continue;
 
4279
            if (trans->count == REGEXP_ALL_LAX_COUNTER) {
 
4280
                continue;
 
4281
            } else if (trans->count == REGEXP_ALL_COUNTER) {
 
4282
                continue;
 
4283
            } else if (trans->counter >= 0) {
 
4284
                continue;
 
4285
            } else {
 
4286
                if ((exec->comp->states[trans->to] != NULL) &&
 
4287
                    (exec->comp->states[trans->to]->type ==
 
4288
                     XML_REGEXP_SINK_STATE)) {
 
4289
                    if (atom->neg)
 
4290
                        values[nb++] = (xmlChar *) atom->valuep2;
 
4291
                    else
 
4292
                        values[nb++] = (xmlChar *) atom->valuep;
 
4293
                    (*nbneg)++;
 
4294
                }
 
4295
            } 
 
4296
        }
 
4297
    }
 
4298
    return(0);
 
4299
}
 
4300
 
 
4301
/**
 
4302
 * xmlRegExecNextValues:
 
4303
 * @exec: a regexp execution context
 
4304
 * @nbval: pointer to the number of accepted values IN/OUT
 
4305
 * @nbneg: return number of negative transitions
 
4306
 * @values: pointer to the array of acceptable values
 
4307
 * @terminal: return value if this was a terminal state
 
4308
 *
 
4309
 * Extract informations from the regexp execution,
 
4310
 * the parameter @values must point to an array of @nbval string pointers
 
4311
 * on return nbval will contain the number of possible strings in that
 
4312
 * state and the @values array will be updated with them. The string values
 
4313
 * returned will be freed with the @exec context and don't need to be
 
4314
 * deallocated.
 
4315
 *
 
4316
 * Returns: 0 in case of success or -1 in case of error.
 
4317
 */
 
4318
int
 
4319
xmlRegExecNextValues(xmlRegExecCtxtPtr exec, int *nbval, int *nbneg,
 
4320
                     xmlChar **values, int *terminal) {
 
4321
    return(xmlRegExecGetValues(exec, 0, nbval, nbneg, values, terminal));
 
4322
}
 
4323
 
 
4324
/**
 
4325
 * xmlRegExecErrInfo:
 
4326
 * @exec: a regexp execution context generating an error
 
4327
 * @string: return value for the error string
 
4328
 * @nbval: pointer to the number of accepted values IN/OUT
 
4329
 * @nbneg: return number of negative transitions
 
4330
 * @values: pointer to the array of acceptable values
 
4331
 * @terminal: return value if this was a terminal state
 
4332
 *
 
4333
 * Extract error informations from the regexp execution, the parameter
 
4334
 * @string will be updated with the value pushed and not accepted,
 
4335
 * the parameter @values must point to an array of @nbval string pointers
 
4336
 * on return nbval will contain the number of possible strings in that
 
4337
 * state and the @values array will be updated with them. The string values
 
4338
 * returned will be freed with the @exec context and don't need to be
 
4339
 * deallocated.
 
4340
 *
 
4341
 * Returns: 0 in case of success or -1 in case of error.
 
4342
 */
 
4343
int
 
4344
xmlRegExecErrInfo(xmlRegExecCtxtPtr exec, const xmlChar **string,
 
4345
                  int *nbval, int *nbneg, xmlChar **values, int *terminal) {
 
4346
    if (exec == NULL)
 
4347
        return(-1);
 
4348
    if (string != NULL) {
 
4349
        if (exec->status != 0)
 
4350
            *string = exec->errString;
 
4351
        else
 
4352
            *string = NULL;
 
4353
    }
 
4354
    return(xmlRegExecGetValues(exec, 1, nbval, nbneg, values, terminal));
 
4355
}
 
4356
 
 
4357
#ifdef DEBUG_ERR
 
4358
static void testerr(xmlRegExecCtxtPtr exec) {
 
4359
    const xmlChar *string;
 
4360
    xmlChar *values[5];
 
4361
    int nb = 5;
 
4362
    int nbneg;
 
4363
    int terminal;
 
4364
    xmlRegExecErrInfo(exec, &string, &nb, &nbneg, &values[0], &terminal);
 
4365
}
 
4366
#endif
 
4367
 
 
4368
#if 0
 
4369
static int
 
4370
xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) {
 
4371
    xmlRegTransPtr trans;
 
4372
    xmlRegAtomPtr atom;
 
4373
    int ret;
 
4374
    int codepoint, len;
 
4375
 
 
4376
    if (exec == NULL)
 
4377
        return(-1);
 
4378
    if (exec->status != 0)
 
4379
        return(exec->status);
 
4380
 
 
4381
    while ((exec->status == 0) &&
 
4382
           ((exec->inputString[exec->index] != 0) ||
 
4383
            (exec->state->type != XML_REGEXP_FINAL_STATE))) {
 
4384
 
 
4385
        /*
 
4386
         * End of input on non-terminal state, rollback, however we may
 
4387
         * still have epsilon like transition for counted transitions
 
4388
         * on counters, in that case don't break too early.
 
4389
         */
 
4390
        if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL))
 
4391
            goto rollback;
 
4392
 
 
4393
        exec->transcount = 0;
 
4394
        for (;exec->transno < exec->state->nbTrans;exec->transno++) {
 
4395
            trans = &exec->state->trans[exec->transno];
 
4396
            if (trans->to < 0)
 
4397
                continue;
 
4398
            atom = trans->atom;
 
4399
            ret = 0;
 
4400
            if (trans->count >= 0) {
 
4401
                int count;
 
4402
                xmlRegCounterPtr counter;
 
4403
 
 
4404
                /*
 
4405
                 * A counted transition.
 
4406
                 */
 
4407
 
 
4408
                count = exec->counts[trans->count];
 
4409
                counter = &exec->comp->counters[trans->count];
 
4410
#ifdef DEBUG_REGEXP_EXEC
 
4411
                printf("testing count %d: val %d, min %d, max %d\n",
 
4412
                       trans->count, count, counter->min,  counter->max);
 
4413
#endif
 
4414
                ret = ((count >= counter->min) && (count <= counter->max));
 
4415
            } else if (atom == NULL) {
 
4416
                fprintf(stderr, "epsilon transition left at runtime\n");
 
4417
                exec->status = -2;
 
4418
                break;
 
4419
            } else if (exec->inputString[exec->index] != 0) {
 
4420
                codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len);
 
4421
                ret = xmlRegCheckCharacter(atom, codepoint);
 
4422
                if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) {
 
4423
                    xmlRegStatePtr to = exec->comp->states[trans->to];
 
4424
 
 
4425
                    /*
 
4426
                     * this is a multiple input sequence
 
4427
                     */
 
4428
                    if (exec->state->nbTrans > exec->transno + 1) {
 
4429
                        xmlFARegExecSave(exec);
 
4430
                    }
 
4431
                    exec->transcount = 1;
 
4432
                    do {
 
4433
                        /*
 
4434
                         * Try to progress as much as possible on the input
 
4435
                         */
 
4436
                        if (exec->transcount == atom->max) {
 
4437
                            break;
 
4438
                        }
 
4439
                        exec->index += len;
 
4440
                        /*
 
4441
                         * End of input: stop here
 
4442
                         */
 
4443
                        if (exec->inputString[exec->index] == 0) {
 
4444
                            exec->index -= len;
 
4445
                            break;
 
4446
                        }
 
4447
                        if (exec->transcount >= atom->min) {
 
4448
                            int transno = exec->transno;
 
4449
                            xmlRegStatePtr state = exec->state;
 
4450
 
 
4451
                            /*
 
4452
                             * The transition is acceptable save it
 
4453
                             */
 
4454
                            exec->transno = -1; /* trick */
 
4455
                            exec->state = to;
 
4456
                            xmlFARegExecSave(exec);
 
4457
                            exec->transno = transno;
 
4458
                            exec->state = state;
 
4459
                        }
 
4460
                        codepoint = CUR_SCHAR(&(exec->inputString[exec->index]),
 
4461
                                              len);
 
4462
                        ret = xmlRegCheckCharacter(atom, codepoint);
 
4463
                        exec->transcount++;
 
4464
                    } while (ret == 1);
 
4465
                    if (exec->transcount < atom->min)
 
4466
                        ret = 0;
 
4467
 
 
4468
                    /*
 
4469
                     * If the last check failed but one transition was found
 
4470
                     * possible, rollback
 
4471
                     */
 
4472
                    if (ret < 0)
 
4473
                        ret = 0;
 
4474
                    if (ret == 0) {
 
4475
                        goto rollback;
 
4476
                    }
 
4477
                }
 
4478
            }
 
4479
            if (ret == 1) {
 
4480
                if (exec->state->nbTrans > exec->transno + 1) {
 
4481
                    xmlFARegExecSave(exec);
 
4482
                }
 
4483
                /*
 
4484
                 * restart count for expressions like this ((abc){2})*
 
4485
                 */
 
4486
                if (trans->count >= 0) {
 
4487
#ifdef DEBUG_REGEXP_EXEC
 
4488
                    printf("Reset count %d\n", trans->count);
 
4489
#endif
 
4490
                    exec->counts[trans->count] = 0;
 
4491
                }
 
4492
                if (trans->counter >= 0) {
 
4493
#ifdef DEBUG_REGEXP_EXEC
 
4494
                    printf("Increasing count %d\n", trans->counter);
 
4495
#endif
 
4496
                    exec->counts[trans->counter]++;
 
4497
                }
 
4498
#ifdef DEBUG_REGEXP_EXEC
 
4499
                printf("entering state %d\n", trans->to);
 
4500
#endif
 
4501
                exec->state = exec->comp->states[trans->to];
 
4502
                exec->transno = 0;
 
4503
                if (trans->atom != NULL) {
 
4504
                    exec->index += len;
 
4505
                }
 
4506
                goto progress;
 
4507
            } else if (ret < 0) {
 
4508
                exec->status = -4;
 
4509
                break;
 
4510
            }
 
4511
        }
 
4512
        if ((exec->transno != 0) || (exec->state->nbTrans == 0)) {
 
4513
rollback:
 
4514
            /*
 
4515
             * Failed to find a way out
 
4516
             */
 
4517
            exec->determinist = 0;
 
4518
            xmlFARegExecRollBack(exec);
 
4519
        }
 
4520
progress:
 
4521
        continue;
 
4522
    }
 
4523
}
 
4524
#endif
 
4525
/************************************************************************
 
4526
 *                                                                      *
 
4527
 *      Parser for the Schemas Datatype Regular Expressions             *
 
4528
 *      http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#regexs      *
 
4529
 *                                                                      *
 
4530
 ************************************************************************/
 
4531
 
 
4532
/**
 
4533
 * xmlFAIsChar:
 
4534
 * @ctxt:  a regexp parser context
 
4535
 *
 
4536
 * [10]   Char   ::=   [^.\?*+()|#x5B#x5D]
 
4537
 */
 
4538
static int
 
4539
xmlFAIsChar(xmlRegParserCtxtPtr ctxt) {
 
4540
    int cur;
 
4541
    int len;
 
4542
 
 
4543
    cur = CUR_SCHAR(ctxt->cur, len);
 
4544
    if ((cur == '.') || (cur == '\\') || (cur == '?') ||
 
4545
        (cur == '*') || (cur == '+') || (cur == '(') ||
 
4546
        (cur == ')') || (cur == '|') || (cur == 0x5B) ||
 
4547
        (cur == 0x5D) || (cur == 0))
 
4548
        return(-1);
 
4549
    return(cur);
 
4550
}
 
4551
 
 
4552
/**
 
4553
 * xmlFAParseCharProp:
 
4554
 * @ctxt:  a regexp parser context
 
4555
 *
 
4556
 * [27]   charProp   ::=   IsCategory | IsBlock
 
4557
 * [28]   IsCategory ::= Letters | Marks | Numbers | Punctuation |
 
4558
 *                       Separators | Symbols | Others 
 
4559
 * [29]   Letters   ::=   'L' [ultmo]?
 
4560
 * [30]   Marks   ::=   'M' [nce]?
 
4561
 * [31]   Numbers   ::=   'N' [dlo]?
 
4562
 * [32]   Punctuation   ::=   'P' [cdseifo]?
 
4563
 * [33]   Separators   ::=   'Z' [slp]?
 
4564
 * [34]   Symbols   ::=   'S' [mcko]?
 
4565
 * [35]   Others   ::=   'C' [cfon]?
 
4566
 * [36]   IsBlock   ::=   'Is' [a-zA-Z0-9#x2D]+
 
4567
 */
 
4568
static void
 
4569
xmlFAParseCharProp(xmlRegParserCtxtPtr ctxt) {
 
4570
    int cur;
 
4571
    xmlRegAtomType type = (xmlRegAtomType) 0;
 
4572
    xmlChar *blockName = NULL;
 
4573
    
 
4574
    cur = CUR;
 
4575
    if (cur == 'L') {
 
4576
        NEXT;
 
4577
        cur = CUR;
 
4578
        if (cur == 'u') {
 
4579
            NEXT;
 
4580
            type = XML_REGEXP_LETTER_UPPERCASE;
 
4581
        } else if (cur == 'l') {
 
4582
            NEXT;
 
4583
            type = XML_REGEXP_LETTER_LOWERCASE;
 
4584
        } else if (cur == 't') {
 
4585
            NEXT;
 
4586
            type = XML_REGEXP_LETTER_TITLECASE;
 
4587
        } else if (cur == 'm') {
 
4588
            NEXT;
 
4589
            type = XML_REGEXP_LETTER_MODIFIER;
 
4590
        } else if (cur == 'o') {
 
4591
            NEXT;
 
4592
            type = XML_REGEXP_LETTER_OTHERS;
 
4593
        } else {
 
4594
            type = XML_REGEXP_LETTER;
 
4595
        }
 
4596
    } else if (cur == 'M') {
 
4597
        NEXT;
 
4598
        cur = CUR;
 
4599
        if (cur == 'n') {
 
4600
            NEXT;
 
4601
            /* nonspacing */
 
4602
            type = XML_REGEXP_MARK_NONSPACING;
 
4603
        } else if (cur == 'c') {
 
4604
            NEXT;
 
4605
            /* spacing combining */
 
4606
            type = XML_REGEXP_MARK_SPACECOMBINING;
 
4607
        } else if (cur == 'e') {
 
4608
            NEXT;
 
4609
            /* enclosing */
 
4610
            type = XML_REGEXP_MARK_ENCLOSING;
 
4611
        } else {
 
4612
            /* all marks */
 
4613
            type = XML_REGEXP_MARK;
 
4614
        }
 
4615
    } else if (cur == 'N') {
 
4616
        NEXT;
 
4617
        cur = CUR;
 
4618
        if (cur == 'd') {
 
4619
            NEXT;
 
4620
            /* digital */
 
4621
            type = XML_REGEXP_NUMBER_DECIMAL;
 
4622
        } else if (cur == 'l') {
 
4623
            NEXT;
 
4624
            /* letter */
 
4625
            type = XML_REGEXP_NUMBER_LETTER;
 
4626
        } else if (cur == 'o') {
 
4627
            NEXT;
 
4628
            /* other */
 
4629
            type = XML_REGEXP_NUMBER_OTHERS;
 
4630
        } else {
 
4631
            /* all numbers */
 
4632
            type = XML_REGEXP_NUMBER;
 
4633
        }
 
4634
    } else if (cur == 'P') {
 
4635
        NEXT;
 
4636
        cur = CUR;
 
4637
        if (cur == 'c') {
 
4638
            NEXT;
 
4639
            /* connector */
 
4640
            type = XML_REGEXP_PUNCT_CONNECTOR;
 
4641
        } else if (cur == 'd') {
 
4642
            NEXT;
 
4643
            /* dash */
 
4644
            type = XML_REGEXP_PUNCT_DASH;
 
4645
        } else if (cur == 's') {
 
4646
            NEXT;
 
4647
            /* open */
 
4648
            type = XML_REGEXP_PUNCT_OPEN;
 
4649
        } else if (cur == 'e') {
 
4650
            NEXT;
 
4651
            /* close */
 
4652
            type = XML_REGEXP_PUNCT_CLOSE;
 
4653
        } else if (cur == 'i') {
 
4654
            NEXT;
 
4655
            /* initial quote */
 
4656
            type = XML_REGEXP_PUNCT_INITQUOTE;
 
4657
        } else if (cur == 'f') {
 
4658
            NEXT;
 
4659
            /* final quote */
 
4660
            type = XML_REGEXP_PUNCT_FINQUOTE;
 
4661
        } else if (cur == 'o') {
 
4662
            NEXT;
 
4663
            /* other */
 
4664
            type = XML_REGEXP_PUNCT_OTHERS;
 
4665
        } else {
 
4666
            /* all punctuation */
 
4667
            type = XML_REGEXP_PUNCT;
 
4668
        }
 
4669
    } else if (cur == 'Z') {
 
4670
        NEXT;
 
4671
        cur = CUR;
 
4672
        if (cur == 's') {
 
4673
            NEXT;
 
4674
            /* space */
 
4675
            type = XML_REGEXP_SEPAR_SPACE;
 
4676
        } else if (cur == 'l') {
 
4677
            NEXT;
 
4678
            /* line */
 
4679
            type = XML_REGEXP_SEPAR_LINE;
 
4680
        } else if (cur == 'p') {
 
4681
            NEXT;
 
4682
            /* paragraph */
 
4683
            type = XML_REGEXP_SEPAR_PARA;
 
4684
        } else {
 
4685
            /* all separators */
 
4686
            type = XML_REGEXP_SEPAR;
 
4687
        }
 
4688
    } else if (cur == 'S') {
 
4689
        NEXT;
 
4690
        cur = CUR;
 
4691
        if (cur == 'm') {
 
4692
            NEXT;
 
4693
            type = XML_REGEXP_SYMBOL_MATH;
 
4694
            /* math */
 
4695
        } else if (cur == 'c') {
 
4696
            NEXT;
 
4697
            type = XML_REGEXP_SYMBOL_CURRENCY;
 
4698
            /* currency */
 
4699
        } else if (cur == 'k') {
 
4700
            NEXT;
 
4701
            type = XML_REGEXP_SYMBOL_MODIFIER;
 
4702
            /* modifiers */
 
4703
        } else if (cur == 'o') {
 
4704
            NEXT;
 
4705
            type = XML_REGEXP_SYMBOL_OTHERS;
 
4706
            /* other */
 
4707
        } else {
 
4708
            /* all symbols */
 
4709
            type = XML_REGEXP_SYMBOL;
 
4710
        }
 
4711
    } else if (cur == 'C') {
 
4712
        NEXT;
 
4713
        cur = CUR;
 
4714
        if (cur == 'c') {
 
4715
            NEXT;
 
4716
            /* control */
 
4717
            type = XML_REGEXP_OTHER_CONTROL;
 
4718
        } else if (cur == 'f') {
 
4719
            NEXT;
 
4720
            /* format */
 
4721
            type = XML_REGEXP_OTHER_FORMAT;
 
4722
        } else if (cur == 'o') {
 
4723
            NEXT;
 
4724
            /* private use */
 
4725
            type = XML_REGEXP_OTHER_PRIVATE;
 
4726
        } else if (cur == 'n') {
 
4727
            NEXT;
 
4728
            /* not assigned */
 
4729
            type = XML_REGEXP_OTHER_NA;
 
4730
        } else {
 
4731
            /* all others */
 
4732
            type = XML_REGEXP_OTHER;
 
4733
        }
 
4734
    } else if (cur == 'I') {
 
4735
        const xmlChar *start;
 
4736
        NEXT;
 
4737
        cur = CUR;
 
4738
        if (cur != 's') {
 
4739
            ERROR("IsXXXX expected");
 
4740
            return;
 
4741
        }
 
4742
        NEXT;
 
4743
        start = ctxt->cur;
 
4744
        cur = CUR;
 
4745
        if (((cur >= 'a') && (cur <= 'z')) || 
 
4746
            ((cur >= 'A') && (cur <= 'Z')) || 
 
4747
            ((cur >= '0') && (cur <= '9')) || 
 
4748
            (cur == 0x2D)) {
 
4749
            NEXT;
 
4750
            cur = CUR;
 
4751
            while (((cur >= 'a') && (cur <= 'z')) || 
 
4752
                ((cur >= 'A') && (cur <= 'Z')) || 
 
4753
                ((cur >= '0') && (cur <= '9')) || 
 
4754
                (cur == 0x2D)) {
 
4755
                NEXT;
 
4756
                cur = CUR;
 
4757
            }
 
4758
        }
 
4759
        type = XML_REGEXP_BLOCK_NAME;
 
4760
        blockName = xmlStrndup(start, ctxt->cur - start);
 
4761
    } else {
 
4762
        ERROR("Unknown char property");
 
4763
        return;
 
4764
    }
 
4765
    if (ctxt->atom == NULL) {
 
4766
        ctxt->atom = xmlRegNewAtom(ctxt, type);
 
4767
        if (ctxt->atom != NULL)
 
4768
            ctxt->atom->valuep = blockName;
 
4769
    } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
 
4770
        xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
 
4771
                           type, 0, 0, blockName);
 
4772
    }
 
4773
}
 
4774
 
 
4775
/**
 
4776
 * xmlFAParseCharClassEsc:
 
4777
 * @ctxt:  a regexp parser context
 
4778
 *
 
4779
 * [23] charClassEsc ::= ( SingleCharEsc | MultiCharEsc | catEsc | complEsc ) 
 
4780
 * [24] SingleCharEsc ::= '\' [nrt\|.?*+(){}#x2D#x5B#x5D#x5E]
 
4781
 * [25] catEsc   ::=   '\p{' charProp '}'
 
4782
 * [26] complEsc ::=   '\P{' charProp '}'
 
4783
 * [37] MultiCharEsc ::= '.' | ('\' [sSiIcCdDwW])
 
4784
 */
 
4785
static void
 
4786
xmlFAParseCharClassEsc(xmlRegParserCtxtPtr ctxt) {
 
4787
    int cur;
 
4788
 
 
4789
    if (CUR == '.') {
 
4790
        if (ctxt->atom == NULL) {
 
4791
            ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_ANYCHAR);
 
4792
        } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
 
4793
            xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
 
4794
                               XML_REGEXP_ANYCHAR, 0, 0, NULL);
 
4795
        }
 
4796
        NEXT;
 
4797
        return;
 
4798
    }
 
4799
    if (CUR != '\\') {
 
4800
        ERROR("Escaped sequence: expecting \\");
 
4801
        return;
 
4802
    }
 
4803
    NEXT;
 
4804
    cur = CUR;
 
4805
    if (cur == 'p') {
 
4806
        NEXT;
 
4807
        if (CUR != '{') {
 
4808
            ERROR("Expecting '{'");
 
4809
            return;
 
4810
        }
 
4811
        NEXT;
 
4812
        xmlFAParseCharProp(ctxt);
 
4813
        if (CUR != '}') {
 
4814
            ERROR("Expecting '}'");
 
4815
            return;
 
4816
        }
 
4817
        NEXT;
 
4818
    } else if (cur == 'P') {
 
4819
        NEXT;
 
4820
        if (CUR != '{') {
 
4821
            ERROR("Expecting '{'");
 
4822
            return;
 
4823
        }
 
4824
        NEXT;
 
4825
        xmlFAParseCharProp(ctxt);
 
4826
        ctxt->atom->neg = 1;
 
4827
        if (CUR != '}') {
 
4828
            ERROR("Expecting '}'");
 
4829
            return;
 
4830
        }
 
4831
        NEXT;
 
4832
    } else if ((cur == 'n') || (cur == 'r') || (cur == 't') || (cur == '\\') ||
 
4833
        (cur == '|') || (cur == '.') || (cur == '?') || (cur == '*') ||
 
4834
        (cur == '+') || (cur == '(') || (cur == ')') || (cur == '{') ||
 
4835
        (cur == '}') || (cur == 0x2D) || (cur == 0x5B) || (cur == 0x5D) ||
 
4836
        (cur == 0x5E)) {
 
4837
        if (ctxt->atom == NULL) {
 
4838
            ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL);
 
4839
            if (ctxt->atom != NULL) {
 
4840
                switch (cur) {
 
4841
                    case 'n':
 
4842
                        ctxt->atom->codepoint = '\n';
 
4843
                        break;
 
4844
                    case 'r':
 
4845
                        ctxt->atom->codepoint = '\r';
 
4846
                        break;
 
4847
                    case 't':
 
4848
                        ctxt->atom->codepoint = '\t';
 
4849
                        break;
 
4850
                    default:
 
4851
                        ctxt->atom->codepoint = cur;
 
4852
                }
 
4853
            }
 
4854
        } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
 
4855
            xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
 
4856
                               XML_REGEXP_CHARVAL, cur, cur, NULL);
 
4857
        }
 
4858
        NEXT;
 
4859
    } else if ((cur == 's') || (cur == 'S') || (cur == 'i') || (cur == 'I') ||
 
4860
        (cur == 'c') || (cur == 'C') || (cur == 'd') || (cur == 'D') ||
 
4861
        (cur == 'w') || (cur == 'W')) {
 
4862
        xmlRegAtomType type = XML_REGEXP_ANYSPACE;
 
4863
 
 
4864
        switch (cur) {
 
4865
            case 's': 
 
4866
                type = XML_REGEXP_ANYSPACE;
 
4867
                break;
 
4868
            case 'S': 
 
4869
                type = XML_REGEXP_NOTSPACE;
 
4870
                break;
 
4871
            case 'i': 
 
4872
                type = XML_REGEXP_INITNAME;
 
4873
                break;
 
4874
            case 'I': 
 
4875
                type = XML_REGEXP_NOTINITNAME;
 
4876
                break;
 
4877
            case 'c': 
 
4878
                type = XML_REGEXP_NAMECHAR;
 
4879
                break;
 
4880
            case 'C': 
 
4881
                type = XML_REGEXP_NOTNAMECHAR;
 
4882
                break;
 
4883
            case 'd': 
 
4884
                type = XML_REGEXP_DECIMAL;
 
4885
                break;
 
4886
            case 'D': 
 
4887
                type = XML_REGEXP_NOTDECIMAL;
 
4888
                break;
 
4889
            case 'w': 
 
4890
                type = XML_REGEXP_REALCHAR;
 
4891
                break;
 
4892
            case 'W': 
 
4893
                type = XML_REGEXP_NOTREALCHAR;
 
4894
                break;
 
4895
        }
 
4896
        NEXT;
 
4897
        if (ctxt->atom == NULL) {
 
4898
            ctxt->atom = xmlRegNewAtom(ctxt, type);
 
4899
        } else if (ctxt->atom->type == XML_REGEXP_RANGES) {
 
4900
            xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
 
4901
                               type, 0, 0, NULL);
 
4902
        }
 
4903
    } else {
 
4904
        ERROR("Wrong escape sequence, misuse of character '\\'");
 
4905
    }
 
4906
}
 
4907
 
 
4908
/**
 
4909
 * xmlFAParseCharRef:
 
4910
 * @ctxt:  a regexp parser context
 
4911
 *
 
4912
 * [19]   XmlCharRef   ::=   ( '&#' [0-9]+ ';' ) | (' &#x' [0-9a-fA-F]+ ';' )
 
4913
 */
 
4914
static int
 
4915
xmlFAParseCharRef(xmlRegParserCtxtPtr ctxt) {
 
4916
    int ret = 0, cur;
 
4917
 
 
4918
    if ((CUR != '&') || (NXT(1) != '#'))
 
4919
        return(-1);
 
4920
    NEXT;
 
4921
    NEXT;
 
4922
    cur = CUR;
 
4923
    if (cur == 'x') {
 
4924
        NEXT;
 
4925
        cur = CUR;
 
4926
        if (((cur >= '0') && (cur <= '9')) ||
 
4927
            ((cur >= 'a') && (cur <= 'f')) ||
 
4928
            ((cur >= 'A') && (cur <= 'F'))) {
 
4929
            while (((cur >= '0') && (cur <= '9')) ||
 
4930
                   ((cur >= 'a') && (cur <= 'f')) ||
 
4931
                   ((cur >= 'A') && (cur <= 'F'))) {
 
4932
                if ((cur >= '0') && (cur <= '9'))
 
4933
                    ret = ret * 16 + cur - '0';
 
4934
                else if ((cur >= 'a') && (cur <= 'f'))
 
4935
                    ret = ret * 16 + 10 + (cur - 'a');
 
4936
                else
 
4937
                    ret = ret * 16 + 10 + (cur - 'A');
 
4938
                NEXT;
 
4939
                cur = CUR;
 
4940
            }
 
4941
        } else {
 
4942
            ERROR("Char ref: expecting [0-9A-F]");
 
4943
            return(-1);
 
4944
        }
 
4945
    } else {
 
4946
        if ((cur >= '0') && (cur <= '9')) {
 
4947
            while ((cur >= '0') && (cur <= '9')) {
 
4948
                ret = ret * 10 + cur - '0';
 
4949
                NEXT;
 
4950
                cur = CUR;
 
4951
            }
 
4952
        } else {
 
4953
            ERROR("Char ref: expecting [0-9]");
 
4954
            return(-1);
 
4955
        }
 
4956
    }
 
4957
    if (cur != ';') {
 
4958
        ERROR("Char ref: expecting ';'");
 
4959
        return(-1);
 
4960
    } else {
 
4961
        NEXT;
 
4962
    }
 
4963
    return(ret);
 
4964
}
 
4965
 
 
4966
/**
 
4967
 * xmlFAParseCharRange:
 
4968
 * @ctxt:  a regexp parser context
 
4969
 *
 
4970
 * [17]   charRange   ::=     seRange | XmlCharRef | XmlCharIncDash 
 
4971
 * [18]   seRange   ::=   charOrEsc '-' charOrEsc
 
4972
 * [20]   charOrEsc   ::=   XmlChar | SingleCharEsc
 
4973
 * [21]   XmlChar   ::=   [^\#x2D#x5B#x5D]
 
4974
 * [22]   XmlCharIncDash   ::=   [^\#x5B#x5D]
 
4975
 */
 
4976
static void
 
4977
xmlFAParseCharRange(xmlRegParserCtxtPtr ctxt) {
 
4978
    int cur, len;
 
4979
    int start = -1;
 
4980
    int end = -1;
 
4981
 
 
4982
    if (CUR == '\0') {
 
4983
        ERROR("Expecting ']'");
 
4984
        return;
 
4985
    }
 
4986
 
 
4987
    if ((CUR == '&') && (NXT(1) == '#')) {
 
4988
        end = start = xmlFAParseCharRef(ctxt);
 
4989
        xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
 
4990
                           XML_REGEXP_CHARVAL, start, end, NULL);
 
4991
        return;
 
4992
    }
 
4993
    cur = CUR;
 
4994
    if (cur == '\\') {
 
4995
        NEXT;
 
4996
        cur = CUR;
 
4997
        switch (cur) {
 
4998
            case 'n': start = 0xA; break;
 
4999
            case 'r': start = 0xD; break;
 
5000
            case 't': start = 0x9; break;
 
5001
            case '\\': case '|': case '.': case '-': case '^': case '?':
 
5002
            case '*': case '+': case '{': case '}': case '(': case ')':
 
5003
            case '[': case ']':
 
5004
                start = cur; break;
 
5005
            default:
 
5006
                ERROR("Invalid escape value");
 
5007
                return;
 
5008
        }
 
5009
        end = start;
 
5010
        len = 1;
 
5011
    } else if ((cur != 0x5B) && (cur != 0x5D)) {
 
5012
        end = start = CUR_SCHAR(ctxt->cur, len);
 
5013
    } else {
 
5014
        ERROR("Expecting a char range");
 
5015
        return;
 
5016
    }
 
5017
    /*
 
5018
     * Since we are "inside" a range, we can assume ctxt->cur is past
 
5019
     * the start of ctxt->string, and PREV should be safe
 
5020
     */
 
5021
    if ((start == '-') && (NXT(1) != ']') && (PREV != '[') && (PREV != '^')) {
 
5022
        NEXTL(len);
 
5023
        return;
 
5024
    }
 
5025
    NEXTL(len);
 
5026
    cur = CUR;
 
5027
    if ((cur != '-') || (NXT(1) == ']')) {
 
5028
        xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
 
5029
                              XML_REGEXP_CHARVAL, start, end, NULL);
 
5030
        return;
 
5031
    }
 
5032
    NEXT;
 
5033
    cur = CUR;
 
5034
    if (cur == '\\') {
 
5035
        NEXT;
 
5036
        cur = CUR;
 
5037
        switch (cur) {
 
5038
            case 'n': end = 0xA; break;
 
5039
            case 'r': end = 0xD; break;
 
5040
            case 't': end = 0x9; break;
 
5041
            case '\\': case '|': case '.': case '-': case '^': case '?':
 
5042
            case '*': case '+': case '{': case '}': case '(': case ')':
 
5043
            case '[': case ']':
 
5044
                end = cur; break;
 
5045
            default:
 
5046
                ERROR("Invalid escape value");
 
5047
                return;
 
5048
        }
 
5049
        len = 1;
 
5050
    } else if ((cur != 0x5B) && (cur != 0x5D)) {
 
5051
        end = CUR_SCHAR(ctxt->cur, len);
 
5052
    } else {
 
5053
        ERROR("Expecting the end of a char range");
 
5054
        return;
 
5055
    }
 
5056
    NEXTL(len);
 
5057
    /* TODO check that the values are acceptable character ranges for XML */
 
5058
    if (end < start) {
 
5059
        ERROR("End of range is before start of range");
 
5060
    } else {
 
5061
        xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg,
 
5062
                           XML_REGEXP_CHARVAL, start, end, NULL);
 
5063
    }
 
5064
    return;
 
5065
}
 
5066
 
 
5067
/**
 
5068
 * xmlFAParsePosCharGroup:
 
5069
 * @ctxt:  a regexp parser context
 
5070
 *
 
5071
 * [14]   posCharGroup ::= ( charRange | charClassEsc  )+
 
5072
 */
 
5073
static void
 
5074
xmlFAParsePosCharGroup(xmlRegParserCtxtPtr ctxt) {
 
5075
    do {
 
5076
        if (CUR == '\\') {
 
5077
            xmlFAParseCharClassEsc(ctxt);
 
5078
        } else {
 
5079
            xmlFAParseCharRange(ctxt);
 
5080
        }
 
5081
    } while ((CUR != ']') && (CUR != '^') && (CUR != '-') &&
 
5082
             (CUR != 0) && (ctxt->error == 0));
 
5083
}
 
5084
 
 
5085
/**
 
5086
 * xmlFAParseCharGroup:
 
5087
 * @ctxt:  a regexp parser context
 
5088
 *
 
5089
 * [13]   charGroup    ::= posCharGroup | negCharGroup | charClassSub
 
5090
 * [15]   negCharGroup ::= '^' posCharGroup
 
5091
 * [16]   charClassSub ::= ( posCharGroup | negCharGroup ) '-' charClassExpr  
 
5092
 * [12]   charClassExpr ::= '[' charGroup ']'
 
5093
 */
 
5094
static void
 
5095
xmlFAParseCharGroup(xmlRegParserCtxtPtr ctxt) {
 
5096
    int n = ctxt->neg;
 
5097
    while ((CUR != ']') && (ctxt->error == 0)) {
 
5098
        if (CUR == '^') {
 
5099
            int neg = ctxt->neg;
 
5100
 
 
5101
            NEXT;
 
5102
            ctxt->neg = !ctxt->neg;
 
5103
            xmlFAParsePosCharGroup(ctxt);
 
5104
            ctxt->neg = neg;
 
5105
        } else if ((CUR == '-') && (NXT(1) == '[')) {
 
5106
            int neg = ctxt->neg;
 
5107
            ctxt->neg = 2;
 
5108
            NEXT;       /* eat the '-' */
 
5109
            NEXT;       /* eat the '[' */
 
5110
            xmlFAParseCharGroup(ctxt);
 
5111
            if (CUR == ']') {
 
5112
                NEXT;
 
5113
            } else {
 
5114
                ERROR("charClassExpr: ']' expected");
 
5115
                break;
 
5116
            }
 
5117
            ctxt->neg = neg;
 
5118
            break;
 
5119
        } else if (CUR != ']') {
 
5120
            xmlFAParsePosCharGroup(ctxt);
 
5121
        }
 
5122
    }
 
5123
    ctxt->neg = n;
 
5124
}
 
5125
 
 
5126
/**
 
5127
 * xmlFAParseCharClass:
 
5128
 * @ctxt:  a regexp parser context
 
5129
 *
 
5130
 * [11]   charClass   ::=     charClassEsc | charClassExpr
 
5131
 * [12]   charClassExpr   ::=   '[' charGroup ']'
 
5132
 */
 
5133
static void
 
5134
xmlFAParseCharClass(xmlRegParserCtxtPtr ctxt) {
 
5135
    if (CUR == '[') {
 
5136
        NEXT;
 
5137
        ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_RANGES);
 
5138
        if (ctxt->atom == NULL)
 
5139
            return;
 
5140
        xmlFAParseCharGroup(ctxt);
 
5141
        if (CUR == ']') {
 
5142
            NEXT;
 
5143
        } else {
 
5144
            ERROR("xmlFAParseCharClass: ']' expected");
 
5145
        }
 
5146
    } else {
 
5147
        xmlFAParseCharClassEsc(ctxt);
 
5148
    }
 
5149
}
 
5150
 
 
5151
/**
 
5152
 * xmlFAParseQuantExact:
 
5153
 * @ctxt:  a regexp parser context
 
5154
 *
 
5155
 * [8]   QuantExact   ::=   [0-9]+
 
5156
 *
 
5157
 * Returns 0 if success or -1 in case of error
 
5158
 */
 
5159
static int
 
5160
xmlFAParseQuantExact(xmlRegParserCtxtPtr ctxt) {
 
5161
    int ret = 0;
 
5162
    int ok = 0;
 
5163
 
 
5164
    while ((CUR >= '0') && (CUR <= '9')) {
 
5165
        ret = ret * 10 + (CUR - '0');
 
5166
        ok = 1;
 
5167
        NEXT;
 
5168
    }
 
5169
    if (ok != 1) {
 
5170
        return(-1);
 
5171
    }
 
5172
    return(ret);
 
5173
}
 
5174
 
 
5175
/**
 
5176
 * xmlFAParseQuantifier:
 
5177
 * @ctxt:  a regexp parser context
 
5178
 *
 
5179
 * [4]   quantifier   ::=   [?*+] | ( '{' quantity '}' )
 
5180
 * [5]   quantity   ::=   quantRange | quantMin | QuantExact
 
5181
 * [6]   quantRange   ::=   QuantExact ',' QuantExact
 
5182
 * [7]   quantMin   ::=   QuantExact ','
 
5183
 * [8]   QuantExact   ::=   [0-9]+
 
5184
 */
 
5185
static int
 
5186
xmlFAParseQuantifier(xmlRegParserCtxtPtr ctxt) {
 
5187
    int cur;
 
5188
 
 
5189
    cur = CUR;
 
5190
    if ((cur == '?') || (cur == '*') || (cur == '+')) {
 
5191
        if (ctxt->atom != NULL) {
 
5192
            if (cur == '?')
 
5193
                ctxt->atom->quant = XML_REGEXP_QUANT_OPT;
 
5194
            else if (cur == '*')
 
5195
                ctxt->atom->quant = XML_REGEXP_QUANT_MULT;
 
5196
            else if (cur == '+')
 
5197
                ctxt->atom->quant = XML_REGEXP_QUANT_PLUS;
 
5198
        }
 
5199
        NEXT;
 
5200
        return(1);
 
5201
    }
 
5202
    if (cur == '{') {
 
5203
        int min = 0, max = 0;
 
5204
 
 
5205
        NEXT;
 
5206
        cur = xmlFAParseQuantExact(ctxt);
 
5207
        if (cur >= 0)
 
5208
            min = cur;
 
5209
        if (CUR == ',') {
 
5210
            NEXT;
 
5211
            if (CUR == '}')
 
5212
                max = INT_MAX;
 
5213
            else {
 
5214
                cur = xmlFAParseQuantExact(ctxt);
 
5215
                if (cur >= 0)
 
5216
                    max = cur;
 
5217
                else {
 
5218
                    ERROR("Improper quantifier");
 
5219
                }
 
5220
            }
 
5221
        }
 
5222
        if (CUR == '}') {
 
5223
            NEXT;
 
5224
        } else {
 
5225
            ERROR("Unterminated quantifier");
 
5226
        }
 
5227
        if (max == 0)
 
5228
            max = min;
 
5229
        if (ctxt->atom != NULL) {
 
5230
            ctxt->atom->quant = XML_REGEXP_QUANT_RANGE;
 
5231
            ctxt->atom->min = min;
 
5232
            ctxt->atom->max = max;
 
5233
        }
 
5234
        return(1);
 
5235
    }
 
5236
    return(0);
 
5237
}
 
5238
 
 
5239
/**
 
5240
 * xmlFAParseAtom:
 
5241
 * @ctxt:  a regexp parser context
 
5242
 *
 
5243
 * [9]   atom   ::=   Char | charClass | ( '(' regExp ')' )
 
5244
 */
 
5245
static int
 
5246
xmlFAParseAtom(xmlRegParserCtxtPtr ctxt) {
 
5247
    int codepoint, len;
 
5248
 
 
5249
    codepoint = xmlFAIsChar(ctxt);
 
5250
    if (codepoint > 0) {
 
5251
        ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL);
 
5252
        if (ctxt->atom == NULL)
 
5253
            return(-1);
 
5254
        codepoint = CUR_SCHAR(ctxt->cur, len);
 
5255
        ctxt->atom->codepoint = codepoint;
 
5256
        NEXTL(len);
 
5257
        return(1);
 
5258
    } else if (CUR == '|') {
 
5259
        return(0);
 
5260
    } else if (CUR == 0) {
 
5261
        return(0);
 
5262
    } else if (CUR == ')') {
 
5263
        return(0);
 
5264
    } else if (CUR == '(') {
 
5265
        xmlRegStatePtr start, oldend, start0;
 
5266
 
 
5267
        NEXT;
 
5268
        /*
 
5269
         * this extra Epsilon transition is needed if we count with 0 allowed
 
5270
         * unfortunately this can't be known at that point
 
5271
         */
 
5272
        xmlFAGenerateEpsilonTransition(ctxt, ctxt->state, NULL);
 
5273
        start0 = ctxt->state;
 
5274
        xmlFAGenerateEpsilonTransition(ctxt, ctxt->state, NULL);
 
5275
        start = ctxt->state;
 
5276
        oldend = ctxt->end;
 
5277
        ctxt->end = NULL;
 
5278
        ctxt->atom = NULL;
 
5279
        xmlFAParseRegExp(ctxt, 0);
 
5280
        if (CUR == ')') {
 
5281
            NEXT;
 
5282
        } else {
 
5283
            ERROR("xmlFAParseAtom: expecting ')'");
 
5284
        }
 
5285
        ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_SUBREG);
 
5286
        if (ctxt->atom == NULL)
 
5287
            return(-1);
 
5288
        ctxt->atom->start = start;
 
5289
        ctxt->atom->start0 = start0;
 
5290
        ctxt->atom->stop = ctxt->state;
 
5291
        ctxt->end = oldend;
 
5292
        return(1);
 
5293
    } else if ((CUR == '[') || (CUR == '\\') || (CUR == '.')) {
 
5294
        xmlFAParseCharClass(ctxt);
 
5295
        return(1);
 
5296
    }
 
5297
    return(0);
 
5298
}
 
5299
 
 
5300
/**
 
5301
 * xmlFAParsePiece:
 
5302
 * @ctxt:  a regexp parser context
 
5303
 *
 
5304
 * [3]   piece   ::=   atom quantifier?
 
5305
 */
 
5306
static int
 
5307
xmlFAParsePiece(xmlRegParserCtxtPtr ctxt) {
 
5308
    int ret;
 
5309
 
 
5310
    ctxt->atom = NULL;
 
5311
    ret = xmlFAParseAtom(ctxt);
 
5312
    if (ret == 0)
 
5313
        return(0);
 
5314
    if (ctxt->atom == NULL) {
 
5315
        ERROR("internal: no atom generated");
 
5316
    }
 
5317
    xmlFAParseQuantifier(ctxt);
 
5318
    return(1);
 
5319
}
 
5320
 
 
5321
/**
 
5322
 * xmlFAParseBranch:
 
5323
 * @ctxt:  a regexp parser context
 
5324
 * @to: optional target to the end of the branch
 
5325
 *
 
5326
 * @to is used to optimize by removing duplicate path in automata
 
5327
 * in expressions like (a|b)(c|d)
 
5328
 *
 
5329
 * [2]   branch   ::=   piece*
 
5330
 */
 
5331
static int
 
5332
xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr to) {
 
5333
    xmlRegStatePtr previous;
 
5334
    int ret;
 
5335
 
 
5336
    previous = ctxt->state;
 
5337
    ret = xmlFAParsePiece(ctxt);
 
5338
    if (ret != 0) {
 
5339
        if (xmlFAGenerateTransitions(ctxt, previous, 
 
5340
                (CUR=='|' || CUR==')') ? to : NULL, ctxt->atom) < 0)
 
5341
            return(-1);
 
5342
        previous = ctxt->state;
 
5343
        ctxt->atom = NULL;
 
5344
    }
 
5345
    while ((ret != 0) && (ctxt->error == 0)) {
 
5346
        ret = xmlFAParsePiece(ctxt);
 
5347
        if (ret != 0) {
 
5348
            if (xmlFAGenerateTransitions(ctxt, previous, 
 
5349
                    (CUR=='|' || CUR==')') ? to : NULL, ctxt->atom) < 0)
 
5350
                    return(-1);
 
5351
            previous = ctxt->state;
 
5352
            ctxt->atom = NULL;
 
5353
        }
 
5354
    }
 
5355
    return(0);
 
5356
}
 
5357
 
 
5358
/**
 
5359
 * xmlFAParseRegExp:
 
5360
 * @ctxt:  a regexp parser context
 
5361
 * @top:  is this the top-level expression ?
 
5362
 *
 
5363
 * [1]   regExp   ::=     branch  ( '|' branch )*
 
5364
 */
 
5365
static void
 
5366
xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top) {
 
5367
    xmlRegStatePtr start, end;
 
5368
 
 
5369
    /* if not top start should have been generated by an epsilon trans */
 
5370
    start = ctxt->state;
 
5371
    ctxt->end = NULL;
 
5372
    xmlFAParseBranch(ctxt, NULL);
 
5373
    if (top) {
 
5374
#ifdef DEBUG_REGEXP_GRAPH
 
5375
        printf("State %d is final\n", ctxt->state->no);
 
5376
#endif
 
5377
        ctxt->state->type = XML_REGEXP_FINAL_STATE;
 
5378
    }
 
5379
    if (CUR != '|') {
 
5380
        ctxt->end = ctxt->state;
 
5381
        return;
 
5382
    }
 
5383
    end = ctxt->state;
 
5384
    while ((CUR == '|') && (ctxt->error == 0)) {
 
5385
        NEXT;
 
5386
        ctxt->state = start;
 
5387
        ctxt->end = NULL;
 
5388
        xmlFAParseBranch(ctxt, end);
 
5389
    }
 
5390
    if (!top) {
 
5391
        ctxt->state = end;
 
5392
        ctxt->end = end;
 
5393
    }
 
5394
}
 
5395
 
 
5396
/************************************************************************
 
5397
 *                                                                      *
 
5398
 *                      The basic API                                   *
 
5399
 *                                                                      *
 
5400
 ************************************************************************/
 
5401
 
 
5402
/**
 
5403
 * xmlRegexpPrint:
 
5404
 * @output: the file for the output debug
 
5405
 * @regexp: the compiled regexp
 
5406
 *
 
5407
 * Print the content of the compiled regular expression
 
5408
 */
 
5409
void
 
5410
xmlRegexpPrint(FILE *output, xmlRegexpPtr regexp) {
 
5411
    int i;
 
5412
 
 
5413
    if (output == NULL)
 
5414
        return;
 
5415
    fprintf(output, " regexp: ");
 
5416
    if (regexp == NULL) {
 
5417
        fprintf(output, "NULL\n");
 
5418
        return;
 
5419
    }
 
5420
    fprintf(output, "'%s' ", regexp->string);
 
5421
    fprintf(output, "\n");
 
5422
    fprintf(output, "%d atoms:\n", regexp->nbAtoms);
 
5423
    for (i = 0;i < regexp->nbAtoms; i++) {
 
5424
        fprintf(output, " %02d ", i);
 
5425
        xmlRegPrintAtom(output, regexp->atoms[i]);
 
5426
    }
 
5427
    fprintf(output, "%d states:", regexp->nbStates);
 
5428
    fprintf(output, "\n");
 
5429
    for (i = 0;i < regexp->nbStates; i++) {
 
5430
        xmlRegPrintState(output, regexp->states[i]);
 
5431
    }
 
5432
    fprintf(output, "%d counters:\n", regexp->nbCounters);
 
5433
    for (i = 0;i < regexp->nbCounters; i++) {
 
5434
        fprintf(output, " %d: min %d max %d\n", i, regexp->counters[i].min,
 
5435
                                                regexp->counters[i].max);
 
5436
    }
 
5437
}
 
5438
 
 
5439
/**
 
5440
 * xmlRegexpCompile:
 
5441
 * @regexp:  a regular expression string
 
5442
 *
 
5443
 * Parses a regular expression conforming to XML Schemas Part 2 Datatype
 
5444
 * Appendix F and builds an automata suitable for testing strings against
 
5445
 * that regular expression
 
5446
 *
 
5447
 * Returns the compiled expression or NULL in case of error
 
5448
 */
 
5449
xmlRegexpPtr
 
5450
xmlRegexpCompile(const xmlChar *regexp) {
 
5451
    xmlRegexpPtr ret;
 
5452
    xmlRegParserCtxtPtr ctxt;
 
5453
 
 
5454
    ctxt = xmlRegNewParserCtxt(regexp);
 
5455
    if (ctxt == NULL)
 
5456
        return(NULL);
 
5457
 
 
5458
    /* initialize the parser */
 
5459
    ctxt->end = NULL;
 
5460
    ctxt->start = ctxt->state = xmlRegNewState(ctxt);
 
5461
    xmlRegStatePush(ctxt, ctxt->start);
 
5462
 
 
5463
    /* parse the expression building an automata */
 
5464
    xmlFAParseRegExp(ctxt, 1);
 
5465
    if (CUR != 0) {
 
5466
        ERROR("xmlFAParseRegExp: extra characters");
 
5467
    }
 
5468
    if (ctxt->error != 0) {
 
5469
        xmlRegFreeParserCtxt(ctxt);
 
5470
        return(NULL);
 
5471
    }
 
5472
    ctxt->end = ctxt->state;
 
5473
    ctxt->start->type = XML_REGEXP_START_STATE;
 
5474
    ctxt->end->type = XML_REGEXP_FINAL_STATE;
 
5475
 
 
5476
    /* remove the Epsilon except for counted transitions */
 
5477
    xmlFAEliminateEpsilonTransitions(ctxt);
 
5478
 
 
5479
 
 
5480
    if (ctxt->error != 0) {
 
5481
        xmlRegFreeParserCtxt(ctxt);
 
5482
        return(NULL);
 
5483
    }
 
5484
    ret = xmlRegEpxFromParse(ctxt);
 
5485
    xmlRegFreeParserCtxt(ctxt);
 
5486
    return(ret);
 
5487
}
 
5488
 
 
5489
/**
 
5490
 * xmlRegexpExec:
 
5491
 * @comp:  the compiled regular expression
 
5492
 * @content:  the value to check against the regular expression
 
5493
 *
 
5494
 * Check if the regular expression generates the value
 
5495
 *
 
5496
 * Returns 1 if it matches, 0 if not and a negative value in case of error
 
5497
 */
 
5498
int
 
5499
xmlRegexpExec(xmlRegexpPtr comp, const xmlChar *content) {
 
5500
    if ((comp == NULL) || (content == NULL))
 
5501
        return(-1);
 
5502
    return(xmlFARegExec(comp, content));
 
5503
}
 
5504
 
 
5505
/**
 
5506
 * xmlRegexpIsDeterminist:
 
5507
 * @comp:  the compiled regular expression
 
5508
 *
 
5509
 * Check if the regular expression is determinist
 
5510
 *
 
5511
 * Returns 1 if it yes, 0 if not and a negative value in case of error
 
5512
 */
 
5513
int
 
5514
xmlRegexpIsDeterminist(xmlRegexpPtr comp) {
 
5515
    xmlAutomataPtr am;
 
5516
    int ret;
 
5517
 
 
5518
    if (comp == NULL)
 
5519
        return(-1);
 
5520
    if (comp->determinist != -1)
 
5521
        return(comp->determinist);
 
5522
 
 
5523
    am = xmlNewAutomata();
 
5524
    if (am->states != NULL) {
 
5525
        int i;
 
5526
 
 
5527
        for (i = 0;i < am->nbStates;i++)
 
5528
            xmlRegFreeState(am->states[i]);
 
5529
        xmlFree(am->states);
 
5530
    }
 
5531
    am->nbAtoms = comp->nbAtoms;
 
5532
    am->atoms = comp->atoms;
 
5533
    am->nbStates = comp->nbStates;
 
5534
    am->states = comp->states;
 
5535
    am->determinist = -1;
 
5536
    ret = xmlFAComputesDeterminism(am);
 
5537
    am->atoms = NULL;
 
5538
    am->states = NULL;
 
5539
    xmlFreeAutomata(am);
 
5540
    return(ret);
 
5541
}
 
5542
 
 
5543
/**
 
5544
 * xmlRegFreeRegexp:
 
5545
 * @regexp:  the regexp
 
5546
 *
 
5547
 * Free a regexp
 
5548
 */
 
5549
void
 
5550
xmlRegFreeRegexp(xmlRegexpPtr regexp) {
 
5551
    int i;
 
5552
    if (regexp == NULL)
 
5553
        return;
 
5554
 
 
5555
    if (regexp->string != NULL)
 
5556
        xmlFree(regexp->string);
 
5557
    if (regexp->states != NULL) {
 
5558
        for (i = 0;i < regexp->nbStates;i++)
 
5559
            xmlRegFreeState(regexp->states[i]);
 
5560
        xmlFree(regexp->states);
 
5561
    }
 
5562
    if (regexp->atoms != NULL) {
 
5563
        for (i = 0;i < regexp->nbAtoms;i++)
 
5564
            xmlRegFreeAtom(regexp->atoms[i]);
 
5565
        xmlFree(regexp->atoms);
 
5566
    }
 
5567
    if (regexp->counters != NULL)
 
5568
        xmlFree(regexp->counters);
 
5569
    if (regexp->compact != NULL)
 
5570
        xmlFree(regexp->compact);
 
5571
    if (regexp->transdata != NULL)
 
5572
        xmlFree(regexp->transdata);
 
5573
    if (regexp->stringMap != NULL) {
 
5574
        for (i = 0; i < regexp->nbstrings;i++)
 
5575
            xmlFree(regexp->stringMap[i]);
 
5576
        xmlFree(regexp->stringMap);
 
5577
    }
 
5578
 
 
5579
    xmlFree(regexp);
 
5580
}
 
5581
 
 
5582
#ifdef LIBXML_AUTOMATA_ENABLED
 
5583
/************************************************************************
 
5584
 *                                                                      *
 
5585
 *                      The Automata interface                          *
 
5586
 *                                                                      *
 
5587
 ************************************************************************/
 
5588
 
 
5589
/**
 
5590
 * xmlNewAutomata:
 
5591
 *
 
5592
 * Create a new automata
 
5593
 *
 
5594
 * Returns the new object or NULL in case of failure
 
5595
 */
 
5596
xmlAutomataPtr
 
5597
xmlNewAutomata(void) {
 
5598
    xmlAutomataPtr ctxt;
 
5599
 
 
5600
    ctxt = xmlRegNewParserCtxt(NULL);
 
5601
    if (ctxt == NULL)
 
5602
        return(NULL);
 
5603
 
 
5604
    /* initialize the parser */
 
5605
    ctxt->end = NULL;
 
5606
    ctxt->start = ctxt->state = xmlRegNewState(ctxt);
 
5607
    if (ctxt->start == NULL) {
 
5608
        xmlFreeAutomata(ctxt);
 
5609
        return(NULL);
 
5610
    }
 
5611
    ctxt->start->type = XML_REGEXP_START_STATE;
 
5612
    if (xmlRegStatePush(ctxt, ctxt->start) < 0) {
 
5613
        xmlRegFreeState(ctxt->start);
 
5614
        xmlFreeAutomata(ctxt);
 
5615
        return(NULL);
 
5616
    }
 
5617
 
 
5618
    return(ctxt);
 
5619
}
 
5620
 
 
5621
/**
 
5622
 * xmlFreeAutomata:
 
5623
 * @am: an automata
 
5624
 *
 
5625
 * Free an automata
 
5626
 */
 
5627
void
 
5628
xmlFreeAutomata(xmlAutomataPtr am) {
 
5629
    if (am == NULL)
 
5630
        return;
 
5631
    xmlRegFreeParserCtxt(am);
 
5632
}
 
5633
 
 
5634
/**
 
5635
 * xmlAutomataGetInitState:
 
5636
 * @am: an automata
 
5637
 *
 
5638
 * Initial state lookup
 
5639
 *
 
5640
 * Returns the initial state of the automata
 
5641
 */
 
5642
xmlAutomataStatePtr
 
5643
xmlAutomataGetInitState(xmlAutomataPtr am) {
 
5644
    if (am == NULL)
 
5645
        return(NULL);
 
5646
    return(am->start);
 
5647
}
 
5648
 
 
5649
/**
 
5650
 * xmlAutomataSetFinalState:
 
5651
 * @am: an automata
 
5652
 * @state: a state in this automata
 
5653
 *
 
5654
 * Makes that state a final state
 
5655
 *
 
5656
 * Returns 0 or -1 in case of error
 
5657
 */
 
5658
int
 
5659
xmlAutomataSetFinalState(xmlAutomataPtr am, xmlAutomataStatePtr state) {
 
5660
    if ((am == NULL) || (state == NULL))
 
5661
        return(-1);
 
5662
    state->type = XML_REGEXP_FINAL_STATE;
 
5663
    return(0);
 
5664
}
 
5665
 
 
5666
/**
 
5667
 * xmlAutomataNewTransition:
 
5668
 * @am: an automata
 
5669
 * @from: the starting point of the transition
 
5670
 * @to: the target point of the transition or NULL
 
5671
 * @token: the input string associated to that transition
 
5672
 * @data: data passed to the callback function if the transition is activated
 
5673
 *
 
5674
 * If @to is NULL, this creates first a new target state in the automata
 
5675
 * and then adds a transition from the @from state to the target state
 
5676
 * activated by the value of @token
 
5677
 *
 
5678
 * Returns the target state or NULL in case of error
 
5679
 */
 
5680
xmlAutomataStatePtr
 
5681
xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
5682
                         xmlAutomataStatePtr to, const xmlChar *token,
 
5683
                         void *data) {
 
5684
    xmlRegAtomPtr atom;
 
5685
 
 
5686
    if ((am == NULL) || (from == NULL) || (token == NULL))
 
5687
        return(NULL);
 
5688
    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
 
5689
    if (atom == NULL)
 
5690
        return(NULL);
 
5691
    atom->data = data;
 
5692
    if (atom == NULL)
 
5693
        return(NULL);
 
5694
    atom->valuep = xmlStrdup(token);
 
5695
 
 
5696
    if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
 
5697
        xmlRegFreeAtom(atom);
 
5698
        return(NULL);
 
5699
    }
 
5700
    if (to == NULL)
 
5701
        return(am->state);
 
5702
    return(to);
 
5703
}
 
5704
 
 
5705
/**
 
5706
 * xmlAutomataNewTransition2:
 
5707
 * @am: an automata
 
5708
 * @from: the starting point of the transition
 
5709
 * @to: the target point of the transition or NULL
 
5710
 * @token: the first input string associated to that transition
 
5711
 * @token2: the second input string associated to that transition
 
5712
 * @data: data passed to the callback function if the transition is activated
 
5713
 *
 
5714
 * If @to is NULL, this creates first a new target state in the automata
 
5715
 * and then adds a transition from the @from state to the target state
 
5716
 * activated by the value of @token
 
5717
 *
 
5718
 * Returns the target state or NULL in case of error
 
5719
 */
 
5720
xmlAutomataStatePtr
 
5721
xmlAutomataNewTransition2(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
5722
                          xmlAutomataStatePtr to, const xmlChar *token,
 
5723
                          const xmlChar *token2, void *data) {
 
5724
    xmlRegAtomPtr atom;
 
5725
 
 
5726
    if ((am == NULL) || (from == NULL) || (token == NULL))
 
5727
        return(NULL);
 
5728
    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
 
5729
    if (atom == NULL)
 
5730
        return(NULL);
 
5731
    atom->data = data;
 
5732
    if ((token2 == NULL) || (*token2 == 0)) {
 
5733
        atom->valuep = xmlStrdup(token);
 
5734
    } else {
 
5735
        int lenn, lenp;
 
5736
        xmlChar *str;
 
5737
 
 
5738
        lenn = strlen((char *) token2);
 
5739
        lenp = strlen((char *) token);
 
5740
 
 
5741
        str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
 
5742
        if (str == NULL) {
 
5743
            xmlRegFreeAtom(atom);
 
5744
            return(NULL);
 
5745
        }
 
5746
        memcpy(&str[0], token, lenp);
 
5747
        str[lenp] = '|';
 
5748
        memcpy(&str[lenp + 1], token2, lenn);
 
5749
        str[lenn + lenp + 1] = 0;
 
5750
 
 
5751
        atom->valuep = str;
 
5752
    }
 
5753
 
 
5754
    if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
 
5755
        xmlRegFreeAtom(atom);
 
5756
        return(NULL);
 
5757
    }
 
5758
    if (to == NULL)
 
5759
        return(am->state);
 
5760
    return(to);
 
5761
}
 
5762
 
 
5763
/**
 
5764
 * xmlAutomataNewNegTrans:
 
5765
 * @am: an automata
 
5766
 * @from: the starting point of the transition
 
5767
 * @to: the target point of the transition or NULL
 
5768
 * @token: the first input string associated to that transition
 
5769
 * @token2: the second input string associated to that transition
 
5770
 * @data: data passed to the callback function if the transition is activated
 
5771
 *
 
5772
 * If @to is NULL, this creates first a new target state in the automata
 
5773
 * and then adds a transition from the @from state to the target state
 
5774
 * activated by any value except (@token,@token2)
 
5775
 * Note that if @token2 is not NULL, then (X, NULL) won't match to follow
 
5776
 # the semantic of XSD ##other
 
5777
 *
 
5778
 * Returns the target state or NULL in case of error
 
5779
 */
 
5780
xmlAutomataStatePtr
 
5781
xmlAutomataNewNegTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
5782
                       xmlAutomataStatePtr to, const xmlChar *token,
 
5783
                       const xmlChar *token2, void *data) {
 
5784
    xmlRegAtomPtr atom;
 
5785
    xmlChar err_msg[200];
 
5786
 
 
5787
    if ((am == NULL) || (from == NULL) || (token == NULL))
 
5788
        return(NULL);
 
5789
    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
 
5790
    if (atom == NULL)
 
5791
        return(NULL);
 
5792
    atom->data = data;
 
5793
    atom->neg = 1;
 
5794
    if ((token2 == NULL) || (*token2 == 0)) {
 
5795
        atom->valuep = xmlStrdup(token);
 
5796
    } else {
 
5797
        int lenn, lenp;
 
5798
        xmlChar *str;
 
5799
 
 
5800
        lenn = strlen((char *) token2);
 
5801
        lenp = strlen((char *) token);
 
5802
 
 
5803
        str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
 
5804
        if (str == NULL) {
 
5805
            xmlRegFreeAtom(atom);
 
5806
            return(NULL);
 
5807
        }
 
5808
        memcpy(&str[0], token, lenp);
 
5809
        str[lenp] = '|';
 
5810
        memcpy(&str[lenp + 1], token2, lenn);
 
5811
        str[lenn + lenp + 1] = 0;
 
5812
 
 
5813
        atom->valuep = str;
 
5814
    }
 
5815
    snprintf((char *) err_msg, 199, "not %s", (const char *) atom->valuep);
 
5816
    err_msg[199] = 0;
 
5817
    atom->valuep2 = xmlStrdup(err_msg);
 
5818
 
 
5819
    if (xmlFAGenerateTransitions(am, from, to, atom) < 0) {
 
5820
        xmlRegFreeAtom(atom);
 
5821
        return(NULL);
 
5822
    }
 
5823
    am->negs++;
 
5824
    if (to == NULL)
 
5825
        return(am->state);
 
5826
    return(to);
 
5827
}
 
5828
 
 
5829
/**
 
5830
 * xmlAutomataNewCountTrans2:
 
5831
 * @am: an automata
 
5832
 * @from: the starting point of the transition
 
5833
 * @to: the target point of the transition or NULL
 
5834
 * @token: the input string associated to that transition
 
5835
 * @token2: the second input string associated to that transition
 
5836
 * @min:  the minimum successive occurences of token
 
5837
 * @max:  the maximum successive occurences of token
 
5838
 * @data:  data associated to the transition
 
5839
 *
 
5840
 * If @to is NULL, this creates first a new target state in the automata
 
5841
 * and then adds a transition from the @from state to the target state
 
5842
 * activated by a succession of input of value @token and @token2 and 
 
5843
 * whose number is between @min and @max
 
5844
 *
 
5845
 * Returns the target state or NULL in case of error
 
5846
 */
 
5847
xmlAutomataStatePtr
 
5848
xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
5849
                         xmlAutomataStatePtr to, const xmlChar *token,
 
5850
                         const xmlChar *token2,
 
5851
                         int min, int max, void *data) {
 
5852
    xmlRegAtomPtr atom;
 
5853
    int counter;
 
5854
 
 
5855
    if ((am == NULL) || (from == NULL) || (token == NULL))
 
5856
        return(NULL);
 
5857
    if (min < 0)
 
5858
        return(NULL);
 
5859
    if ((max < min) || (max < 1))
 
5860
        return(NULL);
 
5861
    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
 
5862
    if (atom == NULL)
 
5863
        return(NULL);
 
5864
    if ((token2 == NULL) || (*token2 == 0)) {
 
5865
        atom->valuep = xmlStrdup(token);
 
5866
    } else {
 
5867
        int lenn, lenp;
 
5868
        xmlChar *str;
 
5869
 
 
5870
        lenn = strlen((char *) token2);
 
5871
        lenp = strlen((char *) token);
 
5872
 
 
5873
        str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
 
5874
        if (str == NULL) {
 
5875
            xmlRegFreeAtom(atom);
 
5876
            return(NULL);
 
5877
        }
 
5878
        memcpy(&str[0], token, lenp);
 
5879
        str[lenp] = '|';
 
5880
        memcpy(&str[lenp + 1], token2, lenn);
 
5881
        str[lenn + lenp + 1] = 0;
 
5882
 
 
5883
        atom->valuep = str;
 
5884
    }
 
5885
    atom->data = data;
 
5886
    if (min == 0)
 
5887
        atom->min = 1;
 
5888
    else
 
5889
        atom->min = min;
 
5890
    atom->max = max;
 
5891
 
 
5892
    /*
 
5893
     * associate a counter to the transition.
 
5894
     */
 
5895
    counter = xmlRegGetCounter(am);
 
5896
    am->counters[counter].min = min;
 
5897
    am->counters[counter].max = max;
 
5898
 
 
5899
    /* xmlFAGenerateTransitions(am, from, to, atom); */
 
5900
    if (to == NULL) {
 
5901
        to = xmlRegNewState(am);
 
5902
        xmlRegStatePush(am, to);
 
5903
    }
 
5904
    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
 
5905
    xmlRegAtomPush(am, atom);
 
5906
    am->state = to;
 
5907
 
 
5908
    if (to == NULL)
 
5909
        to = am->state;
 
5910
    if (to == NULL)
 
5911
        return(NULL);
 
5912
    if (min == 0)
 
5913
        xmlFAGenerateEpsilonTransition(am, from, to);
 
5914
    return(to);
 
5915
}
 
5916
 
 
5917
/**
 
5918
 * xmlAutomataNewCountTrans:
 
5919
 * @am: an automata
 
5920
 * @from: the starting point of the transition
 
5921
 * @to: the target point of the transition or NULL
 
5922
 * @token: the input string associated to that transition
 
5923
 * @min:  the minimum successive occurences of token
 
5924
 * @max:  the maximum successive occurences of token
 
5925
 * @data:  data associated to the transition
 
5926
 *
 
5927
 * If @to is NULL, this creates first a new target state in the automata
 
5928
 * and then adds a transition from the @from state to the target state
 
5929
 * activated by a succession of input of value @token and whose number
 
5930
 * is between @min and @max
 
5931
 *
 
5932
 * Returns the target state or NULL in case of error
 
5933
 */
 
5934
xmlAutomataStatePtr
 
5935
xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
5936
                         xmlAutomataStatePtr to, const xmlChar *token,
 
5937
                         int min, int max, void *data) {
 
5938
    xmlRegAtomPtr atom;
 
5939
    int counter;
 
5940
 
 
5941
    if ((am == NULL) || (from == NULL) || (token == NULL))
 
5942
        return(NULL);
 
5943
    if (min < 0)
 
5944
        return(NULL);
 
5945
    if ((max < min) || (max < 1))
 
5946
        return(NULL);
 
5947
    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
 
5948
    if (atom == NULL)
 
5949
        return(NULL);
 
5950
    atom->valuep = xmlStrdup(token);
 
5951
    atom->data = data;
 
5952
    if (min == 0)
 
5953
        atom->min = 1;
 
5954
    else
 
5955
        atom->min = min;
 
5956
    atom->max = max;
 
5957
 
 
5958
    /*
 
5959
     * associate a counter to the transition.
 
5960
     */
 
5961
    counter = xmlRegGetCounter(am);
 
5962
    am->counters[counter].min = min;
 
5963
    am->counters[counter].max = max;
 
5964
 
 
5965
    /* xmlFAGenerateTransitions(am, from, to, atom); */
 
5966
    if (to == NULL) {
 
5967
        to = xmlRegNewState(am);
 
5968
        xmlRegStatePush(am, to);
 
5969
    }
 
5970
    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
 
5971
    xmlRegAtomPush(am, atom);
 
5972
    am->state = to;
 
5973
 
 
5974
    if (to == NULL)
 
5975
        to = am->state;
 
5976
    if (to == NULL)
 
5977
        return(NULL);
 
5978
    if (min == 0)
 
5979
        xmlFAGenerateEpsilonTransition(am, from, to);
 
5980
    return(to);
 
5981
}
 
5982
 
 
5983
/**
 
5984
 * xmlAutomataNewOnceTrans2:
 
5985
 * @am: an automata
 
5986
 * @from: the starting point of the transition
 
5987
 * @to: the target point of the transition or NULL
 
5988
 * @token: the input string associated to that transition
 
5989
 * @token2: the second input string associated to that transition
 
5990
 * @min:  the minimum successive occurences of token
 
5991
 * @max:  the maximum successive occurences of token
 
5992
 * @data:  data associated to the transition
 
5993
 *
 
5994
 * If @to is NULL, this creates first a new target state in the automata
 
5995
 * and then adds a transition from the @from state to the target state
 
5996
 * activated by a succession of input of value @token and @token2 and whose 
 
5997
 * number is between @min and @max, moreover that transition can only be 
 
5998
 * crossed once.
 
5999
 *
 
6000
 * Returns the target state or NULL in case of error
 
6001
 */
 
6002
xmlAutomataStatePtr
 
6003
xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
6004
                         xmlAutomataStatePtr to, const xmlChar *token,
 
6005
                         const xmlChar *token2,
 
6006
                         int min, int max, void *data) {
 
6007
    xmlRegAtomPtr atom;
 
6008
    int counter;
 
6009
 
 
6010
    if ((am == NULL) || (from == NULL) || (token == NULL))
 
6011
        return(NULL);
 
6012
    if (min < 1)
 
6013
        return(NULL);
 
6014
    if ((max < min) || (max < 1))
 
6015
        return(NULL);
 
6016
    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
 
6017
    if (atom == NULL)
 
6018
        return(NULL);
 
6019
    if ((token2 == NULL) || (*token2 == 0)) {
 
6020
        atom->valuep = xmlStrdup(token);
 
6021
    } else {
 
6022
        int lenn, lenp;
 
6023
        xmlChar *str;
 
6024
 
 
6025
        lenn = strlen((char *) token2);
 
6026
        lenp = strlen((char *) token);
 
6027
 
 
6028
        str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2);
 
6029
        if (str == NULL) {
 
6030
            xmlRegFreeAtom(atom);
 
6031
            return(NULL);
 
6032
        }
 
6033
        memcpy(&str[0], token, lenp);
 
6034
        str[lenp] = '|';
 
6035
        memcpy(&str[lenp + 1], token2, lenn);
 
6036
        str[lenn + lenp + 1] = 0;
 
6037
 
 
6038
        atom->valuep = str;
 
6039
    }    
 
6040
    atom->data = data;
 
6041
    atom->quant = XML_REGEXP_QUANT_ONCEONLY;
 
6042
    atom->min = min;
 
6043
    atom->max = max;
 
6044
    /*
 
6045
     * associate a counter to the transition.
 
6046
     */
 
6047
    counter = xmlRegGetCounter(am);
 
6048
    am->counters[counter].min = 1;
 
6049
    am->counters[counter].max = 1;
 
6050
 
 
6051
    /* xmlFAGenerateTransitions(am, from, to, atom); */
 
6052
    if (to == NULL) {
 
6053
        to = xmlRegNewState(am);
 
6054
        xmlRegStatePush(am, to);
 
6055
    }
 
6056
    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
 
6057
    xmlRegAtomPush(am, atom);
 
6058
    am->state = to;
 
6059
    return(to);
 
6060
}
 
6061
 
 
6062
    
 
6063
 
 
6064
/**
 
6065
 * xmlAutomataNewOnceTrans:
 
6066
 * @am: an automata
 
6067
 * @from: the starting point of the transition
 
6068
 * @to: the target point of the transition or NULL
 
6069
 * @token: the input string associated to that transition
 
6070
 * @min:  the minimum successive occurences of token
 
6071
 * @max:  the maximum successive occurences of token
 
6072
 * @data:  data associated to the transition
 
6073
 *
 
6074
 * If @to is NULL, this creates first a new target state in the automata
 
6075
 * and then adds a transition from the @from state to the target state
 
6076
 * activated by a succession of input of value @token and whose number
 
6077
 * is between @min and @max, moreover that transition can only be crossed
 
6078
 * once.
 
6079
 *
 
6080
 * Returns the target state or NULL in case of error
 
6081
 */
 
6082
xmlAutomataStatePtr
 
6083
xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
6084
                         xmlAutomataStatePtr to, const xmlChar *token,
 
6085
                         int min, int max, void *data) {
 
6086
    xmlRegAtomPtr atom;
 
6087
    int counter;
 
6088
 
 
6089
    if ((am == NULL) || (from == NULL) || (token == NULL))
 
6090
        return(NULL);
 
6091
    if (min < 1)
 
6092
        return(NULL);
 
6093
    if ((max < min) || (max < 1))
 
6094
        return(NULL);
 
6095
    atom = xmlRegNewAtom(am, XML_REGEXP_STRING);
 
6096
    if (atom == NULL)
 
6097
        return(NULL);
 
6098
    atom->valuep = xmlStrdup(token);
 
6099
    atom->data = data;
 
6100
    atom->quant = XML_REGEXP_QUANT_ONCEONLY;
 
6101
    atom->min = min;
 
6102
    atom->max = max;
 
6103
    /*
 
6104
     * associate a counter to the transition.
 
6105
     */
 
6106
    counter = xmlRegGetCounter(am);
 
6107
    am->counters[counter].min = 1;
 
6108
    am->counters[counter].max = 1;
 
6109
 
 
6110
    /* xmlFAGenerateTransitions(am, from, to, atom); */
 
6111
    if (to == NULL) {
 
6112
        to = xmlRegNewState(am);
 
6113
        xmlRegStatePush(am, to);
 
6114
    }
 
6115
    xmlRegStateAddTrans(am, from, atom, to, counter, -1);
 
6116
    xmlRegAtomPush(am, atom);
 
6117
    am->state = to;
 
6118
    return(to);
 
6119
}
 
6120
 
 
6121
/**
 
6122
 * xmlAutomataNewState:
 
6123
 * @am: an automata
 
6124
 *
 
6125
 * Create a new disconnected state in the automata
 
6126
 *
 
6127
 * Returns the new state or NULL in case of error
 
6128
 */
 
6129
xmlAutomataStatePtr
 
6130
xmlAutomataNewState(xmlAutomataPtr am) {
 
6131
    xmlAutomataStatePtr to; 
 
6132
 
 
6133
    if (am == NULL)
 
6134
        return(NULL);
 
6135
    to = xmlRegNewState(am);
 
6136
    xmlRegStatePush(am, to);
 
6137
    return(to);
 
6138
}
 
6139
 
 
6140
/**
 
6141
 * xmlAutomataNewEpsilon:
 
6142
 * @am: an automata
 
6143
 * @from: the starting point of the transition
 
6144
 * @to: the target point of the transition or NULL
 
6145
 *
 
6146
 * If @to is NULL, this creates first a new target state in the automata
 
6147
 * and then adds an epsilon transition from the @from state to the
 
6148
 * target state
 
6149
 *
 
6150
 * Returns the target state or NULL in case of error
 
6151
 */
 
6152
xmlAutomataStatePtr
 
6153
xmlAutomataNewEpsilon(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
6154
                      xmlAutomataStatePtr to) {
 
6155
    if ((am == NULL) || (from == NULL))
 
6156
        return(NULL);
 
6157
    xmlFAGenerateEpsilonTransition(am, from, to);
 
6158
    if (to == NULL)
 
6159
        return(am->state);
 
6160
    return(to);
 
6161
}
 
6162
 
 
6163
/**
 
6164
 * xmlAutomataNewAllTrans:
 
6165
 * @am: an automata
 
6166
 * @from: the starting point of the transition
 
6167
 * @to: the target point of the transition or NULL
 
6168
 * @lax: allow to transition if not all all transitions have been activated
 
6169
 *
 
6170
 * If @to is NULL, this creates first a new target state in the automata
 
6171
 * and then adds a an ALL transition from the @from state to the
 
6172
 * target state. That transition is an epsilon transition allowed only when
 
6173
 * all transitions from the @from node have been activated.
 
6174
 *
 
6175
 * Returns the target state or NULL in case of error
 
6176
 */
 
6177
xmlAutomataStatePtr
 
6178
xmlAutomataNewAllTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
6179
                       xmlAutomataStatePtr to, int lax) {
 
6180
    if ((am == NULL) || (from == NULL))
 
6181
        return(NULL);
 
6182
    xmlFAGenerateAllTransition(am, from, to, lax);
 
6183
    if (to == NULL)
 
6184
        return(am->state);
 
6185
    return(to);
 
6186
}
 
6187
 
 
6188
/**
 
6189
 * xmlAutomataNewCounter:
 
6190
 * @am: an automata
 
6191
 * @min:  the minimal value on the counter
 
6192
 * @max:  the maximal value on the counter
 
6193
 *
 
6194
 * Create a new counter
 
6195
 *
 
6196
 * Returns the counter number or -1 in case of error
 
6197
 */
 
6198
int             
 
6199
xmlAutomataNewCounter(xmlAutomataPtr am, int min, int max) {
 
6200
    int ret;
 
6201
 
 
6202
    if (am == NULL)
 
6203
        return(-1);
 
6204
 
 
6205
    ret = xmlRegGetCounter(am);
 
6206
    if (ret < 0)
 
6207
        return(-1);
 
6208
    am->counters[ret].min = min;
 
6209
    am->counters[ret].max = max;
 
6210
    return(ret);
 
6211
}
 
6212
 
 
6213
/**
 
6214
 * xmlAutomataNewCountedTrans:
 
6215
 * @am: an automata
 
6216
 * @from: the starting point of the transition
 
6217
 * @to: the target point of the transition or NULL
 
6218
 * @counter: the counter associated to that transition
 
6219
 *
 
6220
 * If @to is NULL, this creates first a new target state in the automata
 
6221
 * and then adds an epsilon transition from the @from state to the target state
 
6222
 * which will increment the counter provided
 
6223
 *
 
6224
 * Returns the target state or NULL in case of error
 
6225
 */
 
6226
xmlAutomataStatePtr
 
6227
xmlAutomataNewCountedTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
6228
                xmlAutomataStatePtr to, int counter) {
 
6229
    if ((am == NULL) || (from == NULL) || (counter < 0))
 
6230
        return(NULL);
 
6231
    xmlFAGenerateCountedEpsilonTransition(am, from, to, counter);
 
6232
    if (to == NULL)
 
6233
        return(am->state);
 
6234
    return(to);
 
6235
}
 
6236
 
 
6237
/**
 
6238
 * xmlAutomataNewCounterTrans:
 
6239
 * @am: an automata
 
6240
 * @from: the starting point of the transition
 
6241
 * @to: the target point of the transition or NULL
 
6242
 * @counter: the counter associated to that transition
 
6243
 *
 
6244
 * If @to is NULL, this creates first a new target state in the automata
 
6245
 * and then adds an epsilon transition from the @from state to the target state
 
6246
 * which will be allowed only if the counter is within the right range.
 
6247
 *
 
6248
 * Returns the target state or NULL in case of error
 
6249
 */
 
6250
xmlAutomataStatePtr
 
6251
xmlAutomataNewCounterTrans(xmlAutomataPtr am, xmlAutomataStatePtr from,
 
6252
                xmlAutomataStatePtr to, int counter) {
 
6253
    if ((am == NULL) || (from == NULL) || (counter < 0))
 
6254
        return(NULL);
 
6255
    xmlFAGenerateCountedTransition(am, from, to, counter);
 
6256
    if (to == NULL)
 
6257
        return(am->state);
 
6258
    return(to);
 
6259
}
 
6260
 
 
6261
/**
 
6262
 * xmlAutomataCompile:
 
6263
 * @am: an automata
 
6264
 *
 
6265
 * Compile the automata into a Reg Exp ready for being executed.
 
6266
 * The automata should be free after this point.
 
6267
 *
 
6268
 * Returns the compiled regexp or NULL in case of error
 
6269
 */
 
6270
xmlRegexpPtr          
 
6271
xmlAutomataCompile(xmlAutomataPtr am) {
 
6272
    xmlRegexpPtr ret;
 
6273
 
 
6274
    if ((am == NULL) || (am->error != 0)) return(NULL);
 
6275
    xmlFAEliminateEpsilonTransitions(am);
 
6276
    /* xmlFAComputesDeterminism(am); */
 
6277
    ret = xmlRegEpxFromParse(am);
 
6278
 
 
6279
    return(ret);
 
6280
}
 
6281
 
 
6282
/**
 
6283
 * xmlAutomataIsDeterminist:
 
6284
 * @am: an automata
 
6285
 *
 
6286
 * Checks if an automata is determinist.
 
6287
 *
 
6288
 * Returns 1 if true, 0 if not, and -1 in case of error
 
6289
 */
 
6290
int          
 
6291
xmlAutomataIsDeterminist(xmlAutomataPtr am) {
 
6292
    int ret;
 
6293
 
 
6294
    if (am == NULL)
 
6295
        return(-1);
 
6296
 
 
6297
    ret = xmlFAComputesDeterminism(am);
 
6298
    return(ret);
 
6299
}
 
6300
#endif /* LIBXML_AUTOMATA_ENABLED */
 
6301
 
 
6302
#ifdef LIBXML_EXPR_ENABLED
 
6303
/************************************************************************
 
6304
 *                                                                      *
 
6305
 *              Formal Expression handling code                         *
 
6306
 *                                                                      *
 
6307
 ************************************************************************/
 
6308
/************************************************************************
 
6309
 *                                                                      *
 
6310
 *              Expression handling context                             *
 
6311
 *                                                                      *
 
6312
 ************************************************************************/
 
6313
 
 
6314
struct _xmlExpCtxt {
 
6315
    xmlDictPtr dict;
 
6316
    xmlExpNodePtr *table;
 
6317
    int size;
 
6318
    int nbElems;
 
6319
    int nb_nodes;
 
6320
    const char *expr;
 
6321
    const char *cur;
 
6322
    int nb_cons;
 
6323
    int tabSize;
 
6324
};
 
6325
 
 
6326
/**
 
6327
 * xmlExpNewCtxt:
 
6328
 * @maxNodes:  the maximum number of nodes
 
6329
 * @dict:  optional dictionnary to use internally
 
6330
 *
 
6331
 * Creates a new context for manipulating expressions
 
6332
 *
 
6333
 * Returns the context or NULL in case of error
 
6334
 */
 
6335
xmlExpCtxtPtr
 
6336
xmlExpNewCtxt(int maxNodes, xmlDictPtr dict) {
 
6337
    xmlExpCtxtPtr ret;
 
6338
    int size = 256;
 
6339
 
 
6340
    if (maxNodes <= 4096)
 
6341
        maxNodes = 4096;
 
6342
    
 
6343
    ret = (xmlExpCtxtPtr) xmlMalloc(sizeof(xmlExpCtxt));
 
6344
    if (ret == NULL)
 
6345
        return(NULL);
 
6346
    memset(ret, 0, sizeof(xmlExpCtxt));
 
6347
    ret->size = size;
 
6348
    ret->nbElems = 0;
 
6349
    ret->table = xmlMalloc(size * sizeof(xmlExpNodePtr));
 
6350
    if (ret->table == NULL) {
 
6351
        xmlFree(ret);
 
6352
        return(NULL);
 
6353
    }
 
6354
    memset(ret->table, 0, size * sizeof(xmlExpNodePtr));
 
6355
    if (dict == NULL) {
 
6356
        ret->dict = xmlDictCreate();
 
6357
        if (ret->dict == NULL) {
 
6358
            xmlFree(ret->table);
 
6359
            xmlFree(ret);
 
6360
            return(NULL);
 
6361
        }
 
6362
    } else {
 
6363
        ret->dict = dict;
 
6364
        xmlDictReference(ret->dict);
 
6365
    }
 
6366
    return(ret);
 
6367
}
 
6368
 
 
6369
/**
 
6370
 * xmlExpFreeCtxt:
 
6371
 * @ctxt:  an expression context
 
6372
 *
 
6373
 * Free an expression context
 
6374
 */
 
6375
void
 
6376
xmlExpFreeCtxt(xmlExpCtxtPtr ctxt) {
 
6377
    if (ctxt == NULL)
 
6378
        return;
 
6379
    xmlDictFree(ctxt->dict);
 
6380
    if (ctxt->table != NULL)
 
6381
        xmlFree(ctxt->table);
 
6382
    xmlFree(ctxt);
 
6383
}
 
6384
 
 
6385
/************************************************************************
 
6386
 *                                                                      *
 
6387
 *              Structure associated to an expression node              *
 
6388
 *                                                                      *
 
6389
 ************************************************************************/
 
6390
#define MAX_NODES 10000
 
6391
 
 
6392
/* #define DEBUG_DERIV */
 
6393
 
 
6394
/*
 
6395
 * TODO: 
 
6396
 * - Wildcards
 
6397
 * - public API for creation
 
6398
 *
 
6399
 * Started
 
6400
 * - regression testing
 
6401
 *
 
6402
 * Done
 
6403
 * - split into module and test tool
 
6404
 * - memleaks
 
6405
 */
 
6406
 
 
6407
typedef enum {
 
6408
    XML_EXP_NILABLE = (1 << 0)
 
6409
} xmlExpNodeInfo;
 
6410
 
 
6411
#define IS_NILLABLE(node) ((node)->info & XML_EXP_NILABLE)
 
6412
 
 
6413
struct _xmlExpNode {
 
6414
    unsigned char type;/* xmlExpNodeType */
 
6415
    unsigned char info;/* OR of xmlExpNodeInfo */
 
6416
    unsigned short key; /* the hash key */
 
6417
    unsigned int ref;   /* The number of references */
 
6418
    int c_max;          /* the maximum length it can consume */
 
6419
    xmlExpNodePtr exp_left;
 
6420
    xmlExpNodePtr next;/* the next node in the hash table or free list */
 
6421
    union {
 
6422
        struct {
 
6423
            int f_min;
 
6424
            int f_max;
 
6425
        } count;
 
6426
        struct {
 
6427
            xmlExpNodePtr f_right;
 
6428
        } children;
 
6429
        const xmlChar *f_str;
 
6430
    } field;
 
6431
};
 
6432
 
 
6433
#define exp_min field.count.f_min
 
6434
#define exp_max field.count.f_max
 
6435
/* #define exp_left field.children.f_left */
 
6436
#define exp_right field.children.f_right
 
6437
#define exp_str field.f_str
 
6438
 
 
6439
static xmlExpNodePtr xmlExpNewNode(xmlExpCtxtPtr ctxt, xmlExpNodeType type);
 
6440
static xmlExpNode forbiddenExpNode = {
 
6441
    XML_EXP_FORBID, 0, 0, 0, 0, NULL, NULL, {{ 0, 0}}
 
6442
};
 
6443
xmlExpNodePtr forbiddenExp = &forbiddenExpNode;
 
6444
static xmlExpNode emptyExpNode = {
 
6445
    XML_EXP_EMPTY, 1, 0, 0, 0, NULL, NULL, {{ 0, 0}}
 
6446
};
 
6447
xmlExpNodePtr emptyExp = &emptyExpNode;
 
6448
 
 
6449
/************************************************************************
 
6450
 *                                                                      *
 
6451
 *  The custom hash table for unicity and canonicalization              *
 
6452
 *  of sub-expressions pointers                                         *
 
6453
 *                                                                      *
 
6454
 ************************************************************************/
 
6455
/*
 
6456
 * xmlExpHashNameComputeKey:
 
6457
 * Calculate the hash key for a token
 
6458
 */
 
6459
static unsigned short
 
6460
xmlExpHashNameComputeKey(const xmlChar *name) {
 
6461
    unsigned short value = 0L;
 
6462
    char ch;
 
6463
    
 
6464
    if (name != NULL) {
 
6465
        value += 30 * (*name);
 
6466
        while ((ch = *name++) != 0) {
 
6467
            value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch);
 
6468
        }
 
6469
    }
 
6470
    return (value);
 
6471
}
 
6472
 
 
6473
/*
 
6474
 * xmlExpHashComputeKey:
 
6475
 * Calculate the hash key for a compound expression
 
6476
 */
 
6477
static unsigned short
 
6478
xmlExpHashComputeKey(xmlExpNodeType type, xmlExpNodePtr left,
 
6479
                     xmlExpNodePtr right) {
 
6480
    unsigned long value;
 
6481
    unsigned short ret;
 
6482
    
 
6483
    switch (type) {
 
6484
        case XML_EXP_SEQ:
 
6485
            value = left->key;
 
6486
            value += right->key;
 
6487
            value *= 3;
 
6488
            ret = (unsigned short) value;
 
6489
            break;
 
6490
        case XML_EXP_OR:
 
6491
            value = left->key;
 
6492
            value += right->key;
 
6493
            value *= 7;
 
6494
            ret = (unsigned short) value;
 
6495
            break;
 
6496
        case XML_EXP_COUNT:
 
6497
            value = left->key;
 
6498
            value += right->key;
 
6499
            ret = (unsigned short) value;
 
6500
            break;
 
6501
        default:
 
6502
            ret = 0;
 
6503
    }
 
6504
    return(ret);
 
6505
}
 
6506
 
 
6507
 
 
6508
static xmlExpNodePtr
 
6509
xmlExpNewNode(xmlExpCtxtPtr ctxt, xmlExpNodeType type) {
 
6510
    xmlExpNodePtr ret;
 
6511
 
 
6512
    if (ctxt->nb_nodes >= MAX_NODES)
 
6513
        return(NULL);
 
6514
    ret = (xmlExpNodePtr) xmlMalloc(sizeof(xmlExpNode));
 
6515
    if (ret == NULL)
 
6516
        return(NULL);
 
6517
    memset(ret, 0, sizeof(xmlExpNode));
 
6518
    ret->type = type;
 
6519
    ret->next = NULL;
 
6520
    ctxt->nb_nodes++;
 
6521
    ctxt->nb_cons++;
 
6522
    return(ret);
 
6523
}
 
6524
 
 
6525
/**
 
6526
 * xmlExpHashGetEntry:
 
6527
 * @table: the hash table
 
6528
 *
 
6529
 * Get the unique entry from the hash table. The entry is created if
 
6530
 * needed. @left and @right are consumed, i.e. their ref count will
 
6531
 * be decremented by the operation.
 
6532
 *
 
6533
 * Returns the pointer or NULL in case of error
 
6534
 */
 
6535
static xmlExpNodePtr
 
6536
xmlExpHashGetEntry(xmlExpCtxtPtr ctxt, xmlExpNodeType type,
 
6537
                   xmlExpNodePtr left, xmlExpNodePtr right,
 
6538
                   const xmlChar *name, int min, int max) {
 
6539
    unsigned short kbase, key;
 
6540
    xmlExpNodePtr entry;
 
6541
    xmlExpNodePtr insert;
 
6542
 
 
6543
    if (ctxt == NULL)
 
6544
        return(NULL);
 
6545
 
 
6546
    /*
 
6547
     * Check for duplicate and insertion location.
 
6548
     */
 
6549
    if (type == XML_EXP_ATOM) {
 
6550
        kbase = xmlExpHashNameComputeKey(name);
 
6551
    } else if (type == XML_EXP_COUNT) {
 
6552
        /* COUNT reduction rule 1 */
 
6553
        /* a{1} -> a */
 
6554
        if (min == max) {
 
6555
            if (min == 1) {
 
6556
                return(left);
 
6557
            }
 
6558
            if (min == 0) {
 
6559
                xmlExpFree(ctxt, left);
 
6560
                return(emptyExp);
 
6561
            }
 
6562
        }
 
6563
        if (min < 0) {
 
6564
            xmlExpFree(ctxt, left);
 
6565
            return(forbiddenExp);
 
6566
        }
 
6567
        if (max == -1)
 
6568
            kbase = min + 79;
 
6569
        else
 
6570
            kbase = max - min;
 
6571
        kbase += left->key;
 
6572
    } else if (type == XML_EXP_OR) {
 
6573
        /* Forbid reduction rules */
 
6574
        if (left->type == XML_EXP_FORBID) {
 
6575
            xmlExpFree(ctxt, left);
 
6576
            return(right);
 
6577
        }
 
6578
        if (right->type == XML_EXP_FORBID) {
 
6579
            xmlExpFree(ctxt, right);
 
6580
            return(left);
 
6581
        }
 
6582
 
 
6583
        /* OR reduction rule 1 */
 
6584
        /* a | a reduced to a */
 
6585
        if (left == right) {
 
6586
            left->ref--;
 
6587
            return(left);
 
6588
        }
 
6589
        /* OR canonicalization rule 1 */
 
6590
        /* linearize (a | b) | c into a | (b | c) */
 
6591
        if ((left->type == XML_EXP_OR) && (right->type != XML_EXP_OR)) {
 
6592
            xmlExpNodePtr tmp = left;
 
6593
            left = right;
 
6594
            right = tmp;
 
6595
        }
 
6596
        /* OR reduction rule 2 */
 
6597
        /* a | (a | b) and b | (a | b) are reduced to a | b */
 
6598
        if (right->type == XML_EXP_OR) {
 
6599
            if ((left == right->exp_left) ||
 
6600
                (left == right->exp_right)) {
 
6601
                xmlExpFree(ctxt, left);
 
6602
                return(right);
 
6603
            }
 
6604
        }
 
6605
        /* OR canonicalization rule 2 */
 
6606
        /* linearize (a | b) | c into a | (b | c) */
 
6607
        if (left->type == XML_EXP_OR) {
 
6608
            xmlExpNodePtr tmp;
 
6609
 
 
6610
            /* OR canonicalization rule 2 */
 
6611
            if ((left->exp_right->type != XML_EXP_OR) &&
 
6612
                (left->exp_right->key < left->exp_left->key)) {
 
6613
                tmp = left->exp_right;
 
6614
                left->exp_right = left->exp_left;
 
6615
                left->exp_left = tmp;
 
6616
            }
 
6617
            left->exp_right->ref++;
 
6618
            tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left->exp_right, right,
 
6619
                                     NULL, 0, 0);
 
6620
            left->exp_left->ref++;
 
6621
            tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left->exp_left, tmp,
 
6622
                                     NULL, 0, 0);
 
6623
        
 
6624
            xmlExpFree(ctxt, left);
 
6625
            return(tmp);
 
6626
        }
 
6627
        if (right->type == XML_EXP_OR) {
 
6628
            /* Ordering in the tree */
 
6629
            /* C | (A | B) -> A | (B | C) */
 
6630
            if (left->key > right->exp_right->key) {
 
6631
                xmlExpNodePtr tmp;
 
6632
                right->exp_right->ref++;
 
6633
                tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_right,
 
6634
                                         left, NULL, 0, 0);
 
6635
                right->exp_left->ref++;
 
6636
                tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_left,
 
6637
                                         tmp, NULL, 0, 0);
 
6638
                xmlExpFree(ctxt, right);
 
6639
                return(tmp);
 
6640
            }
 
6641
            /* Ordering in the tree */
 
6642
            /* B | (A | C) -> A | (B | C) */
 
6643
            if (left->key > right->exp_left->key) {
 
6644
                xmlExpNodePtr tmp;
 
6645
                right->exp_right->ref++;
 
6646
                tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left,
 
6647
                                         right->exp_right, NULL, 0, 0);
 
6648
                right->exp_left->ref++;
 
6649
                tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_left,
 
6650
                                         tmp, NULL, 0, 0);
 
6651
                xmlExpFree(ctxt, right);
 
6652
                return(tmp);
 
6653
            }
 
6654
        }
 
6655
        /* we know both types are != XML_EXP_OR here */
 
6656
        else if (left->key > right->key) {
 
6657
            xmlExpNodePtr tmp = left;
 
6658
            left = right;
 
6659
            right = tmp;
 
6660
        }
 
6661
        kbase = xmlExpHashComputeKey(type, left, right);
 
6662
    } else if (type == XML_EXP_SEQ) {
 
6663
        /* Forbid reduction rules */
 
6664
        if (left->type == XML_EXP_FORBID) {
 
6665
            xmlExpFree(ctxt, right);
 
6666
            return(left);
 
6667
        }
 
6668
        if (right->type == XML_EXP_FORBID) {
 
6669
            xmlExpFree(ctxt, left);
 
6670
            return(right);
 
6671
        }
 
6672
        /* Empty reduction rules */
 
6673
        if (right->type == XML_EXP_EMPTY) {
 
6674
            return(left);
 
6675
        }
 
6676
        if (left->type == XML_EXP_EMPTY) {
 
6677
            return(right);
 
6678
        }
 
6679
        kbase = xmlExpHashComputeKey(type, left, right);
 
6680
    } else 
 
6681
        return(NULL);
 
6682
 
 
6683
    key = kbase % ctxt->size;
 
6684
    if (ctxt->table[key] != NULL) {
 
6685
        for (insert = ctxt->table[key]; insert != NULL;
 
6686
             insert = insert->next) {
 
6687
            if ((insert->key == kbase) &&
 
6688
                (insert->type == type)) {
 
6689
                if (type == XML_EXP_ATOM) {
 
6690
                    if (name == insert->exp_str) {
 
6691
                        insert->ref++;
 
6692
                        return(insert);
 
6693
                    }
 
6694
                } else if (type == XML_EXP_COUNT) {
 
6695
                    if ((insert->exp_min == min) && (insert->exp_max == max) &&
 
6696
                        (insert->exp_left == left)) {
 
6697
                        insert->ref++;
 
6698
                        left->ref--;
 
6699
                        return(insert);
 
6700
                    }
 
6701
                } else if ((insert->exp_left == left) &&
 
6702
                           (insert->exp_right == right)) {
 
6703
                    insert->ref++;
 
6704
                    left->ref--;
 
6705
                    right->ref--;
 
6706
                    return(insert);
 
6707
                }
 
6708
            }
 
6709
        }
 
6710
    }
 
6711
 
 
6712
    entry = xmlExpNewNode(ctxt, type);
 
6713
    if (entry == NULL)
 
6714
        return(NULL);
 
6715
    entry->key = kbase;
 
6716
    if (type == XML_EXP_ATOM) {
 
6717
        entry->exp_str = name;
 
6718
        entry->c_max = 1;
 
6719
    } else if (type == XML_EXP_COUNT) {
 
6720
        entry->exp_min = min;
 
6721
        entry->exp_max = max;
 
6722
        entry->exp_left = left;
 
6723
        if ((min == 0) || (IS_NILLABLE(left)))
 
6724
            entry->info |= XML_EXP_NILABLE;
 
6725
        if (max < 0)
 
6726
            entry->c_max = -1;
 
6727
        else
 
6728
            entry->c_max = max * entry->exp_left->c_max;
 
6729
    } else {
 
6730
        entry->exp_left = left;
 
6731
        entry->exp_right = right;
 
6732
        if (type == XML_EXP_OR) {
 
6733
            if ((IS_NILLABLE(left)) || (IS_NILLABLE(right)))
 
6734
                entry->info |= XML_EXP_NILABLE;
 
6735
            if ((entry->exp_left->c_max == -1) ||
 
6736
                (entry->exp_right->c_max == -1))
 
6737
                entry->c_max = -1;
 
6738
            else if (entry->exp_left->c_max > entry->exp_right->c_max)
 
6739
                entry->c_max = entry->exp_left->c_max;
 
6740
            else
 
6741
                entry->c_max = entry->exp_right->c_max;
 
6742
        } else {
 
6743
            if ((IS_NILLABLE(left)) && (IS_NILLABLE(right)))
 
6744
                entry->info |= XML_EXP_NILABLE;
 
6745
            if ((entry->exp_left->c_max == -1) ||
 
6746
                (entry->exp_right->c_max == -1))
 
6747
                entry->c_max = -1;
 
6748
            else
 
6749
                entry->c_max = entry->exp_left->c_max + entry->exp_right->c_max;
 
6750
        }
 
6751
    }
 
6752
    entry->ref = 1;
 
6753
    if (ctxt->table[key] != NULL)
 
6754
        entry->next = ctxt->table[key];
 
6755
 
 
6756
    ctxt->table[key] = entry;
 
6757
    ctxt->nbElems++;
 
6758
 
 
6759
    return(entry);
 
6760
}
 
6761
 
 
6762
/**
 
6763
 * xmlExpFree:
 
6764
 * @ctxt: the expression context
 
6765
 * @exp: the expression
 
6766
 *
 
6767
 * Dereference the expression
 
6768
 */
 
6769
void
 
6770
xmlExpFree(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp) {
 
6771
    if ((exp == NULL) || (exp == forbiddenExp) || (exp == emptyExp))
 
6772
        return;
 
6773
    exp->ref--;
 
6774
    if (exp->ref == 0) {
 
6775
        unsigned short key;
 
6776
 
 
6777
        /* Unlink it first from the hash table */
 
6778
        key = exp->key % ctxt->size;
 
6779
        if (ctxt->table[key] == exp) {
 
6780
            ctxt->table[key] = exp->next;
 
6781
        } else {
 
6782
            xmlExpNodePtr tmp;
 
6783
 
 
6784
            tmp = ctxt->table[key];
 
6785
            while (tmp != NULL) {
 
6786
                if (tmp->next == exp) {
 
6787
                    tmp->next = exp->next;
 
6788
                    break;
 
6789
                }
 
6790
                tmp = tmp->next;
 
6791
            }
 
6792
        }
 
6793
 
 
6794
        if ((exp->type == XML_EXP_SEQ) || (exp->type == XML_EXP_OR)) {
 
6795
            xmlExpFree(ctxt, exp->exp_left);
 
6796
            xmlExpFree(ctxt, exp->exp_right);
 
6797
        } else if (exp->type == XML_EXP_COUNT) {
 
6798
            xmlExpFree(ctxt, exp->exp_left);
 
6799
        }
 
6800
        xmlFree(exp);
 
6801
        ctxt->nb_nodes--;
 
6802
    }
 
6803
}
 
6804
 
 
6805
/**
 
6806
 * xmlExpRef:
 
6807
 * @exp: the expression
 
6808
 *
 
6809
 * Increase the reference count of the expression
 
6810
 */
 
6811
void
 
6812
xmlExpRef(xmlExpNodePtr exp) {
 
6813
    if (exp != NULL)
 
6814
        exp->ref++;
 
6815
}
 
6816
 
 
6817
/**
 
6818
 * xmlExpNewAtom:
 
6819
 * @ctxt: the expression context
 
6820
 * @name: the atom name
 
6821
 * @len: the atom name lenght in byte (or -1);
 
6822
 *
 
6823
 * Get the atom associated to this name from that context
 
6824
 *
 
6825
 * Returns the node or NULL in case of error
 
6826
 */
 
6827
xmlExpNodePtr
 
6828
xmlExpNewAtom(xmlExpCtxtPtr ctxt, const xmlChar *name, int len) {
 
6829
    if ((ctxt == NULL) || (name == NULL))
 
6830
        return(NULL);
 
6831
    name = xmlDictLookup(ctxt->dict, name, len);
 
6832
    if (name == NULL)
 
6833
        return(NULL);
 
6834
    return(xmlExpHashGetEntry(ctxt, XML_EXP_ATOM, NULL, NULL, name, 0, 0));
 
6835
}
 
6836
 
 
6837
/**
 
6838
 * xmlExpNewOr:
 
6839
 * @ctxt: the expression context
 
6840
 * @left: left expression
 
6841
 * @right: right expression
 
6842
 *
 
6843
 * Get the atom associated to the choice @left | @right
 
6844
 * Note that @left and @right are consumed in the operation, to keep
 
6845
 * an handle on them use xmlExpRef() and use xmlExpFree() to release them,
 
6846
 * this is true even in case of failure (unless ctxt == NULL).
 
6847
 *
 
6848
 * Returns the node or NULL in case of error
 
6849
 */
 
6850
xmlExpNodePtr
 
6851
xmlExpNewOr(xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right) {
 
6852
    if (ctxt == NULL)
 
6853
        return(NULL);
 
6854
    if ((left == NULL) || (right == NULL)) {
 
6855
        xmlExpFree(ctxt, left);
 
6856
        xmlExpFree(ctxt, right);
 
6857
        return(NULL);
 
6858
    }
 
6859
    return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, left, right, NULL, 0, 0));
 
6860
}
 
6861
 
 
6862
/**
 
6863
 * xmlExpNewSeq:
 
6864
 * @ctxt: the expression context
 
6865
 * @left: left expression
 
6866
 * @right: right expression
 
6867
 *
 
6868
 * Get the atom associated to the sequence @left , @right
 
6869
 * Note that @left and @right are consumed in the operation, to keep
 
6870
 * an handle on them use xmlExpRef() and use xmlExpFree() to release them,
 
6871
 * this is true even in case of failure (unless ctxt == NULL).
 
6872
 *
 
6873
 * Returns the node or NULL in case of error
 
6874
 */
 
6875
xmlExpNodePtr
 
6876
xmlExpNewSeq(xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right) {
 
6877
    if (ctxt == NULL)
 
6878
        return(NULL);
 
6879
    if ((left == NULL) || (right == NULL)) {
 
6880
        xmlExpFree(ctxt, left);
 
6881
        xmlExpFree(ctxt, right);
 
6882
        return(NULL);
 
6883
    }
 
6884
    return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, left, right, NULL, 0, 0));
 
6885
}
 
6886
 
 
6887
/**
 
6888
 * xmlExpNewRange:
 
6889
 * @ctxt: the expression context
 
6890
 * @subset: the expression to be repeated
 
6891
 * @min: the lower bound for the repetition
 
6892
 * @max: the upper bound for the repetition, -1 means infinite
 
6893
 *
 
6894
 * Get the atom associated to the range (@subset){@min, @max}
 
6895
 * Note that @subset is consumed in the operation, to keep
 
6896
 * an handle on it use xmlExpRef() and use xmlExpFree() to release it,
 
6897
 * this is true even in case of failure (unless ctxt == NULL).
 
6898
 *
 
6899
 * Returns the node or NULL in case of error
 
6900
 */
 
6901
xmlExpNodePtr
 
6902
xmlExpNewRange(xmlExpCtxtPtr ctxt, xmlExpNodePtr subset, int min, int max) {
 
6903
    if (ctxt == NULL)
 
6904
        return(NULL);
 
6905
    if ((subset == NULL) || (min < 0) || (max < -1) ||
 
6906
        ((max >= 0) && (min > max))) {
 
6907
        xmlExpFree(ctxt, subset);
 
6908
        return(NULL);
 
6909
    }
 
6910
    return(xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, subset,
 
6911
                              NULL, NULL, min, max));
 
6912
}
 
6913
 
 
6914
/************************************************************************
 
6915
 *                                                                      *
 
6916
 *              Public API for operations on expressions                *
 
6917
 *                                                                      *
 
6918
 ************************************************************************/
 
6919
 
 
6920
static int
 
6921
xmlExpGetLanguageInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, 
 
6922
                     const xmlChar**list, int len, int nb) {
 
6923
    int tmp, tmp2;
 
6924
tail:
 
6925
    switch (exp->type) {
 
6926
        case XML_EXP_EMPTY:
 
6927
            return(0);
 
6928
        case XML_EXP_ATOM:
 
6929
            for (tmp = 0;tmp < nb;tmp++)
 
6930
                if (list[tmp] == exp->exp_str)
 
6931
                    return(0);
 
6932
            if (nb >= len)
 
6933
                return(-2);
 
6934
            list[nb++] = exp->exp_str;
 
6935
            return(1);
 
6936
        case XML_EXP_COUNT:
 
6937
            exp = exp->exp_left;
 
6938
            goto tail;
 
6939
        case XML_EXP_SEQ:
 
6940
        case XML_EXP_OR:
 
6941
            tmp = xmlExpGetLanguageInt(ctxt, exp->exp_left, list, len, nb);
 
6942
            if (tmp < 0)
 
6943
                return(tmp);
 
6944
            tmp2 = xmlExpGetLanguageInt(ctxt, exp->exp_right, list, len,
 
6945
                                        nb + tmp);
 
6946
            if (tmp2 < 0)
 
6947
                return(tmp2);
 
6948
            return(tmp + tmp2);
 
6949
    }
 
6950
    return(-1);
 
6951
}
 
6952
 
 
6953
/**
 
6954
 * xmlExpGetLanguage:
 
6955
 * @ctxt: the expression context
 
6956
 * @exp: the expression
 
6957
 * @langList: where to store the tokens
 
6958
 * @len: the allocated lenght of @list
 
6959
 *
 
6960
 * Find all the strings used in @exp and store them in @list
 
6961
 *
 
6962
 * Returns the number of unique strings found, -1 in case of errors and
 
6963
 *         -2 if there is more than @len strings
 
6964
 */
 
6965
int
 
6966
xmlExpGetLanguage(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, 
 
6967
                  const xmlChar**langList, int len) {
 
6968
    if ((ctxt == NULL) || (exp == NULL) || (langList == NULL) || (len <= 0))
 
6969
        return(-1);
 
6970
    return(xmlExpGetLanguageInt(ctxt, exp, langList, len, 0));
 
6971
}
 
6972
 
 
6973
static int
 
6974
xmlExpGetStartInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, 
 
6975
                  const xmlChar**list, int len, int nb) {
 
6976
    int tmp, tmp2;
 
6977
tail:
 
6978
    switch (exp->type) {
 
6979
        case XML_EXP_FORBID:
 
6980
            return(0);
 
6981
        case XML_EXP_EMPTY:
 
6982
            return(0);
 
6983
        case XML_EXP_ATOM:
 
6984
            for (tmp = 0;tmp < nb;tmp++)
 
6985
                if (list[tmp] == exp->exp_str)
 
6986
                    return(0);
 
6987
            if (nb >= len)
 
6988
                return(-2);
 
6989
            list[nb++] = exp->exp_str;
 
6990
            return(1);
 
6991
        case XML_EXP_COUNT:
 
6992
            exp = exp->exp_left;
 
6993
            goto tail;
 
6994
        case XML_EXP_SEQ:
 
6995
            tmp = xmlExpGetStartInt(ctxt, exp->exp_left, list, len, nb);
 
6996
            if (tmp < 0)
 
6997
                return(tmp);
 
6998
            if (IS_NILLABLE(exp->exp_left)) {
 
6999
                tmp2 = xmlExpGetStartInt(ctxt, exp->exp_right, list, len,
 
7000
                                            nb + tmp);
 
7001
                if (tmp2 < 0)
 
7002
                    return(tmp2);
 
7003
                tmp += tmp2;
 
7004
            }
 
7005
            return(tmp);
 
7006
        case XML_EXP_OR:
 
7007
            tmp = xmlExpGetStartInt(ctxt, exp->exp_left, list, len, nb);
 
7008
            if (tmp < 0)
 
7009
                return(tmp);
 
7010
            tmp2 = xmlExpGetStartInt(ctxt, exp->exp_right, list, len,
 
7011
                                        nb + tmp);
 
7012
            if (tmp2 < 0)
 
7013
                return(tmp2);
 
7014
            return(tmp + tmp2);
 
7015
    }
 
7016
    return(-1);
 
7017
}
 
7018
 
 
7019
/**
 
7020
 * xmlExpGetStart:
 
7021
 * @ctxt: the expression context
 
7022
 * @exp: the expression
 
7023
 * @tokList: where to store the tokens
 
7024
 * @len: the allocated lenght of @list
 
7025
 *
 
7026
 * Find all the strings that appears at the start of the languages
 
7027
 * accepted by @exp and store them in @list. E.g. for (a, b) | c
 
7028
 * it will return the list [a, c]
 
7029
 *
 
7030
 * Returns the number of unique strings found, -1 in case of errors and
 
7031
 *         -2 if there is more than @len strings
 
7032
 */
 
7033
int
 
7034
xmlExpGetStart(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, 
 
7035
               const xmlChar**tokList, int len) {
 
7036
    if ((ctxt == NULL) || (exp == NULL) || (tokList == NULL) || (len <= 0))
 
7037
        return(-1);
 
7038
    return(xmlExpGetStartInt(ctxt, exp, tokList, len, 0));
 
7039
}
 
7040
 
 
7041
/**
 
7042
 * xmlExpIsNillable:
 
7043
 * @exp: the expression
 
7044
 *
 
7045
 * Finds if the expression is nillable, i.e. if it accepts the empty sequqnce
 
7046
 *
 
7047
 * Returns 1 if nillable, 0 if not and -1 in case of error
 
7048
 */
 
7049
int
 
7050
xmlExpIsNillable(xmlExpNodePtr exp) {
 
7051
    if (exp == NULL)
 
7052
        return(-1);
 
7053
    return(IS_NILLABLE(exp) != 0);
 
7054
}
 
7055
 
 
7056
static xmlExpNodePtr
 
7057
xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *str)
 
7058
{
 
7059
    xmlExpNodePtr ret;
 
7060
 
 
7061
    switch (exp->type) {
 
7062
        case XML_EXP_EMPTY:
 
7063
            return(forbiddenExp);
 
7064
        case XML_EXP_FORBID:
 
7065
            return(forbiddenExp);
 
7066
        case XML_EXP_ATOM:
 
7067
            if (exp->exp_str == str) {
 
7068
#ifdef DEBUG_DERIV
 
7069
                printf("deriv atom: equal => Empty\n");
 
7070
#endif
 
7071
                ret = emptyExp;
 
7072
            } else {
 
7073
#ifdef DEBUG_DERIV
 
7074
                printf("deriv atom: mismatch => forbid\n");
 
7075
#endif
 
7076
                /* TODO wildcards here */
 
7077
                ret = forbiddenExp;
 
7078
            }
 
7079
            return(ret);
 
7080
        case XML_EXP_OR: {
 
7081
            xmlExpNodePtr tmp;
 
7082
 
 
7083
#ifdef DEBUG_DERIV
 
7084
            printf("deriv or: => or(derivs)\n");
 
7085
#endif
 
7086
            tmp = xmlExpStringDeriveInt(ctxt, exp->exp_left, str);
 
7087
            if (tmp == NULL) {
 
7088
                return(NULL);
 
7089
            }
 
7090
            ret = xmlExpStringDeriveInt(ctxt, exp->exp_right, str);
 
7091
            if (ret == NULL) {
 
7092
                xmlExpFree(ctxt, tmp);
 
7093
                return(NULL);
 
7094
            }
 
7095
            ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, tmp, ret,
 
7096
                             NULL, 0, 0);
 
7097
            return(ret);
 
7098
        }
 
7099
        case XML_EXP_SEQ:
 
7100
#ifdef DEBUG_DERIV
 
7101
            printf("deriv seq: starting with left\n");
 
7102
#endif
 
7103
            ret = xmlExpStringDeriveInt(ctxt, exp->exp_left, str);
 
7104
            if (ret == NULL) {
 
7105
                return(NULL);
 
7106
            } else if (ret == forbiddenExp) {
 
7107
                if (IS_NILLABLE(exp->exp_left)) {
 
7108
#ifdef DEBUG_DERIV
 
7109
                    printf("deriv seq: left failed but nillable\n");
 
7110
#endif
 
7111
                    ret = xmlExpStringDeriveInt(ctxt, exp->exp_right, str);
 
7112
                }
 
7113
            } else {
 
7114
#ifdef DEBUG_DERIV
 
7115
                printf("deriv seq: left match => sequence\n");
 
7116
#endif
 
7117
                exp->exp_right->ref++;
 
7118
                ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, exp->exp_right,
 
7119
                                         NULL, 0, 0);
 
7120
            }
 
7121
            return(ret);
 
7122
        case XML_EXP_COUNT: {
 
7123
            int min, max;
 
7124
            xmlExpNodePtr tmp;
 
7125
 
 
7126
            if (exp->exp_max == 0)
 
7127
                return(forbiddenExp);
 
7128
            ret = xmlExpStringDeriveInt(ctxt, exp->exp_left, str);
 
7129
            if (ret == NULL)
 
7130
                return(NULL);
 
7131
            if (ret == forbiddenExp) {
 
7132
#ifdef DEBUG_DERIV
 
7133
                printf("deriv count: pattern mismatch => forbid\n");
 
7134
#endif
 
7135
                return(ret);
 
7136
            }
 
7137
            if (exp->exp_max == 1)
 
7138
                return(ret);
 
7139
            if (exp->exp_max < 0) /* unbounded */
 
7140
                max = -1;
 
7141
            else
 
7142
                max = exp->exp_max - 1;
 
7143
            if (exp->exp_min > 0)
 
7144
                min = exp->exp_min - 1;
 
7145
            else
 
7146
                min = 0;
 
7147
            exp->exp_left->ref++;
 
7148
            tmp = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left, NULL,
 
7149
                                     NULL, min, max);
 
7150
            if (ret == emptyExp) {
 
7151
#ifdef DEBUG_DERIV
 
7152
                printf("deriv count: match to empty => new count\n");
 
7153
#endif
 
7154
                return(tmp);
 
7155
            }
 
7156
#ifdef DEBUG_DERIV
 
7157
            printf("deriv count: match => sequence with new count\n");
 
7158
#endif
 
7159
            return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, tmp,
 
7160
                                      NULL, 0, 0));
 
7161
        }
 
7162
    }
 
7163
    return(NULL);
 
7164
}
 
7165
 
 
7166
/**
 
7167
 * xmlExpStringDerive:
 
7168
 * @ctxt: the expression context
 
7169
 * @exp: the expression
 
7170
 * @str: the string
 
7171
 * @len: the string len in bytes if available
 
7172
 *
 
7173
 * Do one step of Brzozowski derivation of the expression @exp with
 
7174
 * respect to the input string
 
7175
 *
 
7176
 * Returns the resulting expression or NULL in case of internal error
 
7177
 */
 
7178
xmlExpNodePtr
 
7179
xmlExpStringDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
 
7180
                   const xmlChar *str, int len) {
 
7181
    const xmlChar *input;
 
7182
 
 
7183
    if ((exp == NULL) || (ctxt == NULL) || (str == NULL)) {
 
7184
        return(NULL);
 
7185
    }
 
7186
    /*
 
7187
     * check the string is in the dictionnary, if yes use an interned
 
7188
     * copy, otherwise we know it's not an acceptable input
 
7189
     */
 
7190
    input = xmlDictExists(ctxt->dict, str, len);
 
7191
    if (input == NULL) {
 
7192
        return(forbiddenExp);
 
7193
    }
 
7194
    return(xmlExpStringDeriveInt(ctxt, exp, input));
 
7195
}
 
7196
 
 
7197
static int
 
7198
xmlExpCheckCard(xmlExpNodePtr exp, xmlExpNodePtr sub) {
 
7199
    int ret = 1;
 
7200
 
 
7201
    if (sub->c_max == -1) {
 
7202
        if (exp->c_max != -1)
 
7203
            ret = 0;
 
7204
    } else if ((exp->c_max >= 0) && (exp->c_max < sub->c_max)) {
 
7205
        ret = 0;
 
7206
    }
 
7207
#if 0
 
7208
    if ((IS_NILLABLE(sub)) && (!IS_NILLABLE(exp)))
 
7209
        ret = 0;
 
7210
#endif
 
7211
    return(ret);
 
7212
}
 
7213
 
 
7214
static xmlExpNodePtr xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp,
 
7215
                                        xmlExpNodePtr sub);
 
7216
/**
 
7217
 * xmlExpDivide:
 
7218
 * @ctxt: the expressions context
 
7219
 * @exp: the englobing expression
 
7220
 * @sub: the subexpression
 
7221
 * @mult: the multiple expression
 
7222
 * @remain: the remain from the derivation of the multiple
 
7223
 *
 
7224
 * Check if exp is a multiple of sub, i.e. if there is a finite number n
 
7225
 * so that sub{n} subsume exp
 
7226
 *
 
7227
 * Returns the multiple value if successful, 0 if it is not a multiple
 
7228
 *         and -1 in case of internel error.
 
7229
 */
 
7230
 
 
7231
static int
 
7232
xmlExpDivide(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub,
 
7233
             xmlExpNodePtr *mult, xmlExpNodePtr *remain) {
 
7234
    int i;
 
7235
    xmlExpNodePtr tmp, tmp2;
 
7236
 
 
7237
    if (mult != NULL) *mult = NULL;
 
7238
    if (remain != NULL) *remain = NULL;
 
7239
    if (exp->c_max == -1) return(0);
 
7240
    if (IS_NILLABLE(exp) && (!IS_NILLABLE(sub))) return(0);
 
7241
 
 
7242
    for (i = 1;i <= exp->c_max;i++) {
 
7243
        sub->ref++;
 
7244
        tmp = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT,
 
7245
                                 sub, NULL, NULL, i, i);
 
7246
        if (tmp == NULL) {
 
7247
            return(-1);
 
7248
        }
 
7249
        if (!xmlExpCheckCard(tmp, exp)) {
 
7250
            xmlExpFree(ctxt, tmp);
 
7251
            continue;
 
7252
        }
 
7253
        tmp2 = xmlExpExpDeriveInt(ctxt, tmp, exp);
 
7254
        if (tmp2 == NULL) {
 
7255
            xmlExpFree(ctxt, tmp);
 
7256
            return(-1);
 
7257
        }
 
7258
        if ((tmp2 != forbiddenExp) && (IS_NILLABLE(tmp2))) {
 
7259
            if (remain != NULL)
 
7260
                *remain = tmp2;
 
7261
            else
 
7262
                xmlExpFree(ctxt, tmp2);
 
7263
            if (mult != NULL)
 
7264
                *mult = tmp;
 
7265
            else
 
7266
                xmlExpFree(ctxt, tmp);
 
7267
#ifdef DEBUG_DERIV
 
7268
            printf("Divide succeeded %d\n", i);
 
7269
#endif
 
7270
            return(i);
 
7271
        }
 
7272
        xmlExpFree(ctxt, tmp);
 
7273
        xmlExpFree(ctxt, tmp2);
 
7274
    }
 
7275
#ifdef DEBUG_DERIV
 
7276
    printf("Divide failed\n");
 
7277
#endif
 
7278
    return(0);
 
7279
}
 
7280
 
 
7281
/**
 
7282
 * xmlExpExpDeriveInt:
 
7283
 * @ctxt: the expressions context
 
7284
 * @exp: the englobing expression
 
7285
 * @sub: the subexpression
 
7286
 *
 
7287
 * Try to do a step of Brzozowski derivation but at a higher level
 
7288
 * the input being a subexpression.
 
7289
 *
 
7290
 * Returns the resulting expression or NULL in case of internal error
 
7291
 */
 
7292
static xmlExpNodePtr
 
7293
xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) {
 
7294
    xmlExpNodePtr ret, tmp, tmp2, tmp3;
 
7295
    const xmlChar **tab;
 
7296
    int len, i;
 
7297
 
 
7298
    /*
 
7299
     * In case of equality and if the expression can only consume a finite
 
7300
     * amount, then the derivation is empty
 
7301
     */
 
7302
    if ((exp == sub) && (exp->c_max >= 0)) {
 
7303
#ifdef DEBUG_DERIV
 
7304
        printf("Equal(exp, sub) and finite -> Empty\n");
 
7305
#endif
 
7306
        return(emptyExp);
 
7307
    }
 
7308
    /*
 
7309
     * decompose sub sequence first
 
7310
     */
 
7311
    if (sub->type == XML_EXP_EMPTY) {
 
7312
#ifdef DEBUG_DERIV
 
7313
        printf("Empty(sub) -> Empty\n");
 
7314
#endif
 
7315
        exp->ref++;
 
7316
        return(exp);
 
7317
    }
 
7318
    if (sub->type == XML_EXP_SEQ) {
 
7319
#ifdef DEBUG_DERIV
 
7320
        printf("Seq(sub) -> decompose\n");
 
7321
#endif
 
7322
        tmp = xmlExpExpDeriveInt(ctxt, exp, sub->exp_left);
 
7323
        if (tmp == NULL)
 
7324
            return(NULL);
 
7325
        if (tmp == forbiddenExp)
 
7326
            return(tmp);
 
7327
        ret = xmlExpExpDeriveInt(ctxt, tmp, sub->exp_right);
 
7328
        xmlExpFree(ctxt, tmp);
 
7329
        return(ret);
 
7330
    }
 
7331
    if (sub->type == XML_EXP_OR) {
 
7332
#ifdef DEBUG_DERIV
 
7333
        printf("Or(sub) -> decompose\n");
 
7334
#endif
 
7335
        tmp = xmlExpExpDeriveInt(ctxt, exp, sub->exp_left);
 
7336
        if (tmp == forbiddenExp)
 
7337
            return(tmp);
 
7338
        if (tmp == NULL)
 
7339
            return(NULL);
 
7340
        ret = xmlExpExpDeriveInt(ctxt, exp, sub->exp_right);
 
7341
        if ((ret == NULL) || (ret == forbiddenExp)) {
 
7342
            xmlExpFree(ctxt, tmp);
 
7343
            return(ret);
 
7344
        }
 
7345
        return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, tmp, ret, NULL, 0, 0));
 
7346
    }
 
7347
    if (!xmlExpCheckCard(exp, sub)) {
 
7348
#ifdef DEBUG_DERIV
 
7349
        printf("CheckCard(exp, sub) failed -> Forbid\n");
 
7350
#endif
 
7351
        return(forbiddenExp);
 
7352
    }
 
7353
    switch (exp->type) {
 
7354
        case XML_EXP_EMPTY:
 
7355
            if (sub == emptyExp)
 
7356
                return(emptyExp);
 
7357
#ifdef DEBUG_DERIV
 
7358
            printf("Empty(exp) -> Forbid\n");
 
7359
#endif
 
7360
            return(forbiddenExp);
 
7361
        case XML_EXP_FORBID:
 
7362
#ifdef DEBUG_DERIV
 
7363
            printf("Forbid(exp) -> Forbid\n");
 
7364
#endif
 
7365
            return(forbiddenExp);
 
7366
        case XML_EXP_ATOM:
 
7367
            if (sub->type == XML_EXP_ATOM) {
 
7368
                /* TODO: handle wildcards */
 
7369
                if (exp->exp_str == sub->exp_str) {
 
7370
#ifdef DEBUG_DERIV
 
7371
                    printf("Atom match -> Empty\n");
 
7372
#endif
 
7373
                    return(emptyExp);
 
7374
                }
 
7375
#ifdef DEBUG_DERIV
 
7376
                printf("Atom mismatch -> Forbid\n");
 
7377
#endif
 
7378
                return(forbiddenExp);
 
7379
            }
 
7380
            if ((sub->type == XML_EXP_COUNT) &&
 
7381
                (sub->exp_max == 1) &&
 
7382
                (sub->exp_left->type == XML_EXP_ATOM)) {
 
7383
                /* TODO: handle wildcards */
 
7384
                if (exp->exp_str == sub->exp_left->exp_str) {
 
7385
#ifdef DEBUG_DERIV
 
7386
                    printf("Atom match -> Empty\n");
 
7387
#endif
 
7388
                    return(emptyExp);
 
7389
                }
 
7390
#ifdef DEBUG_DERIV
 
7391
                printf("Atom mismatch -> Forbid\n");
 
7392
#endif
 
7393
                return(forbiddenExp);
 
7394
            }
 
7395
#ifdef DEBUG_DERIV
 
7396
            printf("Compex exp vs Atom -> Forbid\n");
 
7397
#endif
 
7398
            return(forbiddenExp);
 
7399
        case XML_EXP_SEQ:
 
7400
            /* try to get the sequence consumed only if possible */
 
7401
            if (xmlExpCheckCard(exp->exp_left, sub)) {
 
7402
                /* See if the sequence can be consumed directly */
 
7403
#ifdef DEBUG_DERIV
 
7404
                printf("Seq trying left only\n");
 
7405
#endif
 
7406
                ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub);
 
7407
                if ((ret != forbiddenExp) && (ret != NULL)) {
 
7408
#ifdef DEBUG_DERIV
 
7409
                    printf("Seq trying left only worked\n");
 
7410
#endif
 
7411
                    /*
 
7412
                     * TODO: assumption here that we are determinist
 
7413
                     *       i.e. we won't get to a nillable exp left
 
7414
                     *       subset which could be matched by the right
 
7415
                     *       part too.
 
7416
                     * e.g.: (a | b)+,(a | c) and 'a+,a'
 
7417
                     */
 
7418
                    exp->exp_right->ref++;
 
7419
                    return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret,
 
7420
                                              exp->exp_right, NULL, 0, 0));
 
7421
                }
 
7422
#ifdef DEBUG_DERIV
 
7423
            } else {
 
7424
                printf("Seq: left too short\n");
 
7425
#endif
 
7426
            }
 
7427
            /* Try instead to decompose */
 
7428
            if (sub->type == XML_EXP_COUNT) {
 
7429
                int min, max;
 
7430
 
 
7431
#ifdef DEBUG_DERIV
 
7432
                printf("Seq: sub is a count\n");
 
7433
#endif
 
7434
                ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub->exp_left);
 
7435
                if (ret == NULL)
 
7436
                    return(NULL);
 
7437
                if (ret != forbiddenExp) {
 
7438
#ifdef DEBUG_DERIV
 
7439
                    printf("Seq , Count match on left\n");
 
7440
#endif
 
7441
                    if (sub->exp_max < 0)
 
7442
                        max = -1;
 
7443
                    else
 
7444
                        max = sub->exp_max -1;
 
7445
                    if (sub->exp_min > 0)
 
7446
                        min = sub->exp_min -1;
 
7447
                    else
 
7448
                        min = 0;
 
7449
                    exp->exp_right->ref++;
 
7450
                    tmp = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret,
 
7451
                                             exp->exp_right, NULL, 0, 0);
 
7452
                    if (tmp == NULL)
 
7453
                        return(NULL);
 
7454
 
 
7455
                    sub->exp_left->ref++;
 
7456
                    tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT,
 
7457
                                      sub->exp_left, NULL, NULL, min, max);
 
7458
                    if (tmp2 == NULL) {
 
7459
                        xmlExpFree(ctxt, tmp);
 
7460
                        return(NULL);
 
7461
                    }
 
7462
                    ret = xmlExpExpDeriveInt(ctxt, tmp, tmp2);
 
7463
                    xmlExpFree(ctxt, tmp);
 
7464
                    xmlExpFree(ctxt, tmp2);
 
7465
                    return(ret);
 
7466
                }
 
7467
            }
 
7468
            /* we made no progress on structured operations */
 
7469
            break;
 
7470
        case XML_EXP_OR:
 
7471
#ifdef DEBUG_DERIV
 
7472
            printf("Or , trying both side\n");
 
7473
#endif
 
7474
            ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub);
 
7475
            if (ret == NULL)
 
7476
                return(NULL);
 
7477
            tmp = xmlExpExpDeriveInt(ctxt, exp->exp_right, sub);
 
7478
            if (tmp == NULL) {
 
7479
                xmlExpFree(ctxt, ret);
 
7480
                return(NULL);
 
7481
            }
 
7482
            return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, tmp, NULL, 0, 0));
 
7483
        case XML_EXP_COUNT: {
 
7484
            int min, max;
 
7485
 
 
7486
            if (sub->type == XML_EXP_COUNT) {
 
7487
                /*
 
7488
                 * Try to see if the loop is completely subsumed
 
7489
                 */
 
7490
                tmp = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub->exp_left);
 
7491
                if (tmp == NULL)
 
7492
                    return(NULL);
 
7493
                if (tmp == forbiddenExp) {
 
7494
                    int mult;
 
7495
 
 
7496
#ifdef DEBUG_DERIV
 
7497
                    printf("Count, Count inner don't subsume\n");
 
7498
#endif
 
7499
                    mult = xmlExpDivide(ctxt, sub->exp_left, exp->exp_left,
 
7500
                                        NULL, &tmp);
 
7501
                    if (mult <= 0) {
 
7502
#ifdef DEBUG_DERIV
 
7503
                        printf("Count, Count not multiple => forbidden\n");
 
7504
#endif
 
7505
                        return(forbiddenExp);
 
7506
                    }
 
7507
                    if (sub->exp_max == -1) {
 
7508
                        max = -1;
 
7509
                        if (exp->exp_max == -1) {
 
7510
                            if (exp->exp_min <= sub->exp_min * mult)
 
7511
                                min = 0;
 
7512
                            else
 
7513
                                min = exp->exp_min - sub->exp_min * mult;
 
7514
                        } else {
 
7515
#ifdef DEBUG_DERIV
 
7516
                            printf("Count, Count finite can't subsume infinite\n");
 
7517
#endif
 
7518
                            xmlExpFree(ctxt, tmp);
 
7519
                            return(forbiddenExp);
 
7520
                        }
 
7521
                    } else {
 
7522
                        if (exp->exp_max == -1) {
 
7523
#ifdef DEBUG_DERIV
 
7524
                            printf("Infinite loop consume mult finite loop\n");
 
7525
#endif
 
7526
                            if (exp->exp_min > sub->exp_min * mult) {
 
7527
                                max = -1;
 
7528
                                min = exp->exp_min - sub->exp_min * mult;
 
7529
                            } else {
 
7530
                                max = -1;
 
7531
                                min = 0;
 
7532
                            }
 
7533
                        } else {
 
7534
                            if (exp->exp_max < sub->exp_max * mult) {
 
7535
#ifdef DEBUG_DERIV
 
7536
                                printf("loops max mult mismatch => forbidden\n");
 
7537
#endif
 
7538
                                xmlExpFree(ctxt, tmp);
 
7539
                                return(forbiddenExp);
 
7540
                            }
 
7541
                            if (sub->exp_max * mult > exp->exp_min)
 
7542
                                min = 0;
 
7543
                            else
 
7544
                                min = exp->exp_min - sub->exp_max * mult;
 
7545
                            max = exp->exp_max - sub->exp_max * mult;
 
7546
                        }
 
7547
                    }
 
7548
                } else if (!IS_NILLABLE(tmp)) {
 
7549
                    /*
 
7550
                     * TODO: loop here to try to grow if working on finite
 
7551
                     *       blocks.
 
7552
                     */
 
7553
#ifdef DEBUG_DERIV
 
7554
                    printf("Count, Count remain not nillable => forbidden\n");
 
7555
#endif
 
7556
                    xmlExpFree(ctxt, tmp);
 
7557
                    return(forbiddenExp);
 
7558
                } else if (sub->exp_max == -1) {
 
7559
                    if (exp->exp_max == -1) {
 
7560
                        if (exp->exp_min <= sub->exp_min) {
 
7561
#ifdef DEBUG_DERIV
 
7562
                            printf("Infinite loops Okay => COUNT(0,Inf)\n");
 
7563
#endif
 
7564
                            max = -1;
 
7565
                            min = 0;
 
7566
                        } else {
 
7567
#ifdef DEBUG_DERIV
 
7568
                            printf("Infinite loops min => Count(X,Inf)\n");
 
7569
#endif
 
7570
                            max = -1;
 
7571
                            min = exp->exp_min - sub->exp_min;
 
7572
                        }
 
7573
                    } else if (exp->exp_min > sub->exp_min) {
 
7574
#ifdef DEBUG_DERIV
 
7575
                        printf("loops min mismatch 1 => forbidden ???\n");
 
7576
#endif
 
7577
                        xmlExpFree(ctxt, tmp);
 
7578
                        return(forbiddenExp);
 
7579
                    } else {
 
7580
                        max = -1;
 
7581
                        min = 0;
 
7582
                    }
 
7583
                } else {
 
7584
                    if (exp->exp_max == -1) {
 
7585
#ifdef DEBUG_DERIV
 
7586
                        printf("Infinite loop consume finite loop\n");
 
7587
#endif
 
7588
                        if (exp->exp_min > sub->exp_min) {
 
7589
                            max = -1;
 
7590
                            min = exp->exp_min - sub->exp_min;
 
7591
                        } else {
 
7592
                            max = -1;
 
7593
                            min = 0;
 
7594
                        }
 
7595
                    } else {
 
7596
                        if (exp->exp_max < sub->exp_max) {
 
7597
#ifdef DEBUG_DERIV
 
7598
                            printf("loops max mismatch => forbidden\n");
 
7599
#endif
 
7600
                            xmlExpFree(ctxt, tmp);
 
7601
                            return(forbiddenExp);
 
7602
                        }
 
7603
                        if (sub->exp_max > exp->exp_min)
 
7604
                            min = 0;
 
7605
                        else
 
7606
                            min = exp->exp_min - sub->exp_max;
 
7607
                        max = exp->exp_max - sub->exp_max;
 
7608
                    }
 
7609
                }
 
7610
#ifdef DEBUG_DERIV
 
7611
                printf("loops match => SEQ(COUNT())\n");
 
7612
#endif
 
7613
                exp->exp_left->ref++;
 
7614
                tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left,
 
7615
                                          NULL, NULL, min, max);
 
7616
                if (tmp2 == NULL) {
 
7617
                    return(NULL);
 
7618
                }
 
7619
                ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, tmp, tmp2,
 
7620
                                         NULL, 0, 0);
 
7621
                return(ret);
 
7622
            }
 
7623
            tmp = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub);
 
7624
            if (tmp == NULL)
 
7625
                return(NULL);
 
7626
            if (tmp == forbiddenExp) {
 
7627
#ifdef DEBUG_DERIV
 
7628
                printf("loop mismatch => forbidden\n");
 
7629
#endif
 
7630
                return(forbiddenExp);
 
7631
            }
 
7632
            if (exp->exp_min > 0)
 
7633
                min = exp->exp_min - 1;
 
7634
            else
 
7635
                min = 0;
 
7636
            if (exp->exp_max < 0)
 
7637
                max = -1;
 
7638
            else
 
7639
                max = exp->exp_max - 1;
 
7640
 
 
7641
#ifdef DEBUG_DERIV
 
7642
            printf("loop match => SEQ(COUNT())\n");
 
7643
#endif
 
7644
            exp->exp_left->ref++;
 
7645
            tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left,
 
7646
                                      NULL, NULL, min, max);
 
7647
            if (tmp2 == NULL)
 
7648
                return(NULL);
 
7649
            ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, tmp, tmp2,
 
7650
                                     NULL, 0, 0);
 
7651
            return(ret);
 
7652
        }
 
7653
    }
 
7654
 
 
7655
#ifdef DEBUG_DERIV
 
7656
    printf("Fallback to derivative\n");
 
7657
#endif
 
7658
    if (IS_NILLABLE(sub)) {
 
7659
        if (!(IS_NILLABLE(exp)))
 
7660
            return(forbiddenExp);
 
7661
        else
 
7662
            ret = emptyExp;
 
7663
    } else
 
7664
        ret = NULL;
 
7665
    /*
 
7666
     * here the structured derivation made no progress so
 
7667
     * we use the default token based derivation to force one more step
 
7668
     */
 
7669
    if (ctxt->tabSize == 0)
 
7670
        ctxt->tabSize = 40;
 
7671
 
 
7672
    tab = (const xmlChar **) xmlMalloc(ctxt->tabSize *
 
7673
                                       sizeof(const xmlChar *));
 
7674
    if (tab == NULL) {
 
7675
        return(NULL);
 
7676
    }
 
7677
 
 
7678
    /*
 
7679
     * collect all the strings accepted by the subexpression on input
 
7680
     */
 
7681
    len = xmlExpGetStartInt(ctxt, sub, tab, ctxt->tabSize, 0);
 
7682
    while (len < 0) {
 
7683
        const xmlChar **temp;
 
7684
        temp = (const xmlChar **) xmlRealloc((xmlChar **) tab, ctxt->tabSize * 2 *
 
7685
                                             sizeof(const xmlChar *));
 
7686
        if (temp == NULL) {
 
7687
            xmlFree((xmlChar **) tab);
 
7688
            return(NULL);
 
7689
        }
 
7690
        tab = temp;
 
7691
        ctxt->tabSize *= 2;
 
7692
        len = xmlExpGetStartInt(ctxt, sub, tab, ctxt->tabSize, 0);
 
7693
    }
 
7694
    for (i = 0;i < len;i++) {
 
7695
        tmp = xmlExpStringDeriveInt(ctxt, exp, tab[i]);
 
7696
        if ((tmp == NULL) || (tmp == forbiddenExp)) {
 
7697
            xmlExpFree(ctxt, ret);
 
7698
            xmlFree((xmlChar **) tab);
 
7699
            return(tmp);
 
7700
        }
 
7701
        tmp2 = xmlExpStringDeriveInt(ctxt, sub, tab[i]);
 
7702
        if ((tmp2 == NULL) || (tmp2 == forbiddenExp)) {
 
7703
            xmlExpFree(ctxt, tmp);
 
7704
            xmlExpFree(ctxt, ret);
 
7705
            xmlFree((xmlChar **) tab);
 
7706
            return(tmp);
 
7707
        }
 
7708
        tmp3 = xmlExpExpDeriveInt(ctxt, tmp, tmp2);
 
7709
        xmlExpFree(ctxt, tmp);
 
7710
        xmlExpFree(ctxt, tmp2);
 
7711
 
 
7712
        if ((tmp3 == NULL) || (tmp3 == forbiddenExp)) {
 
7713
            xmlExpFree(ctxt, ret);
 
7714
            xmlFree((xmlChar **) tab);
 
7715
            return(tmp3);
 
7716
        }
 
7717
 
 
7718
        if (ret == NULL)
 
7719
            ret = tmp3;
 
7720
        else {
 
7721
            ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, tmp3, NULL, 0, 0);
 
7722
            if (ret == NULL) {
 
7723
                xmlFree((xmlChar **) tab);
 
7724
                return(NULL);
 
7725
            }
 
7726
        }
 
7727
    }
 
7728
    xmlFree((xmlChar **) tab);
 
7729
    return(ret);
 
7730
}
 
7731
    
 
7732
/**
 
7733
 * xmlExpExpDerive:
 
7734
 * @ctxt: the expressions context
 
7735
 * @exp: the englobing expression
 
7736
 * @sub: the subexpression
 
7737
 *
 
7738
 * Evaluates the expression resulting from @exp consuming a sub expression @sub
 
7739
 * Based on algebraic derivation and sometimes direct Brzozowski derivation
 
7740
 * it usually tatkes less than linear time and can handle expressions generating
 
7741
 * infinite languages.
 
7742
 *
 
7743
 * Returns the resulting expression or NULL in case of internal error, the
 
7744
 *         result must be freed
 
7745
 */
 
7746
xmlExpNodePtr
 
7747
xmlExpExpDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) {
 
7748
    if ((exp == NULL) || (ctxt == NULL) || (sub == NULL))
 
7749
        return(NULL);
 
7750
 
 
7751
    /*
 
7752
     * O(1) speedups
 
7753
     */
 
7754
    if (IS_NILLABLE(sub) && (!IS_NILLABLE(exp))) {
 
7755
#ifdef DEBUG_DERIV
 
7756
        printf("Sub nillable and not exp : can't subsume\n");
 
7757
#endif
 
7758
        return(forbiddenExp);
 
7759
    }
 
7760
    if (xmlExpCheckCard(exp, sub) == 0) {
 
7761
#ifdef DEBUG_DERIV
 
7762
        printf("sub generate longuer sequances than exp : can't subsume\n");
 
7763
#endif
 
7764
        return(forbiddenExp);
 
7765
    }
 
7766
    return(xmlExpExpDeriveInt(ctxt, exp, sub));
 
7767
}
 
7768
 
 
7769
/**
 
7770
 * xmlExpSubsume:
 
7771
 * @ctxt: the expressions context
 
7772
 * @exp: the englobing expression
 
7773
 * @sub: the subexpression
 
7774
 *
 
7775
 * Check whether @exp accepts all the languages accexpted by @sub
 
7776
 * the input being a subexpression.
 
7777
 *
 
7778
 * Returns 1 if true 0 if false and -1 in case of failure.
 
7779
 */
 
7780
int
 
7781
xmlExpSubsume(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) {
 
7782
    xmlExpNodePtr tmp;
 
7783
    
 
7784
    if ((exp == NULL) || (ctxt == NULL) || (sub == NULL))
 
7785
        return(-1);
 
7786
 
 
7787
    /*
 
7788
     * TODO: speedup by checking the language of sub is a subset of the
 
7789
     *       language of exp
 
7790
     */
 
7791
    /*
 
7792
     * O(1) speedups
 
7793
     */
 
7794
    if (IS_NILLABLE(sub) && (!IS_NILLABLE(exp))) {
 
7795
#ifdef DEBUG_DERIV
 
7796
        printf("Sub nillable and not exp : can't subsume\n");
 
7797
#endif
 
7798
        return(0);
 
7799
    }
 
7800
    if (xmlExpCheckCard(exp, sub) == 0) {
 
7801
#ifdef DEBUG_DERIV
 
7802
        printf("sub generate longuer sequances than exp : can't subsume\n");
 
7803
#endif
 
7804
        return(0);
 
7805
    }
 
7806
    tmp = xmlExpExpDeriveInt(ctxt, exp, sub);
 
7807
#ifdef DEBUG_DERIV
 
7808
    printf("Result derivation :\n");
 
7809
    PRINT_EXP(tmp);
 
7810
#endif
 
7811
    if (tmp == NULL)
 
7812
        return(-1);
 
7813
    if (tmp == forbiddenExp)
 
7814
        return(0);
 
7815
    if (tmp == emptyExp)
 
7816
        return(1);
 
7817
    if ((tmp != NULL) && (IS_NILLABLE(tmp))) {
 
7818
        xmlExpFree(ctxt, tmp);
 
7819
        return(1);
 
7820
    }
 
7821
    xmlExpFree(ctxt, tmp);
 
7822
    return(0);
 
7823
}
 
7824
 
 
7825
/************************************************************************
 
7826
 *                                                                      *
 
7827
 *                      Parsing expression                              *
 
7828
 *                                                                      *
 
7829
 ************************************************************************/
 
7830
 
 
7831
static xmlExpNodePtr xmlExpParseExpr(xmlExpCtxtPtr ctxt);
 
7832
 
 
7833
#undef CUR
 
7834
#define CUR (*ctxt->cur)
 
7835
#undef NEXT
 
7836
#define NEXT ctxt->cur++;
 
7837
#undef IS_BLANK
 
7838
#define IS_BLANK(c) ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))
 
7839
#define SKIP_BLANKS while (IS_BLANK(*ctxt->cur)) ctxt->cur++;
 
7840
 
 
7841
static int
 
7842
xmlExpParseNumber(xmlExpCtxtPtr ctxt) {
 
7843
    int ret = 0;
 
7844
 
 
7845
    SKIP_BLANKS
 
7846
    if (CUR == '*') {
 
7847
        NEXT
 
7848
        return(-1);
 
7849
    }
 
7850
    if ((CUR < '0') || (CUR > '9'))
 
7851
        return(-1);
 
7852
    while ((CUR >= '0') && (CUR <= '9')) {
 
7853
        ret = ret * 10 + (CUR - '0');
 
7854
        NEXT
 
7855
    }
 
7856
    return(ret);
 
7857
}
 
7858
 
 
7859
static xmlExpNodePtr
 
7860
xmlExpParseOr(xmlExpCtxtPtr ctxt) {
 
7861
    const char *base;
 
7862
    xmlExpNodePtr ret;
 
7863
    const xmlChar *val;
 
7864
 
 
7865
    SKIP_BLANKS
 
7866
    base = ctxt->cur;
 
7867
    if (*ctxt->cur == '(') {
 
7868
        NEXT
 
7869
        ret = xmlExpParseExpr(ctxt);
 
7870
        SKIP_BLANKS
 
7871
        if (*ctxt->cur != ')') {
 
7872
            fprintf(stderr, "unbalanced '(' : %s\n", base);
 
7873
            xmlExpFree(ctxt, ret);
 
7874
            return(NULL);
 
7875
        }
 
7876
        NEXT;
 
7877
        SKIP_BLANKS
 
7878
        goto parse_quantifier;
 
7879
    }
 
7880
    while ((CUR != 0) && (!(IS_BLANK(CUR))) && (CUR != '(') &&
 
7881
           (CUR != ')') && (CUR != '|') && (CUR != ',') && (CUR != '{') &&
 
7882
           (CUR != '*') && (CUR != '+') && (CUR != '?') && (CUR != '}'))
 
7883
        NEXT;
 
7884
    val = xmlDictLookup(ctxt->dict, BAD_CAST base, ctxt->cur - base);
 
7885
    if (val == NULL)
 
7886
        return(NULL);
 
7887
    ret = xmlExpHashGetEntry(ctxt, XML_EXP_ATOM, NULL, NULL, val, 0, 0);
 
7888
    if (ret == NULL)
 
7889
        return(NULL);
 
7890
    SKIP_BLANKS
 
7891
parse_quantifier:
 
7892
    if (CUR == '{') {
 
7893
        int min, max;
 
7894
 
 
7895
        NEXT
 
7896
        min = xmlExpParseNumber(ctxt);
 
7897
        if (min < 0) {
 
7898
            xmlExpFree(ctxt, ret);
 
7899
            return(NULL);
 
7900
        }
 
7901
        SKIP_BLANKS
 
7902
        if (CUR == ',') {
 
7903
            NEXT
 
7904
            max = xmlExpParseNumber(ctxt);
 
7905
            SKIP_BLANKS
 
7906
        } else
 
7907
            max = min;
 
7908
        if (CUR != '}') {
 
7909
            xmlExpFree(ctxt, ret);
 
7910
            return(NULL);
 
7911
        }
 
7912
        NEXT
 
7913
        ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
 
7914
                                 min, max);
 
7915
        SKIP_BLANKS
 
7916
    } else if (CUR == '?') {
 
7917
        NEXT
 
7918
        ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
 
7919
                                 0, 1);
 
7920
        SKIP_BLANKS
 
7921
    } else if (CUR == '+') {
 
7922
        NEXT
 
7923
        ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
 
7924
                                 1, -1);
 
7925
        SKIP_BLANKS
 
7926
    } else if (CUR == '*') {
 
7927
        NEXT
 
7928
        ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL,
 
7929
                                 0, -1);
 
7930
        SKIP_BLANKS
 
7931
    } 
 
7932
    return(ret);
 
7933
}
 
7934
 
 
7935
 
 
7936
static xmlExpNodePtr
 
7937
xmlExpParseSeq(xmlExpCtxtPtr ctxt) {
 
7938
    xmlExpNodePtr ret, right;
 
7939
 
 
7940
    ret = xmlExpParseOr(ctxt);
 
7941
    SKIP_BLANKS
 
7942
    while (CUR == '|') {
 
7943
        NEXT
 
7944
        right = xmlExpParseOr(ctxt);
 
7945
        if (right == NULL) {
 
7946
            xmlExpFree(ctxt, ret);
 
7947
            return(NULL);
 
7948
        }
 
7949
        ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, right, NULL, 0, 0);
 
7950
        if (ret == NULL)
 
7951
            return(NULL);
 
7952
    }
 
7953
    return(ret);
 
7954
}
 
7955
 
 
7956
static xmlExpNodePtr
 
7957
xmlExpParseExpr(xmlExpCtxtPtr ctxt) {
 
7958
    xmlExpNodePtr ret, right;
 
7959
 
 
7960
    ret = xmlExpParseSeq(ctxt);
 
7961
    SKIP_BLANKS
 
7962
    while (CUR == ',') {
 
7963
        NEXT
 
7964
        right = xmlExpParseSeq(ctxt);
 
7965
        if (right == NULL) {
 
7966
            xmlExpFree(ctxt, ret);
 
7967
            return(NULL);
 
7968
        }
 
7969
        ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, right, NULL, 0, 0);
 
7970
        if (ret == NULL)
 
7971
            return(NULL);
 
7972
    }
 
7973
    return(ret);
 
7974
}
 
7975
 
 
7976
/**
 
7977
 * xmlExpParse:
 
7978
 * @ctxt: the expressions context
 
7979
 * @expr: the 0 terminated string
 
7980
 *
 
7981
 * Minimal parser for regexps, it understand the following constructs
 
7982
 *  - string terminals
 
7983
 *  - choice operator |
 
7984
 *  - sequence operator ,
 
7985
 *  - subexpressions (...)
 
7986
 *  - usual cardinality operators + * and ?
 
7987
 *  - finite sequences  { min, max }
 
7988
 *  - infinite sequences { min, * }
 
7989
 * There is minimal checkings made especially no checking on strings values
 
7990
 *
 
7991
 * Returns a new expression or NULL in case of failure
 
7992
 */
 
7993
xmlExpNodePtr
 
7994
xmlExpParse(xmlExpCtxtPtr ctxt, const char *expr) {
 
7995
    xmlExpNodePtr ret;
 
7996
 
 
7997
    ctxt->expr = expr;
 
7998
    ctxt->cur = expr;
 
7999
 
 
8000
    ret = xmlExpParseExpr(ctxt);
 
8001
    SKIP_BLANKS
 
8002
    if (*ctxt->cur != 0) {
 
8003
        xmlExpFree(ctxt, ret);
 
8004
        return(NULL);
 
8005
    }
 
8006
    return(ret);
 
8007
}
 
8008
 
 
8009
static void
 
8010
xmlExpDumpInt(xmlBufferPtr buf, xmlExpNodePtr expr, int glob) {
 
8011
    xmlExpNodePtr c;
 
8012
 
 
8013
    if (expr == NULL) return;
 
8014
    if (glob) xmlBufferWriteChar(buf, "(");
 
8015
    switch (expr->type) {
 
8016
        case XML_EXP_EMPTY:
 
8017
            xmlBufferWriteChar(buf, "empty");
 
8018
            break;
 
8019
        case XML_EXP_FORBID:
 
8020
            xmlBufferWriteChar(buf, "forbidden");
 
8021
            break;
 
8022
        case XML_EXP_ATOM:
 
8023
            xmlBufferWriteCHAR(buf, expr->exp_str);
 
8024
            break;
 
8025
        case XML_EXP_SEQ:
 
8026
            c = expr->exp_left;
 
8027
            if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
 
8028
                xmlExpDumpInt(buf, c, 1);
 
8029
            else
 
8030
                xmlExpDumpInt(buf, c, 0);
 
8031
            xmlBufferWriteChar(buf, " , ");
 
8032
            c = expr->exp_right;
 
8033
            if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
 
8034
                xmlExpDumpInt(buf, c, 1);
 
8035
            else
 
8036
                xmlExpDumpInt(buf, c, 0);
 
8037
            break;
 
8038
        case XML_EXP_OR:
 
8039
            c = expr->exp_left;
 
8040
            if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
 
8041
                xmlExpDumpInt(buf, c, 1);
 
8042
            else
 
8043
                xmlExpDumpInt(buf, c, 0);
 
8044
            xmlBufferWriteChar(buf, " | ");
 
8045
            c = expr->exp_right;
 
8046
            if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
 
8047
                xmlExpDumpInt(buf, c, 1);
 
8048
            else
 
8049
                xmlExpDumpInt(buf, c, 0);
 
8050
            break;
 
8051
        case XML_EXP_COUNT: {
 
8052
            char rep[40];
 
8053
            
 
8054
            c = expr->exp_left;
 
8055
            if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR))
 
8056
                xmlExpDumpInt(buf, c, 1);
 
8057
            else
 
8058
                xmlExpDumpInt(buf, c, 0);
 
8059
            if ((expr->exp_min == 0) && (expr->exp_max == 1)) {
 
8060
                rep[0] = '?';
 
8061
                rep[1] = 0;
 
8062
            } else if ((expr->exp_min == 0) && (expr->exp_max == -1)) {
 
8063
                rep[0] = '*';
 
8064
                rep[1] = 0;
 
8065
            } else if ((expr->exp_min == 1) && (expr->exp_max == -1)) {
 
8066
                rep[0] = '+';
 
8067
                rep[1] = 0;
 
8068
            } else if (expr->exp_max == expr->exp_min) {
 
8069
                snprintf(rep, 39, "{%d}", expr->exp_min);
 
8070
            } else if (expr->exp_max < 0) {
 
8071
                snprintf(rep, 39, "{%d,inf}", expr->exp_min);
 
8072
            } else {
 
8073
                snprintf(rep, 39, "{%d,%d}", expr->exp_min, expr->exp_max);
 
8074
            }
 
8075
            rep[39] = 0;
 
8076
            xmlBufferWriteChar(buf, rep);
 
8077
            break;
 
8078
        }
 
8079
        default:
 
8080
            fprintf(stderr, "Error in tree\n");
 
8081
    }
 
8082
    if (glob)
 
8083
        xmlBufferWriteChar(buf, ")");
 
8084
}
 
8085
/**
 
8086
 * xmlExpDump:
 
8087
 * @buf:  a buffer to receive the output
 
8088
 * @expr:  the compiled expression
 
8089
 *
 
8090
 * Serialize the expression as compiled to the buffer
 
8091
 */
 
8092
void
 
8093
xmlExpDump(xmlBufferPtr buf, xmlExpNodePtr expr) {
 
8094
    if ((buf == NULL) || (expr == NULL))
 
8095
        return;
 
8096
    xmlExpDumpInt(buf, expr, 0);
 
8097
}
 
8098
 
 
8099
/**
 
8100
 * xmlExpMaxToken:
 
8101
 * @expr: a compiled expression
 
8102
 *
 
8103
 * Indicate the maximum number of input a expression can accept
 
8104
 *
 
8105
 * Returns the maximum length or -1 in case of error
 
8106
 */
 
8107
int
 
8108
xmlExpMaxToken(xmlExpNodePtr expr) {
 
8109
    if (expr == NULL)
 
8110
        return(-1);
 
8111
    return(expr->c_max);
 
8112
}
 
8113
 
 
8114
/**
 
8115
 * xmlExpCtxtNbNodes:
 
8116
 * @ctxt: an expression context
 
8117
 *
 
8118
 * Debugging facility provides the number of allocated nodes at a that point
 
8119
 *
 
8120
 * Returns the number of nodes in use or -1 in case of error
 
8121
 */
 
8122
int
 
8123
xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt) {
 
8124
    if (ctxt == NULL)
 
8125
        return(-1);
 
8126
    return(ctxt->nb_nodes);
 
8127
}
 
8128
 
 
8129
/**
 
8130
 * xmlExpCtxtNbCons:
 
8131
 * @ctxt: an expression context
 
8132
 *
 
8133
 * Debugging facility provides the number of allocated nodes over lifetime
 
8134
 *
 
8135
 * Returns the number of nodes ever allocated or -1 in case of error
 
8136
 */
 
8137
int
 
8138
xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt) {
 
8139
    if (ctxt == NULL)
 
8140
        return(-1);
 
8141
    return(ctxt->nb_cons);
 
8142
}
 
8143
 
 
8144
#endif /* LIBXML_EXPR_ENABLED */
 
8145
#define bottom_xmlregexp
 
8146
#include "elfgcchack.h"
 
8147
#endif /* LIBXML_REGEXP_ENABLED */