Logo Search packages:      
Sourcecode: x11-apps version File versions  Download package

rec.c

/*
 * Copyright (c) 2002 by The XFree86 Project, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Except as contained in this notice, the name of the XFree86 Project shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from the
 * XFree86 Project.
 *
 * Author: Paulo C├ęsar Pereira de Andrade
 */

/* $XFree86: xc/programs/xedit/lisp/re/rec.c,v 1.3 2002/11/15 07:01:33 paulo Exp $ */

#include "rep.h"

/*
 * Types
 */

/*  Information used while compiling the intermediate format of the re. */
typedef struct _irec_info {
    unsigned char *ptr;       /* Pointer in the given regex pattern */
    unsigned char *end;       /* End of regex pattern */
    int flags;                /* Compile flags */
    rec_alt *alt;       /* Toplevel first/single alternative */

    rec_alt *palt;            /* Current alternative being compiled */
    rec_grp *pgrp;            /* Current group, if any */
    rec_pat *ppat;            /* Current pattern, if any */

    /*  Number of open parenthesis, for error checking */
    int nparens;

    int ngrps;                /* Number of groups, for backreference */

    int ecode;
} irec_info;


/*
 * Prototypes
 */

      /* (i)ntermediate (r)egular (e)xpression (c)ompile
       *  Generates an intermediate stage compiled regex from
       * the specified pattern argument. Basically builds an
       * intermediate data structure to analyse and do syntax
       * error checking.
       */
static void irec_simple_pattern(irec_info*, rec_pat_t);
static void irec_literal_pattern(irec_info*, int);
static void irec_case_literal_pattern(irec_info*, int);
static void irec_open_group(irec_info*);
static void irec_close_group(irec_info*);
static void irec_range(irec_info*);
static void irec_range_single(irec_info*, int);
static void irec_range_complex(irec_info*, int, int);
static void irec_escape(irec_info*);
static void irec_simple_repetition(irec_info*, rec_rep_t);
static void irec_complex_repetition(irec_info*);
static void irec_add_repetition(irec_info*, rec_rep*);
static void irec_free(irec_info*);
static void irec_free_grp(rec_grp*);
static void irec_free_pats(rec_pat*);


/*
 * Implementation
 */
