15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/re/rec.c,v 1.3 2002/11/15 07:01:33 paulo Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include "rep.h"
335dfecf96Smrg
345dfecf96Smrg/*
355dfecf96Smrg * Types
365dfecf96Smrg */
375dfecf96Smrg
385dfecf96Smrg/*  Information used while compiling the intermediate format of the re. */
395dfecf96Smrgtypedef struct _irec_info {
405dfecf96Smrg    unsigned char *ptr;		/* Pointer in the given regex pattern */
415dfecf96Smrg    unsigned char *end;		/* End of regex pattern */
425dfecf96Smrg    int flags;			/* Compile flags */
435dfecf96Smrg    rec_alt *alt;		/* Toplevel first/single alternative */
445dfecf96Smrg
455dfecf96Smrg    rec_alt *palt;		/* Current alternative being compiled */
465dfecf96Smrg    rec_grp *pgrp;		/* Current group, if any */
475dfecf96Smrg    rec_pat *ppat;		/* Current pattern, if any */
485dfecf96Smrg
495dfecf96Smrg    /*  Number of open parenthesis, for error checking */
505dfecf96Smrg    int nparens;
515dfecf96Smrg
525dfecf96Smrg    int ngrps;			/* Number of groups, for backreference */
535dfecf96Smrg
545dfecf96Smrg    int ecode;
555dfecf96Smrg} irec_info;
565dfecf96Smrg
575dfecf96Smrg
585dfecf96Smrg/*
595dfecf96Smrg * Prototypes
605dfecf96Smrg */
615dfecf96Smrg
625dfecf96Smrg	/* (i)ntermediate (r)egular (e)xpression (c)ompile
635dfecf96Smrg	 *  Generates an intermediate stage compiled regex from
645dfecf96Smrg	 * the specified pattern argument. Basically builds an
655dfecf96Smrg	 * intermediate data structure to analyse and do syntax
665dfecf96Smrg	 * error checking.
675dfecf96Smrg	 */
685dfecf96Smrgstatic void irec_simple_pattern(irec_info*, rec_pat_t);
695dfecf96Smrgstatic void irec_literal_pattern(irec_info*, int);
705dfecf96Smrgstatic void irec_case_literal_pattern(irec_info*, int);
715dfecf96Smrgstatic void irec_open_group(irec_info*);
725dfecf96Smrgstatic void irec_close_group(irec_info*);
735dfecf96Smrgstatic void irec_range(irec_info*);
745dfecf96Smrgstatic void irec_range_single(irec_info*, int);
755dfecf96Smrgstatic void irec_range_complex(irec_info*, int, int);
765dfecf96Smrgstatic void irec_escape(irec_info*);
775dfecf96Smrgstatic void irec_simple_repetition(irec_info*, rec_rep_t);
785dfecf96Smrgstatic void irec_complex_repetition(irec_info*);
795dfecf96Smrgstatic void irec_add_repetition(irec_info*, rec_rep*);
805dfecf96Smrgstatic void irec_free(irec_info*);
815dfecf96Smrgstatic void irec_free_grp(rec_grp*);
825dfecf96Smrgstatic void irec_free_pats(rec_pat*);
835dfecf96Smrg
845dfecf96Smrg
855dfecf96Smrg/*
865dfecf96Smrg * Implementation
875dfecf96Smrg */
885dfecf96Smrgrec_alt *
895dfecf96Smrgirec_comp(const char *pattern, const char *endp, int flags, int *ecode)
905dfecf96Smrg{
915dfecf96Smrg    unsigned char *ptr;
925dfecf96Smrg    rec_alt *alt;
935dfecf96Smrg    irec_info inf;
945dfecf96Smrg
955dfecf96Smrg    if (pattern == NULL || endp < pattern) {
965dfecf96Smrg	*ecode = RE_INVARG;
975dfecf96Smrg	return (NULL);
985dfecf96Smrg    }
995dfecf96Smrg
1005dfecf96Smrg    if (endp == pattern) {
1015dfecf96Smrg	*ecode = RE_EMPTY;
1025dfecf96Smrg	return (NULL);
1035dfecf96Smrg    }
1045dfecf96Smrg
1055dfecf96Smrg    alt = calloc(1, sizeof(rec_alt));
1065dfecf96Smrg    if (alt == NULL) {
1075dfecf96Smrg	*ecode = RE_ESPACE;
1085dfecf96Smrg	return (NULL);
1095dfecf96Smrg    }
1105dfecf96Smrg
1115dfecf96Smrg    inf.ptr = (unsigned char*)pattern;
1125dfecf96Smrg    inf.end = (unsigned char*)endp;
1135dfecf96Smrg    inf.flags = flags;
1145dfecf96Smrg    inf.alt = inf.palt = alt;
1155dfecf96Smrg    inf.pgrp = NULL;
1165dfecf96Smrg    inf.ppat = NULL;
1175dfecf96Smrg    inf.nparens = inf.ngrps = 0;
1185dfecf96Smrg    inf.ecode = 0;
1195dfecf96Smrg
1205dfecf96Smrg    if (flags & RE_NOSPEC) {
1215dfecf96Smrg	/* Just searching for a character or substring */
1225dfecf96Smrg	for (; inf.ecode == 0 && inf.ptr < inf.end; inf.ptr++) {
1235dfecf96Smrg	    if (!(flags & RE_ICASE) ||
1245dfecf96Smrg		(!isupper(*inf.ptr) && !islower(*inf.ptr)))
1255dfecf96Smrg		irec_literal_pattern(&inf, *inf.ptr);
1265dfecf96Smrg	    else
1275dfecf96Smrg		irec_case_literal_pattern(&inf, *inf.ptr);
1285dfecf96Smrg	}
1295dfecf96Smrg    }
1305dfecf96Smrg    /* inf.ptr = inf.end is nul if flags & RE_NOSPEC */
1315dfecf96Smrg    for (; inf.ecode == 0 && inf.ptr < inf.end;) {
1325dfecf96Smrg	switch (*inf.ptr++) {
1335dfecf96Smrg	    case '*':
1345dfecf96Smrg		irec_simple_repetition(&inf, Rer_AnyTimes);
1355dfecf96Smrg		break;
1365dfecf96Smrg	    case '+':
1375dfecf96Smrg		irec_simple_repetition(&inf, Rer_AtLeast);
1385dfecf96Smrg		break;
1395dfecf96Smrg	    case '?':
1405dfecf96Smrg		irec_simple_repetition(&inf, Rer_Maybe);
1415dfecf96Smrg		break;
1425dfecf96Smrg	    case '.':
1435dfecf96Smrg		irec_simple_pattern(&inf, Rep_Any);
1445dfecf96Smrg		break;
1455dfecf96Smrg	    case '^':
1465dfecf96Smrg		if (flags & RE_NEWLINE)
1475dfecf96Smrg		    /* It is up to the user decide if this can match */
1485dfecf96Smrg		    irec_simple_pattern(&inf, Rep_Bol);
1495dfecf96Smrg		else {
1505dfecf96Smrg		    for (ptr = inf.ptr - 1;
1515dfecf96Smrg			 ptr > (unsigned char*)pattern && *ptr == '('; ptr--)
1525dfecf96Smrg			;
1535dfecf96Smrg		    /* If at the start of a pattern */
1545dfecf96Smrg		    if (ptr == (unsigned char*)pattern || *ptr == '|')
1555dfecf96Smrg			irec_simple_pattern(&inf, Rep_Bol);
1565dfecf96Smrg		    else
1575dfecf96Smrg			/* In the middle of a pattern, treat as literal */
1585dfecf96Smrg			irec_literal_pattern(&inf, '^');
1595dfecf96Smrg		}
1605dfecf96Smrg		break;
1615dfecf96Smrg	    case '$':
1625dfecf96Smrg		if (flags & RE_NEWLINE)
1635dfecf96Smrg		    irec_simple_pattern(&inf, Rep_Eol);
1645dfecf96Smrg		else {
1655dfecf96Smrg		    /* Look ahead to check if is the last char of a group */
1665dfecf96Smrg		    for (ptr = inf.ptr; ptr < inf.end && *ptr == ')'; ptr++)
1675dfecf96Smrg			;
1685dfecf96Smrg		    if (*ptr == '\0' || *ptr == '|')
1695dfecf96Smrg			/* Last character of pattern, an EOL match */
1705dfecf96Smrg			irec_simple_pattern(&inf, Rep_Eol);
1715dfecf96Smrg		    else
1725dfecf96Smrg			/* Normal character */
1735dfecf96Smrg			irec_literal_pattern(&inf, '$');
1745dfecf96Smrg		}
1755dfecf96Smrg		break;
1765dfecf96Smrg	    case '(':
1775dfecf96Smrg		irec_open_group(&inf);
1785dfecf96Smrg		break;
1795dfecf96Smrg	    case ')':
1805dfecf96Smrg		/* Look ahead to check if need to close the group now */
1815dfecf96Smrg		ptr = inf.ptr;
1825dfecf96Smrg		if (*ptr != '*' && *ptr != '+' && *ptr != '?' && *ptr != '{')
1835dfecf96Smrg		    /* If a repetition does not follow */
1845dfecf96Smrg		    irec_close_group(&inf);
1855dfecf96Smrg		else if (inf.pgrp == NULL)
1865dfecf96Smrg		    /* A repetition follows, but current group is implicit */
1875dfecf96Smrg		    inf.ecode = RE_EPAREN;
1885dfecf96Smrg		else
1895dfecf96Smrg		    /* Can do this as next character is known */
1905dfecf96Smrg		    inf.ppat = NULL;
1915dfecf96Smrg		break;
1925dfecf96Smrg	    case '[':
1935dfecf96Smrg		irec_range(&inf);
1945dfecf96Smrg		break;
1955dfecf96Smrg	    case ']':
1965dfecf96Smrg		irec_literal_pattern(&inf, ']');
1975dfecf96Smrg		break;
1985dfecf96Smrg	    case '{':
1995dfecf96Smrg		irec_complex_repetition(&inf);
2005dfecf96Smrg		break;
2015dfecf96Smrg	    case '}':
2025dfecf96Smrg		irec_literal_pattern(&inf, '}');
2035dfecf96Smrg		break;
2045dfecf96Smrg	    case '|':
2055dfecf96Smrg		    /* If first character in the pattern */
2065dfecf96Smrg		if (inf.ptr - 1 == (unsigned char*)pattern ||
2075dfecf96Smrg		    /* If last character in the pattern */
2085dfecf96Smrg		    inf.ptr >= inf.end ||
2095dfecf96Smrg		    /* If empty pattern */
2105dfecf96Smrg		    inf.ptr[0] == '|' ||
2115dfecf96Smrg		    inf.ptr[0] == ')')
2125dfecf96Smrg		    inf.ecode = RE_EMPTY;
2135dfecf96Smrg		else {
2145dfecf96Smrg		    rec_alt *alt = calloc(1, sizeof(rec_alt));
2155dfecf96Smrg
2165dfecf96Smrg		    if (alt) {
2175dfecf96Smrg			alt->prev = inf.palt;
2185dfecf96Smrg			inf.palt->next = alt;
2195dfecf96Smrg			inf.palt = alt;
2205dfecf96Smrg			inf.ppat = NULL;
2215dfecf96Smrg		    }
2225dfecf96Smrg		    else
2235dfecf96Smrg			inf.ecode = RE_ESPACE;
2245dfecf96Smrg		}
2255dfecf96Smrg		break;
2265dfecf96Smrg	    case '\\':
2275dfecf96Smrg		irec_escape(&inf);
2285dfecf96Smrg		break;
2295dfecf96Smrg	    default:
2305dfecf96Smrg		if (!(flags & RE_ICASE) ||
2315dfecf96Smrg		    (!isupper(inf.ptr[-1]) && !islower(inf.ptr[-1])))
2325dfecf96Smrg		    irec_literal_pattern(&inf, inf.ptr[-1]);
2335dfecf96Smrg		else
2345dfecf96Smrg		    irec_case_literal_pattern(&inf, inf.ptr[-1]);
2355dfecf96Smrg		break;
2365dfecf96Smrg	}
2375dfecf96Smrg    }
2385dfecf96Smrg
2395dfecf96Smrg    /* Check if not all groups closed */
2405dfecf96Smrg    if (inf.ecode == 0 && inf.nparens)
2415dfecf96Smrg	inf.ecode = RE_EPAREN;
2425dfecf96Smrg
2435dfecf96Smrg    if (inf.ecode == 0)
2445dfecf96Smrg	inf.ecode = orec_comp(inf.alt, flags);
2455dfecf96Smrg
2465dfecf96Smrg    /* If an error generated */
2475dfecf96Smrg    if (inf.ecode) {
2485dfecf96Smrg	irec_free(&inf);
2495dfecf96Smrg	alt = NULL;
2505dfecf96Smrg    }
2515dfecf96Smrg
2525dfecf96Smrg    *ecode = inf.ecode;
2535dfecf96Smrg
2545dfecf96Smrg    return (alt);
2555dfecf96Smrg}
2565dfecf96Smrg
2575dfecf96Smrgvoid
2585dfecf96Smrgirec_free_alt(rec_alt *alt)
2595dfecf96Smrg{
2605dfecf96Smrg    rec_alt *next;
2615dfecf96Smrg
2625dfecf96Smrg    while (alt) {
2635dfecf96Smrg	next = alt->next;
2645dfecf96Smrg	irec_free_pats(alt->pat);
2655dfecf96Smrg	free(alt);
2665dfecf96Smrg	alt = next;
2675dfecf96Smrg    }
2685dfecf96Smrg}
2695dfecf96Smrg
2705dfecf96Smrg
2715dfecf96Smrg
2725dfecf96Smrgstatic void
2735dfecf96Smrgirec_simple_pattern(irec_info *inf, rec_pat_t type)
2745dfecf96Smrg{
2755dfecf96Smrg    rec_pat *pat;
2765dfecf96Smrg
2775dfecf96Smrg    /* Always add a new pattern to list */
2785dfecf96Smrg    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
2795dfecf96Smrg	inf->ecode = RE_ESPACE;
2805dfecf96Smrg	return;
2815dfecf96Smrg    }
2825dfecf96Smrg
2835dfecf96Smrg    pat->type = type;
2845dfecf96Smrg    if ((pat->prev = inf->ppat) != NULL)
2855dfecf96Smrg	inf->ppat->next = pat;
2865dfecf96Smrg    else
2875dfecf96Smrg	inf->palt->pat = pat;
2885dfecf96Smrg    inf->ppat = pat;
2895dfecf96Smrg}
2905dfecf96Smrg
2915dfecf96Smrgstatic void
2925dfecf96Smrgirec_literal_pattern(irec_info *inf, int value)
2935dfecf96Smrg{
2945dfecf96Smrg    int length;
2955dfecf96Smrg    rec_pat *pat;
2965dfecf96Smrg    unsigned char chr, *str;
2975dfecf96Smrg
2985dfecf96Smrg	/* If there is a current pattern */
2995dfecf96Smrg    if (inf->ppat && inf->ppat->rep == NULL) {
3005dfecf96Smrg	switch (inf->ppat->type) {
3015dfecf96Smrg	    case Rep_Literal:
3025dfecf96Smrg		/* Start literal string */
3035dfecf96Smrg		chr = inf->ppat->data.chr;
3045dfecf96Smrg		if ((str = malloc(16)) == NULL) {
3055dfecf96Smrg		    inf->ecode = RE_ESPACE;
3065dfecf96Smrg		    return;
3075dfecf96Smrg		}
3085dfecf96Smrg		inf->ppat->type = Rep_String;
3095dfecf96Smrg		inf->ppat->data.str = str;
3105dfecf96Smrg		str[0] = chr;
3115dfecf96Smrg		str[1] = value;
3125dfecf96Smrg		str[2] = '\0';
3135dfecf96Smrg		return;
3145dfecf96Smrg
3155dfecf96Smrg	    case Rep_String:
3165dfecf96Smrg		/* Augments literal string */
3175dfecf96Smrg		length = strlen((char*)inf->ppat->data.str);
3185dfecf96Smrg		if ((length % 16) >= 14) {
3195dfecf96Smrg		    if ((str = realloc(inf->ppat->data.str,
3205dfecf96Smrg				       length + 18)) == NULL) {
3215dfecf96Smrg			inf->ecode = RE_ESPACE;
3225dfecf96Smrg			return;
3235dfecf96Smrg		    }
3245dfecf96Smrg		    inf->ppat->data.str = str;
3255dfecf96Smrg		}
3265dfecf96Smrg		inf->ppat->data.str[length] = value;
3275dfecf96Smrg		inf->ppat->data.str[length + 1] = '\0';
3285dfecf96Smrg		return;
3295dfecf96Smrg
3305dfecf96Smrg	    default:
3315dfecf96Smrg		/* Anything else is added as a new pattern list element */
3325dfecf96Smrg		break;
3335dfecf96Smrg	}
3345dfecf96Smrg    }
3355dfecf96Smrg
3365dfecf96Smrg    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
3375dfecf96Smrg	inf->ecode = RE_ESPACE;
3385dfecf96Smrg	return;
3395dfecf96Smrg    }
3405dfecf96Smrg
3415dfecf96Smrg    pat->type = Rep_Literal;
3425dfecf96Smrg    pat->data.chr = value;
3435dfecf96Smrg    if ((pat->prev = inf->ppat) != NULL)
3445dfecf96Smrg	inf->ppat->next = pat;
3455dfecf96Smrg    else
3465dfecf96Smrg	inf->palt->pat = pat;
3475dfecf96Smrg    inf->ppat = pat;
3485dfecf96Smrg}
3495dfecf96Smrg
3505dfecf96Smrgstatic void
3515dfecf96Smrgirec_case_literal_pattern(irec_info *inf, int value)
3525dfecf96Smrg{
3535dfecf96Smrg    int length;
3545dfecf96Smrg    rec_pat *pat;
3555dfecf96Smrg    unsigned char plower, pupper, lower, upper, *str;
3565dfecf96Smrg
3575dfecf96Smrg    lower = tolower(value);
3585dfecf96Smrg    upper = toupper(value);
3595dfecf96Smrg
3605dfecf96Smrg	/* If there is a current pattern */
3615dfecf96Smrg    if (inf->ppat && inf->ppat->rep == NULL) {
3625dfecf96Smrg	switch (inf->ppat->type) {
3635dfecf96Smrg	    case Rep_CaseLiteral:
3645dfecf96Smrg		/* Start case literal string */
3655dfecf96Smrg		plower = inf->ppat->data.cse.lower;
3665dfecf96Smrg		pupper = inf->ppat->data.cse.upper;
3675dfecf96Smrg		if ((str = malloc(32)) == NULL) {
3685dfecf96Smrg		    inf->ecode = RE_ESPACE;
3695dfecf96Smrg		    return;
3705dfecf96Smrg		}
3715dfecf96Smrg		inf->ppat->type = Rep_CaseString;
3725dfecf96Smrg		inf->ppat->data.str = str;
3735dfecf96Smrg		str[0] = plower;
3745dfecf96Smrg		str[1] = pupper;
3755dfecf96Smrg		str[2] = lower;
3765dfecf96Smrg		str[3] = upper;
3775dfecf96Smrg		str[4] = '\0';
3785dfecf96Smrg		return;
3795dfecf96Smrg
3805dfecf96Smrg	    case Rep_CaseString:
3815dfecf96Smrg		/* Augments case literal string */
3825dfecf96Smrg		length = strlen((char*)inf->ppat->data.str);
3835dfecf96Smrg		if (((length) % 32) >= 28) {
3845dfecf96Smrg		    if ((str = realloc(inf->ppat->data.str,
3855dfecf96Smrg				       length + 36)) == NULL) {
3865dfecf96Smrg			inf->ecode = RE_ESPACE;
3875dfecf96Smrg			return;
3885dfecf96Smrg		    }
3895dfecf96Smrg		    inf->ppat->data.str = str;
3905dfecf96Smrg		}
3915dfecf96Smrg		inf->ppat->data.str[length] = lower;
3925dfecf96Smrg		inf->ppat->data.str[length + 1] = upper;
3935dfecf96Smrg		inf->ppat->data.str[length + 2] = '\0';
3945dfecf96Smrg		return;
3955dfecf96Smrg
3965dfecf96Smrg	    default:
3975dfecf96Smrg		/* Anything else is added as a new pattern list element */
3985dfecf96Smrg		break;
3995dfecf96Smrg	}
4005dfecf96Smrg    }
4015dfecf96Smrg
4025dfecf96Smrg    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
4035dfecf96Smrg	inf->ecode = RE_ESPACE;
4045dfecf96Smrg	return;
4055dfecf96Smrg    }
4065dfecf96Smrg
4075dfecf96Smrg    pat->type = Rep_CaseLiteral;
4085dfecf96Smrg    pat->data.cse.lower = lower;
4095dfecf96Smrg    pat->data.cse.upper = upper;
4105dfecf96Smrg    pat->prev = inf->ppat;
4115dfecf96Smrg    if ((pat->prev = inf->ppat) != NULL)
4125dfecf96Smrg	inf->ppat->next = pat;
4135dfecf96Smrg    else
4145dfecf96Smrg	inf->palt->pat = pat;
4155dfecf96Smrg    inf->ppat = pat;
4165dfecf96Smrg}
4175dfecf96Smrg
4185dfecf96Smrgstatic void
4195dfecf96Smrgirec_open_group(irec_info *inf)
4205dfecf96Smrg{
4215dfecf96Smrg    rec_pat *pat;
4225dfecf96Smrg    rec_alt *alt;
4235dfecf96Smrg    rec_grp *grp;
4245dfecf96Smrg
4255dfecf96Smrg    if ((grp = calloc(1, sizeof(rec_grp))) == NULL) {
4265dfecf96Smrg	inf->ecode = RE_ESPACE;
4275dfecf96Smrg	return;
4285dfecf96Smrg    }
4295dfecf96Smrg
4305dfecf96Smrg    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
4315dfecf96Smrg	free(grp);
4325dfecf96Smrg	inf->ecode = RE_ESPACE;
4335dfecf96Smrg	return;
4345dfecf96Smrg    }
4355dfecf96Smrg
4365dfecf96Smrg    if ((alt = calloc(1, sizeof(rec_alt))) == NULL) {
4375dfecf96Smrg	free(grp);
4385dfecf96Smrg	free(pat);
4395dfecf96Smrg	inf->ecode = RE_ESPACE;
4405dfecf96Smrg	return;
4415dfecf96Smrg    }
4425dfecf96Smrg
4435dfecf96Smrg    pat->type = Rep_Group;
4445dfecf96Smrg    pat->data.grp = grp;
4455dfecf96Smrg    grp->parent = pat;
4465dfecf96Smrg    grp->palt = inf->palt;
4475dfecf96Smrg    grp->pgrp = inf->pgrp;
4485dfecf96Smrg    grp->alt = alt;
4495dfecf96Smrg    grp->comp = 0;
4505dfecf96Smrg    if ((pat->prev = inf->ppat) != NULL)
4515dfecf96Smrg	inf->ppat->next = pat;
4525dfecf96Smrg    else
4535dfecf96Smrg	inf->palt->pat = pat;
4545dfecf96Smrg    inf->palt = alt;
4555dfecf96Smrg    inf->ppat = NULL;
4565dfecf96Smrg
4575dfecf96Smrg    /* Only toplevel parenthesis supported */
4585dfecf96Smrg    if (++inf->nparens == 1)
4595dfecf96Smrg	++inf->ngrps;
4605dfecf96Smrg
4615dfecf96Smrg    inf->pgrp = grp;
4625dfecf96Smrg}
4635dfecf96Smrg
4645dfecf96Smrgstatic void
4655dfecf96Smrgirec_close_group(irec_info *inf)
4665dfecf96Smrg{
4675dfecf96Smrg    if (inf->pgrp == NULL) {
4685dfecf96Smrg	inf->ecode = RE_EPAREN;
4695dfecf96Smrg	return;
4705dfecf96Smrg    }
4715dfecf96Smrg
4725dfecf96Smrg    inf->palt = inf->pgrp->palt;
4735dfecf96Smrg    inf->ppat = inf->pgrp->parent;
4745dfecf96Smrg    inf->pgrp = inf->pgrp->pgrp;
4755dfecf96Smrg
4765dfecf96Smrg    --inf->nparens;
4775dfecf96Smrg}
4785dfecf96Smrg
4795dfecf96Smrgstatic void
4805dfecf96Smrgirec_range(irec_info *inf)
4815dfecf96Smrg{
4825dfecf96Smrg    int count;
4835dfecf96Smrg    rec_pat *pat;
4845dfecf96Smrg    rec_rng *rng;
4855dfecf96Smrg    int not = inf->ptr[0] == '^';
4865dfecf96Smrg
4875dfecf96Smrg    if (not)
4885dfecf96Smrg	++inf->ptr;
4895dfecf96Smrg
4905dfecf96Smrg    pat = calloc(1, sizeof(rec_pat));
4915dfecf96Smrg    if (pat == NULL) {
4925dfecf96Smrg	inf->ecode = RE_ESPACE;
4935dfecf96Smrg	return;
4945dfecf96Smrg    }
4955dfecf96Smrg
4965dfecf96Smrg    rng = calloc(1, sizeof(rec_rng));
4975dfecf96Smrg    if (pat == NULL) {
4985dfecf96Smrg	free(pat);
4995dfecf96Smrg	inf->ecode = RE_ESPACE;
5005dfecf96Smrg	return;
5015dfecf96Smrg    }
5025dfecf96Smrg
5035dfecf96Smrg    pat->data.rng = rng;
5045dfecf96Smrg    pat->type = not ? Rep_RangeNot : Rep_Range;
5055dfecf96Smrg    if ((pat->prev = inf->ppat) != NULL)
5065dfecf96Smrg	inf->ppat->next = pat;
5075dfecf96Smrg    else
5085dfecf96Smrg	inf->palt->pat = pat;
5095dfecf96Smrg    inf->ppat = pat;
5105dfecf96Smrg
5115dfecf96Smrg    /* First pass, add everything seen */
5125dfecf96Smrg    for (count = 0; inf->ecode == 0; count++) {
5135dfecf96Smrg	/* If bracket not closed */
5145dfecf96Smrg	if (inf->ptr == inf->end) {
5155dfecf96Smrg	    inf->ecode = RE_EBRACK;
5165dfecf96Smrg	    return;
5175dfecf96Smrg	}
5185dfecf96Smrg	/* If not the first character */
5195dfecf96Smrg	else if (inf->ptr[0] == ']' && count)
5205dfecf96Smrg	    break;
5215dfecf96Smrg	else {
5225dfecf96Smrg	    /* If not a range of characters */
5235dfecf96Smrg	    if (inf->ptr[1] != '-' || inf->ptr[2] == ']') {
5245dfecf96Smrg		irec_range_single(inf, inf->ptr[0]);
5255dfecf96Smrg		++inf->ptr;
5265dfecf96Smrg	    }
5275dfecf96Smrg	    else {
5285dfecf96Smrg		if ((inf->flags & RE_NEWLINE) &&
5295dfecf96Smrg		    inf->ptr[0] < '\n' && inf->ptr[2] > '\n') {
5305dfecf96Smrg		    /*  Unless it is forced to be a delimiter, don't allow
5315dfecf96Smrg		     * a newline in a character range */
5325dfecf96Smrg		    if (inf->ptr[0] == '\n' - 1)
5335dfecf96Smrg			irec_range_single(inf, inf->ptr[0]);
5345dfecf96Smrg		    else
5355dfecf96Smrg			irec_range_complex(inf, inf->ptr[0], '\n' - 1);
5365dfecf96Smrg		    if (inf->ptr[2] == '\n' + 1)
5375dfecf96Smrg			irec_range_single(inf, inf->ptr[2]);
5385dfecf96Smrg		    else
5395dfecf96Smrg			irec_range_complex(inf, '\n' + 1, inf->ptr[2]);
5405dfecf96Smrg		}
5415dfecf96Smrg		else
5425dfecf96Smrg		    irec_range_complex(inf, inf->ptr[0], inf->ptr[2]);
5435dfecf96Smrg		inf->ptr += 3;
5445dfecf96Smrg	    }
5455dfecf96Smrg	}
5465dfecf96Smrg    }
5475dfecf96Smrg
5485dfecf96Smrg    /* Skip ] */
5495dfecf96Smrg    ++inf->ptr;
5505dfecf96Smrg}
5515dfecf96Smrg
5525dfecf96Smrgstatic void
5535dfecf96Smrgirec_range_single(irec_info *inf, int value)
5545dfecf96Smrg{
5555dfecf96Smrg    if (value >= 0 && value <= 255)
5565dfecf96Smrg	inf->ppat->data.rng->range[value] = 1;
5575dfecf96Smrg
5585dfecf96Smrg    if (inf->flags & RE_ICASE) {
5595dfecf96Smrg	if (islower(value)) {
5605dfecf96Smrg	    value = toupper(value);
5615dfecf96Smrg	    if (value >= 0 && value <= 255)
5625dfecf96Smrg		inf->ppat->data.rng->range[value] = 1;
5635dfecf96Smrg	}
5645dfecf96Smrg	else if (isupper(value)) {
5655dfecf96Smrg	    value = tolower(value);
5665dfecf96Smrg	    if (value >= 0 && value <= 255)
5675dfecf96Smrg		inf->ppat->data.rng->range[value] = 1;
5685dfecf96Smrg	}
5695dfecf96Smrg    }
5705dfecf96Smrg}
5715dfecf96Smrg
5725dfecf96Smrgstatic void
5735dfecf96Smrgirec_range_complex(irec_info *inf, int chrf, int chrt)
5745dfecf96Smrg{
5755dfecf96Smrg    if (chrf > chrt) {
5765dfecf96Smrg	inf->ecode = RE_ERANGE;
5775dfecf96Smrg	return;
5785dfecf96Smrg    }
5795dfecf96Smrg
5805dfecf96Smrg    for (; chrf <= chrt; chrf++)
5815dfecf96Smrg	irec_range_single(inf, chrf);
5825dfecf96Smrg}
5835dfecf96Smrg
5845dfecf96Smrgstatic void
5855dfecf96Smrgirec_escape(irec_info *inf)
5865dfecf96Smrg{
5875dfecf96Smrg    rec_pat *pat;
5885dfecf96Smrg    unsigned char chr = inf->ptr[0];
5895dfecf96Smrg
5905dfecf96Smrg    if (chr == 0) {
5915dfecf96Smrg	inf->ecode = RE_EESCAPE;
5925dfecf96Smrg	return;
5935dfecf96Smrg    }
5945dfecf96Smrg    ++inf->ptr;
5955dfecf96Smrg    switch (chr) {
5965dfecf96Smrg	case 'o':
5975dfecf96Smrg	    irec_simple_pattern(inf, Rep_Odigit);
5985dfecf96Smrg	    break;
5995dfecf96Smrg	case 'O':
6005dfecf96Smrg	    irec_simple_pattern(inf, Rep_OdigitNot);
6015dfecf96Smrg	    break;
6025dfecf96Smrg	case 'd':
6035dfecf96Smrg	    irec_simple_pattern(inf, Rep_Digit);
6045dfecf96Smrg	    break;
6055dfecf96Smrg	case 'D':
6065dfecf96Smrg	    irec_simple_pattern(inf, Rep_DigitNot);
6075dfecf96Smrg	    break;
6085dfecf96Smrg	case 'x':
6095dfecf96Smrg	    irec_simple_pattern(inf, Rep_Xdigit);
6105dfecf96Smrg	    break;
6115dfecf96Smrg	case 'X':
6125dfecf96Smrg	    irec_simple_pattern(inf, Rep_XdigitNot);
6135dfecf96Smrg	    break;
6145dfecf96Smrg	case 's':
6155dfecf96Smrg	    irec_simple_pattern(inf, Rep_Space);
6165dfecf96Smrg	    break;
6175dfecf96Smrg	case 'S':
6185dfecf96Smrg	    irec_simple_pattern(inf, Rep_SpaceNot);
6195dfecf96Smrg	    break;
6205dfecf96Smrg	case 't':
6215dfecf96Smrg	    irec_simple_pattern(inf, Rep_Tab);
6225dfecf96Smrg	    break;
6235dfecf96Smrg	case 'n':
6245dfecf96Smrg	    irec_simple_pattern(inf, Rep_Newline);
6255dfecf96Smrg	    break;
6265dfecf96Smrg	case 'l':
6275dfecf96Smrg	    irec_simple_pattern(inf, Rep_Lower);
6285dfecf96Smrg	    break;
6295dfecf96Smrg	case 'u':
6305dfecf96Smrg	    irec_simple_pattern(inf, Rep_Upper);
6315dfecf96Smrg	    break;
6325dfecf96Smrg	case 'w':
6335dfecf96Smrg	    irec_simple_pattern(inf, Rep_Alnum);
6345dfecf96Smrg	    break;
6355dfecf96Smrg	case 'W':
6365dfecf96Smrg	    irec_simple_pattern(inf, Rep_AlnumNot);
6375dfecf96Smrg	    break;
6385dfecf96Smrg	case 'c':
6395dfecf96Smrg	    irec_simple_pattern(inf, Rep_Control);
6405dfecf96Smrg	    break;
6415dfecf96Smrg	case 'C':
6425dfecf96Smrg	    irec_simple_pattern(inf, Rep_ControlNot);
6435dfecf96Smrg	    break;
6445dfecf96Smrg	case '<':
6455dfecf96Smrg	    irec_simple_pattern(inf, Rep_Bow);
6465dfecf96Smrg	    break;
6475dfecf96Smrg	case '>':
6485dfecf96Smrg	    irec_simple_pattern(inf, Rep_Eow);
6495dfecf96Smrg	    break;
6505dfecf96Smrg	case '1':	case '2':	case '3':
6515dfecf96Smrg	case '4':	case '5':	case '6':
6525dfecf96Smrg	case '7':	case '8':	case '9':
6535dfecf96Smrg	    if ((inf->flags & RE_NOSUB) || (chr -= '1') >= inf->ngrps) {
6545dfecf96Smrg		inf->ecode = RE_ESUBREG;
6555dfecf96Smrg		return;
6565dfecf96Smrg	    }
6575dfecf96Smrg	    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
6585dfecf96Smrg		inf->ecode = RE_ESPACE;
6595dfecf96Smrg		return;
6605dfecf96Smrg	    }
6615dfecf96Smrg	    pat->type = Rep_Backref;
6625dfecf96Smrg	    pat->data.chr = chr;
6635dfecf96Smrg	    pat->prev = inf->ppat;
6645dfecf96Smrg	    if (inf->ppat)
6655dfecf96Smrg		inf->ppat->next = pat;
6665dfecf96Smrg	    else
6675dfecf96Smrg		inf->palt->pat = pat;
6685dfecf96Smrg	    inf->ppat = pat;
6695dfecf96Smrg	    break;
6705dfecf96Smrg
6715dfecf96Smrg	/* True literals */
6725dfecf96Smrg	case '0':
6735dfecf96Smrg	    irec_literal_pattern(inf, '\0');
6745dfecf96Smrg	    break;
6755dfecf96Smrg	case 'a':
6765dfecf96Smrg	    irec_literal_pattern(inf, '\a');
6775dfecf96Smrg	    break;
6785dfecf96Smrg	case 'b':
6795dfecf96Smrg	    irec_literal_pattern(inf, '\b');
6805dfecf96Smrg	    break;
6815dfecf96Smrg	case 'f':
6825dfecf96Smrg	    irec_literal_pattern(inf, '\f');
6835dfecf96Smrg	    break;
6845dfecf96Smrg	case 'r':
6855dfecf96Smrg	    irec_literal_pattern(inf, '\r');
6865dfecf96Smrg	    break;
6875dfecf96Smrg	case 'v':
6885dfecf96Smrg	    irec_literal_pattern(inf, '\v');
6895dfecf96Smrg	    break;
6905dfecf96Smrg
6915dfecf96Smrg	default:
6925dfecf96Smrg	    /* Don't check if case insensitive regular expression */
6935dfecf96Smrg	    irec_literal_pattern(inf, chr);
6945dfecf96Smrg	    break;
6955dfecf96Smrg    }
6965dfecf96Smrg}
6975dfecf96Smrg
6985dfecf96Smrgstatic void
6995dfecf96Smrgirec_simple_repetition(irec_info *inf, rec_rep_t type)
7005dfecf96Smrg{
7015dfecf96Smrg    rec_rep *rep;
7025dfecf96Smrg
7035dfecf96Smrg	/* If nowhere to add repetition */
7045dfecf96Smrg    if ((inf->pgrp == NULL && inf->ppat == NULL) ||
7055dfecf96Smrg	/* If repetition already added to last/current pattern */
7065dfecf96Smrg	(inf->pgrp == NULL && inf->ppat->rep != NULL) ||
7075dfecf96Smrg	/* If repetition already added to last/current group */
7085dfecf96Smrg	(inf->ppat == NULL && inf->pgrp->parent->rep != NULL)) {
7095dfecf96Smrg	inf->ecode = RE_BADRPT;
7105dfecf96Smrg	return;
7115dfecf96Smrg    }
7125dfecf96Smrg
7135dfecf96Smrg    if ((rep = calloc(1, sizeof(rec_rep))) == NULL) {
7145dfecf96Smrg	inf->ecode = RE_ESPACE;
7155dfecf96Smrg	return;
7165dfecf96Smrg    }
7175dfecf96Smrg
7185dfecf96Smrg    rep->type = type;
7195dfecf96Smrg    irec_add_repetition(inf, rep);
7205dfecf96Smrg}
7215dfecf96Smrg
7225dfecf96Smrgstatic void
7235dfecf96Smrgirec_complex_repetition(irec_info *inf)
7245dfecf96Smrg{
7255dfecf96Smrg    int exact;
7265dfecf96Smrg    rec_rep *rep;
7275dfecf96Smrg    long mine, maxc;
7285dfecf96Smrg    unsigned char *end;
7295dfecf96Smrg
7305dfecf96Smrg	/* If nowhere to add repetition */
7315dfecf96Smrg    if ((inf->pgrp == NULL && inf->ppat == NULL) ||
7325dfecf96Smrg	/* If repetition already added to last/current pattern */
7335dfecf96Smrg	(inf->pgrp == NULL && inf->ppat->rep != NULL) ||
7345dfecf96Smrg	/* If repetition already added to last/current group */
7355dfecf96Smrg	(inf->ppat == NULL && inf->pgrp->parent->rep != NULL)) {
7365dfecf96Smrg	inf->ecode = RE_EBADBR;
7375dfecf96Smrg	return;
7385dfecf96Smrg    }
7395dfecf96Smrg
7405dfecf96Smrg    exact = 0;
7415dfecf96Smrg    mine = maxc = -1;
7425dfecf96Smrg    if (inf->ptr[0] == ',')
7435dfecf96Smrg	/* Specify max number of ocurrences only */
7445dfecf96Smrg	goto domax;
7455dfecf96Smrg    else if (!isdigit(inf->ptr[0]))
7465dfecf96Smrg	goto badbr;
7475dfecf96Smrg
7485dfecf96Smrg    mine = strtol((char*)inf->ptr, (char**)&end, 10);
7495dfecf96Smrg    inf->ptr = end;
7505dfecf96Smrg    if (inf->ptr[0] == '}') {
7515dfecf96Smrg	exact = 1;
7525dfecf96Smrg	++inf->ptr;
7535dfecf96Smrg	goto redone;
7545dfecf96Smrg    }
7555dfecf96Smrg    else if (inf->ptr[0] != ',')
7565dfecf96Smrg	goto badbr;
7575dfecf96Smrg
7585dfecf96Smrgdomax:
7595dfecf96Smrg	/* Add one to skip comma */
7605dfecf96Smrg    ++inf->ptr;
7615dfecf96Smrg    if (inf->ptr[0] == '}') {
7625dfecf96Smrg	++inf->ptr;
7635dfecf96Smrg	goto redone;
7645dfecf96Smrg    }
7655dfecf96Smrg    else if (!isdigit(inf->ptr[0]))
7665dfecf96Smrg	goto badbr;
7675dfecf96Smrg    maxc = strtol((char*)inf->ptr, (char**)&end, 10);
7685dfecf96Smrg    inf->ptr = end;
7695dfecf96Smrg    if (inf->ptr[0] != '}')
7705dfecf96Smrg	goto badbr;
7715dfecf96Smrg    ++inf->ptr;
7725dfecf96Smrg
7735dfecf96Smrgredone:
7745dfecf96Smrg    if (mine == maxc) {
7755dfecf96Smrg	maxc = -1;
7765dfecf96Smrg	exact = 1;
7775dfecf96Smrg    }
7785dfecf96Smrg
7795dfecf96Smrg    /* Check range and if min-max parameters are valid */
7805dfecf96Smrg    if (mine >= 255 || maxc >= 255 ||
7815dfecf96Smrg	(mine >= 0 && maxc >= 0 && mine > maxc))
7825dfecf96Smrg	goto badbr;
7835dfecf96Smrg
7845dfecf96Smrg    /* Check for noop */
7855dfecf96Smrg    if (exact && mine == 1)
7865dfecf96Smrg	return;
7875dfecf96Smrg
7885dfecf96Smrg    if ((rep = calloc(1, sizeof(rec_rep))) == NULL) {
7895dfecf96Smrg	inf->ecode = RE_ESPACE;
7905dfecf96Smrg	return;
7915dfecf96Smrg    }
7925dfecf96Smrg
7935dfecf96Smrg	/* Convert {0,1} to ? */
7945dfecf96Smrg    if (mine == 0 && maxc == 1)
7955dfecf96Smrg	rep->type = Rer_Maybe;
7965dfecf96Smrg    else if (exact) {
7975dfecf96Smrg	rep->type = Rer_Exact;
7985dfecf96Smrg	rep->mine = mine;
7995dfecf96Smrg    }
8005dfecf96Smrg	/* Convert {0,} to * */
8015dfecf96Smrg    else if (mine == 0 && maxc == -1)
8025dfecf96Smrg	rep->type = Rer_AnyTimes;
8035dfecf96Smrg	/* Convert {1,} to + */
8045dfecf96Smrg    else if (mine == 1 && maxc == -1)
8055dfecf96Smrg	rep->type = Rer_AtLeast;
8065dfecf96Smrg    else if (maxc == -1) {
8075dfecf96Smrg	rep->type = Rer_Min;
8085dfecf96Smrg	rep->mine = mine;
8095dfecf96Smrg    }
8105dfecf96Smrg    else if (mine < 1) {
8115dfecf96Smrg	rep->type = Rer_Max;
8125dfecf96Smrg	rep->maxc = maxc;
8135dfecf96Smrg    }
8145dfecf96Smrg    else {
8155dfecf96Smrg	rep->type = Rer_MinMax;
8165dfecf96Smrg	rep->mine = mine;
8175dfecf96Smrg	rep->maxc = maxc;
8185dfecf96Smrg    }
8195dfecf96Smrg
8205dfecf96Smrg    irec_add_repetition(inf, rep);
8215dfecf96Smrg
8225dfecf96Smrg    return;
8235dfecf96Smrg
8245dfecf96Smrgbadbr:
8255dfecf96Smrg    inf->ecode = RE_EBADBR;
8265dfecf96Smrg}
8275dfecf96Smrg
8285dfecf96Smrg/*  The rep argument is allocated and has no reference yet,
8295dfecf96Smrg * if something fails it must be freed before returning.
8305dfecf96Smrg */
8315dfecf96Smrgstatic void
8325dfecf96Smrgirec_add_repetition(irec_info *inf, rec_rep *rep)
8335dfecf96Smrg{
8345dfecf96Smrg    int length;
8355dfecf96Smrg    rec_pat *pat;
8365dfecf96Smrg    rec_grp *grp;
8375dfecf96Smrg    rec_rep_t rept;
8385dfecf96Smrg    unsigned char value, upper;
8395dfecf96Smrg
8405dfecf96Smrg    rept = rep->type;
8415dfecf96Smrg
8425dfecf96Smrg    if (inf->ppat == NULL) {
8435dfecf96Smrg	rec_pat *any;
8445dfecf96Smrg	rec_grp *grp = inf->pgrp;
8455dfecf96Smrg
8465dfecf96Smrg	if (rept == Rer_AnyTimes || rept == Rer_Maybe || rept == Re_AtLeast) {
8475dfecf96Smrg	    /* Convert (.)* to (.*), ((.))* not handled and may not match */
8485dfecf96Smrg	    any = NULL;
8495dfecf96Smrg
8505dfecf96Smrg	    if (grp->alt && grp->alt->pat) {
8515dfecf96Smrg		for (any = grp->alt->pat; any->next; any = any->next)
8525dfecf96Smrg		    ;
8535dfecf96Smrg		switch (any->type) {
8545dfecf96Smrg		    case Rep_Any:
8555dfecf96Smrg			break;
8565dfecf96Smrg		    case Rep_AnyAnyTimes:
8575dfecf96Smrg		    case Rep_AnyMaybe:
8585dfecf96Smrg		    case Rep_AnyAtLeast:
8595dfecf96Smrg			free(rep);
8605dfecf96Smrg			inf->ecode = RE_BADRPT;
8615dfecf96Smrg			return;
8625dfecf96Smrg		    default:
8635dfecf96Smrg			any = NULL;
8645dfecf96Smrg			break;
8655dfecf96Smrg		}
8665dfecf96Smrg	    }
8675dfecf96Smrg	    if (any) {
8685dfecf96Smrg		free(rep);
8695dfecf96Smrg		rep = NULL;
8705dfecf96Smrg		any->type = (rept == Rer_AnyTimes) ? Rep_AnyAnyTimes :
8715dfecf96Smrg			    (rept == Rer_AtLeast) ? Rep_AnyAtLeast :
8725dfecf96Smrg			    Rep_AnyMaybe;
8735dfecf96Smrg		while (grp) {
8745dfecf96Smrg		    ++grp->comp;
8755dfecf96Smrg		    grp = grp->pgrp;
8765dfecf96Smrg		}
8775dfecf96Smrg	    }
8785dfecf96Smrg	}
8795dfecf96Smrg	inf->pgrp->parent->rep = rep;
8805dfecf96Smrg	irec_close_group(inf);
8815dfecf96Smrg	return;
8825dfecf96Smrg    }
8835dfecf96Smrg
8845dfecf96Smrg    switch (inf->ppat->type) {
8855dfecf96Smrg	case Rep_Bol:
8865dfecf96Smrg	case Rep_Eol:
8875dfecf96Smrg	case Rep_Bow:
8885dfecf96Smrg	case Rep_Eow:
8895dfecf96Smrg	case Rep_AnyAnyTimes:
8905dfecf96Smrg	case Rep_AnyMaybe:
8915dfecf96Smrg	case Rep_AnyAtLeast:
8925dfecf96Smrg	    /* Markers that cannot repeat */
8935dfecf96Smrg	    free(rep);
8945dfecf96Smrg	    inf->ecode = RE_BADRPT;
8955dfecf96Smrg	    return;
8965dfecf96Smrg
8975dfecf96Smrg	case Rep_Any:
8985dfecf96Smrg	    grp = inf->pgrp;
8995dfecf96Smrg	    free(rep);
9005dfecf96Smrg	    if (rept == Rer_AnyTimes ||
9015dfecf96Smrg		rept == Rer_Maybe ||
9025dfecf96Smrg		rept == Rer_AtLeast) {
9035dfecf96Smrg		inf->ppat->type = (rept == Rer_AnyTimes) ?
9045dfecf96Smrg				   Rep_AnyAnyTimes :
9055dfecf96Smrg				  (rept == Rer_Maybe) ?
9065dfecf96Smrg				   Rep_AnyMaybe :
9075dfecf96Smrg				   Rep_AnyAtLeast;
9085dfecf96Smrg		while (grp) {
9095dfecf96Smrg		    ++grp->comp;
9105dfecf96Smrg		    grp = grp->pgrp;
9115dfecf96Smrg		}
9125dfecf96Smrg	    }
9135dfecf96Smrg	    else
9145dfecf96Smrg		/* XXX Not (yet) implemented */
9155dfecf96Smrg		inf->ecode = RE_BADRPT;
9165dfecf96Smrg	    rep = NULL;
9175dfecf96Smrg	    break;
9185dfecf96Smrg
9195dfecf96Smrg	case Rep_String:
9205dfecf96Smrg	    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
9215dfecf96Smrg		free(rep);
9225dfecf96Smrg		inf->ecode = RE_ESPACE;
9235dfecf96Smrg		return;
9245dfecf96Smrg	    }
9255dfecf96Smrg
9265dfecf96Smrg	    length = strlen((char*)inf->ppat->data.str);
9275dfecf96Smrg	    pat->type = Rep_Literal;
9285dfecf96Smrg	    pat->prev = inf->ppat;
9295dfecf96Smrg	    pat->data.chr = inf->ppat->data.str[length - 1];
9305dfecf96Smrg	    if (length == 2) {
9315dfecf96Smrg		/* Must convert to two Rep_Literals */
9325dfecf96Smrg		value = inf->ppat->data.str[0];
9335dfecf96Smrg		free(inf->ppat->data.str);
9345dfecf96Smrg		inf->ppat->data.chr = value;
9355dfecf96Smrg		inf->ppat->type = Rep_Literal;
9365dfecf96Smrg	    }
9375dfecf96Smrg	    else
9385dfecf96Smrg		/* Must remove last character from string */
9395dfecf96Smrg		inf->ppat->data.str[length - 1] = '\0';
9405dfecf96Smrg	    inf->ppat->next = pat;
9415dfecf96Smrg	    inf->ppat = pat;
9425dfecf96Smrg	    break;
9435dfecf96Smrg
9445dfecf96Smrg	case Rep_CaseString:
9455dfecf96Smrg	    if ((pat = calloc(1, sizeof(rec_pat))) == NULL) {
9465dfecf96Smrg		free(rep);
9475dfecf96Smrg		inf->ecode = RE_ESPACE;
9485dfecf96Smrg		return;
9495dfecf96Smrg	    }
9505dfecf96Smrg
9515dfecf96Smrg	    length = strlen((char*)inf->ppat->data.str);
9525dfecf96Smrg	    pat->type = Rep_CaseLiteral;
9535dfecf96Smrg	    pat->prev = inf->ppat;
9545dfecf96Smrg	    pat->data.cse.lower = inf->ppat->data.str[length - 2];
9555dfecf96Smrg	    pat->data.cse.upper = inf->ppat->data.str[length - 1];
9565dfecf96Smrg	    if (length == 4) {
9575dfecf96Smrg		/* Must convert to two Rep_CaseLiterals */
9585dfecf96Smrg		value = inf->ppat->data.str[0];
9595dfecf96Smrg		upper = inf->ppat->data.str[1];
9605dfecf96Smrg		free(inf->ppat->data.str);
9615dfecf96Smrg		inf->ppat->data.cse.lower = value;
9625dfecf96Smrg		inf->ppat->data.cse.upper = upper;
9635dfecf96Smrg		inf->ppat->next = pat;
9645dfecf96Smrg		inf->ppat->type = Rep_CaseLiteral;
9655dfecf96Smrg	    }
9665dfecf96Smrg	    else
9675dfecf96Smrg		/* Must remove last character pair from string */
9685dfecf96Smrg		inf->ppat->data.str[length - 2] = '\0';
9695dfecf96Smrg	    inf->ppat->next = pat;
9705dfecf96Smrg	    inf->ppat = pat;
9715dfecf96Smrg	    break;
9725dfecf96Smrg
9735dfecf96Smrg	default:
9745dfecf96Smrg	    /* Anything else does not need special handling */
9755dfecf96Smrg	    break;
9765dfecf96Smrg    }
9775dfecf96Smrg
9785dfecf96Smrg    inf->ppat->rep = rep;
9795dfecf96Smrg}
9805dfecf96Smrg
9815dfecf96Smrgstatic void
9825dfecf96Smrgirec_free(irec_info *inf)
9835dfecf96Smrg{
9845dfecf96Smrg    irec_free_alt(inf->alt);
9855dfecf96Smrg}
9865dfecf96Smrg
9875dfecf96Smrgstatic void
9885dfecf96Smrgirec_free_grp(rec_grp *grp)
9895dfecf96Smrg{
9905dfecf96Smrg    if (grp->alt)
9915dfecf96Smrg	irec_free_alt(grp->alt);
9925dfecf96Smrg    free(grp);
9935dfecf96Smrg}
9945dfecf96Smrg
9955dfecf96Smrgstatic void
9965dfecf96Smrgirec_free_pats(rec_pat *pat)
9975dfecf96Smrg{
9985dfecf96Smrg    rec_pat *next;
9995dfecf96Smrg    rec_pat_t rect;
10005dfecf96Smrg
10015dfecf96Smrg    while (pat) {
10025dfecf96Smrg	next = pat->next;
10035dfecf96Smrg	if (pat->rep)
10045dfecf96Smrg	    free(pat->rep);
10055dfecf96Smrg	rect = pat->type;
10065dfecf96Smrg	if (rect == Rep_Range || rect == Rep_RangeNot)
10075dfecf96Smrg	    free(pat->data.rng);
10085dfecf96Smrg	else if (rect == Rep_Group)
10095dfecf96Smrg	    irec_free_grp(pat->data.grp);
10105dfecf96Smrg	else if (rect == Rep_StringList)
10115dfecf96Smrg	    orec_free_stl(pat->data.stl);
10125dfecf96Smrg	free(pat);
10135dfecf96Smrg	pat = next;
10145dfecf96Smrg    }
10155dfecf96Smrg}
1016