rec_alt *
irec_comp(const char *pattern, const char *endp, int flags, int *ecode)
{
    unsigned char *ptr;
    rec_alt *alt;
    irec_info inf;

    if (pattern == NULL || endp < pattern) {
      *ecode = RE_INVARG;
      return (NULL);
    }

    if (endp == pattern) {
      *ecode = RE_EMPTY;
      return (NULL);
    }

    alt = calloc(1, sizeof(rec_alt));
    if (alt == NULL) {
      *ecode = RE_ESPACE;
      return (NULL);
    }

    inf.ptr = (unsigned char*)pattern;
    inf.end = (unsigned char*)endp;
    inf.flags = flags;
    inf.alt = inf.palt = alt;
    inf.pgrp = NULL;
    inf.ppat = NULL;
    inf.nparens = inf.ngrps = 0;
    inf.ecode = 0;

    if (flags & RE_NOSPEC) {
      /* Just searching for a character or substring */
      for (; inf.ecode == 0 && inf.ptr < inf.end; inf.ptr++) {
          if (!(flags & RE_ICASE) ||
            (!isupper(*inf.ptr) && !islower(*inf.ptr)))
            irec_literal_pattern(&inf, *inf.ptr);
          else
            irec_case_literal_pattern(&inf, *inf.ptr);
      }
    }
    /* inf.ptr = inf.end is nul if flags & RE_NOSPEC */
    for (; inf.ecode == 0 && inf.ptr < inf.end;) {
      switch (*inf.ptr++) {
          case '*':
            irec_simple_repetition(&inf, Rer_AnyTimes);
            break;
          case '+':
            irec_simple_repetition(&inf, Rer_AtLeast);
            break;
          case '?':
            irec_simple_repetition(&inf, Rer_Maybe);
            break;
          case '.':
            irec_simple_pattern(&inf, Rep_Any);
            break;
          case '^':
            if (flags & RE_NEWLINE)
                /* It is up to the user decide if this can match */
                irec_simple_pattern(&inf, Rep_Bol);
            else {
                for (ptr = inf.ptr - 1;
                   ptr > (unsigned char*)pattern && *ptr == '('; ptr--)
                  ;
                /* If at the start of a pattern */
                if (ptr == (unsigned char*)pattern || *ptr == '|')
                  irec_simple_pattern(&inf, Rep_Bol);
                else
                  /* In the middle of a pattern, treat as literal */
                  irec_literal_pattern(&inf, '^');
            }
            break;
          case '$':
            if (flags & RE_NEWLINE)
                irec_simple_pattern(&inf, Rep_Eol);
            else {
                /* Look ahead to check if is the last char of a group */
                for (ptr = inf.ptr; ptr < inf.end && *ptr == ')'; ptr++)
                  ;
                if (*ptr == '\0' || *ptr == '|')
                  /* Last character of pattern, an EOL match */
                  irec_simple_pattern(&inf, Rep_Eol);
                else
                  /* Normal character */
                  irec_literal_pattern(&inf, '$');
            }
            break;
          case '(':
            irec_open_group(&inf);
            break;
          case ')':
            /* Look ahead to check if need to close the group now */
            ptr = inf.ptr;
            if (*ptr != '*' && *ptr != '+' && *ptr != '?' && *ptr != '{')
                /* If a repetition does not follow */
                irec_close_group(&inf);
            else if (inf.pgrp == NULL)
                /* A repetition follows, but current group is implicit */
                inf.ecode = RE_EPAREN;
            else
                /* Can do this as next character is known */
                inf.ppat = NULL;
            break;
          case '[':
            irec_range(&inf);
            break;
          case ']':
            irec_literal_pattern(&inf, ']');
            break;
          case '{':
            irec_complex_repetition(&inf);
            break;
          case '}':
            irec_literal_pattern(&inf, '}');
            break;
          case '|':
                /* If first character in the pattern */
            if (inf.ptr - 1 == (unsigned char*)pattern ||
                /* If last character in the pattern */
                inf.ptr >= inf.end ||
                /* If empty pattern */
                inf.ptr[0] == '|' ||
                inf.ptr[0] == ')')
                inf.ecode = RE_EMPTY;
            else {
                rec_alt *alt = calloc(1, sizeof(rec_alt));

                if (alt) {
                  alt->prev = inf.palt;
                  inf.palt->next = alt;
                  inf.palt = alt;
                  inf.ppat = NULL;
                }
                else
                  inf.ecode = RE_ESPACE;
            }
            break;
          case '\\':
            irec_escape(&inf);
            break;
          default:
            if (!(flags & RE_ICASE) ||
                (!isupper(inf.ptr[-1]) && !islower(inf.ptr[-1])))
                irec_literal_pattern(&inf, inf.ptr[-1]);
            else
                irec_case_literal_pattern(&inf, inf.ptr[-1]);
            break;
      }
    }

    /* Check if not all groups closed */
    if (inf.ecode == 0 && inf.nparens)
      inf.ecode = RE_EPAREN;

    if (inf.ecode == 0)
      inf.ecode = orec_comp(inf.alt, flags);

    /* If an error generated */
    if (inf.ecode) {
      irec_free(&inf);
      alt = NULL;
    }

    *ecode = inf.ecode;

    return (alt);
}

void
irec_free_alt(rec_alt *alt)
{
    rec_alt *next;

    while (alt) {
      next = alt->next;
      irec_free_pats(alt->pat);
      free(alt);
      alt = next;
    }
}



static void
irec_simple_pattern(irec_info *inf, rec_pat_t type)
{
    rec_pat *pat;

    /* Always add a new pattern to list */
    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
      inf->ecode = RE_ESPACE;
      return;
    }

    pat->type = type;
    if ((pat->prev = inf->ppat) != NULL)
      inf->ppat->next = pat;
    else
      inf->palt->pat = pat;
    inf->ppat = pat;
}

static void
irec_literal_pattern(irec_info *inf, int value)
{
    int length;
    rec_pat *pat;
    unsigned char chr, *str;

      /* If there is a current pattern */
    if (inf->ppat && inf->ppat->rep == NULL) {
      switch (inf->ppat->type) {
          case Rep_Literal:
            /* Start literal string */
            chr = inf->ppat->data.chr;
            if ((str = malloc(16)) == NULL) {
                inf->ecode = RE_ESPACE;
                return;
            }
            inf->ppat->type = Rep_String;
            inf->ppat->data.str = str;
            str[0] = chr;
            str[1] = value;
            str[2] = '\0';
            return;

          case Rep_String:
            /* Augments literal string */
            length = strlen((char*)inf->ppat->data.str);
            if ((length % 16) >= 14) {
                if ((str = realloc(inf->ppat->data.str,
                               length + 18)) == NULL) {
                  inf->ecode = RE_ESPACE;
                  return;
                }
                inf->ppat->data.str = str;
            }
            inf->ppat->data.str[length] = value;
            inf->ppat->data.str[length + 1] = '\0';
            return;

          default:
            /* Anything else is added as a new pattern list element */
            break;
      }
    }

    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
      inf->ecode = RE_ESPACE;
      return;
    }

    pat->type = Rep_Literal;
    pat->data.chr = value;
    if ((pat->prev = inf->ppat) != NULL)
      inf->ppat->next = pat;
    else
      inf->palt->pat = pat;
    inf->ppat = pat;
}

static void
irec_case_literal_pattern(irec_info *inf, int value)
{
    int length;
    rec_pat *pat;
    unsigned char plower, pupper, lower, upper, *str;

    lower = tolower(value);
    upper = toupper(value);

      /* If there is a current pattern */
    if (inf->ppat && inf->ppat->rep == NULL) {
      switch (inf->ppat->type) {
          case Rep_CaseLiteral:
            /* Start case literal string */
            plower = inf->ppat->data.cse.lower;
            pupper = inf->ppat->data.cse.upper;
            if ((str = malloc(32)) == NULL) {
                inf->ecode = RE_ESPACE;
                return;
            }
            inf->ppat->type = Rep_CaseString;
            inf->ppat->data.str = str;
            str[0] = plower;
            str[1] = pupper;
            str[2] = lower;
            str[3] = upper;
            str[4] = '\0';
            return;

          case Rep_CaseString:
            /* Augments case literal string */
            length = strlen((char*)inf->ppat->data.str);
            if (((length) % 32) >= 28) {
                if ((str = realloc(inf->ppat->data.str,
                               length + 36)) == NULL) {
                  inf->ecode = RE_ESPACE;
                  return;
                }
                inf->ppat->data.str = str;
            }
            inf->ppat->data.str[length] = lower;
            inf->ppat->data.str[length + 1] = upper;
            inf->ppat->data.str[length + 2] = '\0';
            return;

          default:
            /* Anything else is added as a new pattern list element */
            break;
      }
    }

    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
      inf->ecode = RE_ESPACE;
      return;
    }

    pat->type = Rep_CaseLiteral;
    pat->data.cse.lower = lower;
    pat->data.cse.upper = upper;
    pat->prev = inf->ppat;
    if ((pat->prev = inf->ppat) != NULL)
      inf->ppat->next = pat;
    else
      inf->palt->pat = pat;
    inf->ppat = pat;
}

static void
irec_open_group(irec_info *inf)
{
    rec_pat *pat;
    rec_alt *alt;
    rec_grp *grp;

    if ((grp = calloc(1, sizeof(rec_grp))) == NULL) {
      inf->ecode = RE_ESPACE;
      return;
    }

    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
      free(grp);
      inf->ecode = RE_ESPACE;
      return;
    }

    if ((alt = calloc(1, sizeof(rec_alt))) == NULL) {
      free(grp);
      free(pat);
      inf->ecode = RE_ESPACE;
      return;
    }

    pat->type = Rep_Group;
    pat->data.grp = grp;
    grp->parent = pat;
    grp->palt = inf->palt;
    grp->pgrp = inf->pgrp;
    grp->alt = alt;
    grp->comp = 0;
    if ((pat->prev = inf->ppat) != NULL)
      inf->ppat->next = pat;
    else
      inf->palt->pat = pat;
    inf->palt = alt;
    inf->ppat = NULL;

    /* Only toplevel parenthesis supported */
    if (++inf->nparens == 1)
      ++inf->ngrps;

    inf->pgrp = grp;
}

static void
irec_close_group(irec_info *inf)
{
    if (inf->pgrp == NULL) {
      inf->ecode = RE_EPAREN;
      return;
    }

    inf->palt = inf->pgrp->palt;
    inf->ppat = inf->pgrp->parent;
    inf->pgrp = inf->pgrp->pgrp;

    --inf->nparens;
}

static void
irec_range(irec_info *inf)
{
    int count;
    rec_pat *pat;
    rec_rng *rng;
    int not = inf->ptr[0] == '^';

    if (not)
      ++inf->ptr;

    pat = calloc(1, sizeof(rec_pat));
    if (pat == NULL) {
      inf->ecode = RE_ESPACE;
      return;
    }

    rng = calloc(1, sizeof(rec_rng));
    if (pat == NULL) {
      free(pat);
      inf->ecode = RE_ESPACE;
      return;
    }

    pat->data.rng = rng;
    pat->type = not ? Rep_RangeNot : Rep_Range;
    if ((pat->prev = inf->ppat) != NULL)
      inf->ppat->next = pat;
    else
      inf->palt->pat = pat;
    inf->ppat = pat;

    /* First pass, add everything seen */
    for (count = 0; inf->ecode == 0; count++) {
      /* If bracket not closed */
      if (inf->ptr == inf->end) {
          inf->ecode = RE_EBRACK;
          return;
      }
      /* If not the first character */
      else if (inf->ptr[0] == ']' && count)
          break;
      else {
          /* If not a range of characters */
          if (inf->ptr[1] != '-' || inf->ptr[2] == ']') {
            irec_range_single(inf, inf->ptr[0]);
            ++inf->ptr;
          }
          else {
            if ((inf->flags & RE_NEWLINE) &&
                inf->ptr[0] < '\n' && inf->ptr[2] > '\n') {
                /*  Unless it is forced to be a delimiter, don't allow
                 * a newline in a character range */
                if (inf->ptr[0] == '\n' - 1)
                  irec_range_single(inf, inf->ptr[0]);
                else
                  irec_range_complex(inf, inf->ptr[0], '\n' - 1);
                if (inf->ptr[2] == '\n' + 1)
                  irec_range_single(inf, inf->ptr[2]);
                else
                  irec_range_complex(inf, '\n' + 1, inf->ptr[2]);
            }
            else
                irec_range_complex(inf, inf->ptr[0], inf->ptr[2]);
            inf->ptr += 3;
          }
      }
    }

    /* Skip ] */
    ++inf->ptr;
}

static void
irec_range_single(irec_info *inf, int value)
{
    if (value >= 0 && value <= 255)
      inf->ppat->data.rng->range[value] = 1;

    if (inf->flags & RE_ICASE) {
      if (islower(value)) {
          value = toupper(value);
          if (value >= 0 && value <= 255)
            inf->ppat->data.rng->range[value] = 1;
      }
      else if (isupper(value)) {
          value = tolower(value);
          if (value >= 0 && value <= 255)
            inf->ppat->data.rng->range[value] = 1;
      }
    }
}

static void
irec_range_complex(irec_info *inf, int chrf, int chrt)
{
    if (chrf > chrt) {
      inf->ecode = RE_ERANGE;
      return;
    }

    for (; chrf <= chrt; chrf++)
      irec_range_single(inf, chrf);
}

static void
irec_escape(irec_info *inf)
{
    rec_pat *pat;
    unsigned char chr = inf->ptr[0];

    if (chr == 0) {
      inf->ecode = RE_EESCAPE;
      return;
    }
    ++inf->ptr;
    switch (chr) {
      case 'o':
          irec_simple_pattern(inf, Rep_Odigit);
          break;
      case 'O':
          irec_simple_pattern(inf, Rep_OdigitNot);
          break;
      case 'd':
          irec_simple_pattern(inf, Rep_Digit);
          break;
      case 'D':
          irec_simple_pattern(inf, Rep_DigitNot);
          break;
      case 'x':
          irec_simple_pattern(inf, Rep_Xdigit);
          break;
      case 'X':
          irec_simple_pattern(inf, Rep_XdigitNot);
          break;
      case 's':
          irec_simple_pattern(inf, Rep_Space);
          break;
      case 'S':
          irec_simple_pattern(inf, Rep_SpaceNot);
          break;
      case 't':
          irec_simple_pattern(inf, Rep_Tab);
          break;
      case 'n':
          irec_simple_pattern(inf, Rep_Newline);
          break;
      case 'l':
          irec_simple_pattern(inf, Rep_Lower);
          break;
      case 'u':
          irec_simple_pattern(inf, Rep_Upper);
          break;
      case 'w':
          irec_simple_pattern(inf, Rep_Alnum);
          break;
      case 'W':
          irec_simple_pattern(inf, Rep_AlnumNot);
          break;
      case 'c':
          irec_simple_pattern(inf, Rep_Control);
          break;
      case 'C':
          irec_simple_pattern(inf, Rep_ControlNot);
          break;
      case '<':
          irec_simple_pattern(inf, Rep_Bow);
          break;
      case '>':
          irec_simple_pattern(inf, Rep_Eow);
          break;
      case '1':   case '2':   case '3':
      case '4':   case '5':   case '6':
      case '7':   case '8':   case '9':
          if ((inf->flags & RE_NOSUB) || (chr -= '1') >= inf->ngrps) {
            inf->ecode = RE_ESUBREG;
            return;
          }
          if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
            inf->ecode = RE_ESPACE;
            return;
          }
          pat->type = Rep_Backref;
          pat->data.chr = chr;
          pat->prev = inf->ppat;
          if (inf->ppat)
            inf->ppat->next = pat;
          else
            inf->palt->pat = pat;
          inf->ppat = pat;
          break;

      /* True literals */
      case '0':
          irec_literal_pattern(inf, '\0');
          break;
      case 'a':
          irec_literal_pattern(inf, '\a');
          break;
      case 'b':
          irec_literal_pattern(inf, '\b');
          break;
      case 'f':
          irec_literal_pattern(inf, '\f');
          break;
      case 'r':
          irec_literal_pattern(inf, '\r');
          break;
      case 'v':
          irec_literal_pattern(inf, '\v');
          break;

      default:
          /* Don't check if case insensitive regular expression */
          irec_literal_pattern(inf, chr);
          break;
    }
}

static void
irec_simple_repetition(irec_info *inf, rec_rep_t type)
{
    rec_rep *rep;

      /* If nowhere to add repetition */
    if ((inf->pgrp == NULL && inf->ppat == NULL) ||
      /* If repetition already added to last/current pattern */
      (inf->pgrp == NULL && inf->ppat->rep != NULL) ||
      /* If repetition already added to last/current group */
      (inf->ppat == NULL && inf->pgrp->parent->rep != NULL)) {
      inf->ecode = RE_BADRPT;
      return;
    }

    if ((rep = calloc(1, sizeof(rec_rep))) == NULL) {
      inf->ecode = RE_ESPACE;
      return;
    }

    rep->type = type;
    irec_add_repetition(inf, rep);
}

static void
irec_complex_repetition(irec_info *inf)
{
    int exact;
    rec_rep *rep;
    long mine, maxc;
    unsigned char *end;

      /* If nowhere to add repetition */
    if ((inf->pgrp == NULL && inf->ppat == NULL) ||
      /* If repetition already added to last/current pattern */
      (inf->pgrp == NULL && inf->ppat->rep != NULL) ||
      /* If repetition already added to last/current group */
      (inf->ppat == NULL && inf->pgrp->parent->rep != NULL)) {
      inf->ecode = RE_EBADBR;
      return;
    }

    exact = 0;
    mine = maxc = -1;
    if (inf->ptr[0] == ',')
      /* Specify max number of ocurrences only */
      goto domax;
    else if (!isdigit(inf->ptr[0]))
      goto badbr;

    mine = strtol((char*)inf->ptr, (char**)&end, 10);
    inf->ptr = end;
    if (inf->ptr[0] == '}') {
      exact = 1;
      ++inf->ptr;
      goto redone;
    }
    else if (inf->ptr[0] != ',')
      goto badbr;

domax:
      /* Add one to skip comma */
    ++inf->ptr;
    if (inf->ptr[0] == '}') {
      ++inf->ptr;
      goto redone;
    }
    else if (!isdigit(inf->ptr[0]))
      goto badbr;
    maxc = strtol((char*)inf->ptr, (char**)&end, 10);
    inf->ptr = end;
    if (inf->ptr[0] != '}')
      goto badbr;
    ++inf->ptr;

redone:
    if (mine == maxc) {
      maxc = -1;
      exact = 1;
    }

    /* Check range and if min-max parameters are valid */
    if (mine >= 255 || maxc >= 255 ||
      (mine >= 0 && maxc >= 0 && mine > maxc))
      goto badbr;

    /* Check for noop */
    if (exact && mine == 1)
      return;

    if ((rep = calloc(1, sizeof(rec_rep))) == NULL) {
      inf->ecode = RE_ESPACE;
      return;
    }

      /* Convert {0,1} to ? */
    if (mine == 0 && maxc == 1)
      rep->type = Rer_Maybe;
    else if (exact) {
      rep->type = Rer_Exact;
      rep->mine = mine;
    }
      /* Convert {0,} to * */
    else if (mine == 0 && maxc == -1)
      rep->type = Rer_AnyTimes;
      /* Convert {1,} to + */
    else if (mine == 1 && maxc == -1)
      rep->type = Rer_AtLeast;
    else if (maxc == -1) {
      rep->type = Rer_Min;
      rep->mine = mine;
    }
    else if (mine < 1) {
      rep->type = Rer_Max;
      rep->maxc = maxc;
    }
    else {
      rep->type = Rer_MinMax;
      rep->mine = mine;
      rep->maxc = maxc;
    }

    irec_add_repetition(inf, rep);

    return;

badbr:
    inf->ecode = RE_EBADBR;
}

/*  The rep argument is allocated and has no reference yet,
 * if something fails it must be freed before returning.
 */
static void
irec_add_repetition(irec_info *inf, rec_rep *rep)
{
    int length;
    rec_pat *pat;
    rec_grp *grp;
    rec_rep_t rept;
    unsigned char value, upper;

    rept = rep->type;

    if (inf->ppat == NULL) {
      rec_pat *any;
      rec_grp *grp = inf->pgrp;

      if (rept == Rer_AnyTimes || rept == Rer_Maybe || rept == Re_AtLeast) {
          /* Convert (.)* to (.*), ((.))* not handled and may not match */
          any = NULL;

          if (grp->alt && grp->alt->pat) {
            for (any = grp->alt->pat; any->next; any = any->next)
                ;
            switch (any->type) {
                case Rep_Any:
                  break;
                case Rep_AnyAnyTimes:
                case Rep_AnyMaybe:
                case Rep_AnyAtLeast:
                  free(rep);
                  inf->ecode = RE_BADRPT;
                  return;
                default:
                  any = NULL;
                  break;
            }
          }
          if (any) {
            free(rep);
            rep = NULL;
            any->type = (rept == Rer_AnyTimes) ? Rep_AnyAnyTimes :
                      (rept == Rer_AtLeast) ? Rep_AnyAtLeast :
                      Rep_AnyMaybe;
            while (grp) {
                ++grp->comp;
                grp = grp->pgrp;
            }
          }
      }
      inf->pgrp->parent->rep = rep;
      irec_close_group(inf);
      return;
    }

    switch (inf->ppat->type) {
      case Rep_Bol:
      case Rep_Eol:
      case Rep_Bow:
      case Rep_Eow:
      case Rep_AnyAnyTimes:
      case Rep_AnyMaybe:
      case Rep_AnyAtLeast:
          /* Markers that cannot repeat */
          free(rep);
          inf->ecode = RE_BADRPT;
          return;

      case Rep_Any:
          grp = inf->pgrp;
          free(rep);
          if (rept == Rer_AnyTimes ||
            rept == Rer_Maybe ||
            rept == Rer_AtLeast) {
            inf->ppat->type = (rept == Rer_AnyTimes) ?
                           Rep_AnyAnyTimes :
                          (rept == Rer_Maybe) ?
                           Rep_AnyMaybe :
                           Rep_AnyAtLeast;
            while (grp) {
                ++grp->comp;
                grp = grp->pgrp;
            }
          }
          else
            /* XXX Not (yet) implemented */
            inf->ecode = RE_BADRPT;
          rep = NULL;
          break;

      case Rep_String:
          if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
            free(rep);
            inf->ecode = RE_ESPACE;
            return;
          }

          length = strlen((char*)inf->ppat->data.str);
          pat->type = Rep_Literal;
          pat->prev = inf->ppat;
          pat->data.chr = inf->ppat->data.str[length - 1];
          if (length == 2) {
            /* Must convert to two Rep_Literals */
            value = inf->ppat->data.str[0];
            free(inf->ppat->data.str);
            inf->ppat->data.chr = value;
            inf->ppat->type = Rep_Literal;
          }
          else
            /* Must remove last character from string */
            inf->ppat->data.str[length - 1] = '\0';
          inf->ppat->next = pat;
          inf->ppat = pat;
          break;

      case Rep_CaseString:
          if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
            free(rep);
            inf->ecode = RE_ESPACE;
            return;
          }

          length = strlen((char*)inf->ppat->data.str);
          pat->type = Rep_CaseLiteral;
          pat->prev = inf->ppat;
          pat->data.cse.lower = inf->ppat->data.str[length - 2];
          pat->data.cse.upper = inf->ppat->data.str[length - 1];
          if (length == 4) {
            /* Must convert to two Rep_CaseLiterals */
            value = inf->ppat->data.str[0];
            upper = inf->ppat->data.str[1];
            free(inf->ppat->data.str);
            inf->ppat->data.cse.lower = value;
            inf->ppat->data.cse.upper = upper;
            inf->ppat->next = pat;
            inf->ppat->type = Rep_CaseLiteral;
          }
          else
            /* Must remove last character pair from string */
            inf->ppat->data.str[length - 2] = '\0';
          inf->ppat->next = pat;
          inf->ppat = pat;
          break;

      default:
          /* Anything else does not need special handling */
          break;
    }

    inf->ppat->rep = rep;
}

static void
irec_free(irec_info *inf)
{
    irec_free_alt(inf->alt);
}

static void
irec_free_grp(rec_grp *grp)
{
    if (grp->alt)
      irec_free_alt(grp->alt);
    free(grp);
}

static void
irec_free_pats(rec_pat *pat)
{
    rec_pat *next;
    rec_pat_t rect;

    while (pat) {
      next = pat->next;
      if (pat->rep)
          free(pat->rep);
      rect = pat->type;
      if (rect == Rep_Range || rect == Rep_RangeNot)
          free(pat->data.rng);
      else if (rect == Rep_Group)
          irec_free_grp(pat->data.grp);
      else if (rect == Rep_StringList)
          orec_free_stl(pat->data.stl);
      free(pat);
      pat = next;
    }
}

Generated by  Doxygen 1.6.0   Back to index