/* ed style regular expressions */
/* Copyright (c) 1992, 1999, 2001 John E. Davis
*
* You may distribute under the terms of either the GNU General Public
* License or the Perl Artistic License.
*/
#include "slinclud.h"
#include "slang.h"
#include "_slang.h"
#define SET_BIT(b, n) b[(unsigned int) (n) >> 3] |= 1 << ((unsigned int) (n) % 8)
#define TEST_BIT(b, n) (b[(unsigned int)(n) >> 3] & (1 << ((unsigned int) (n) % 8)))
#define LITERAL 1
#define RANGE 2 /* [...] */
#define ANY 3 /* . */
#define BOL 4 /* ^ */
#define EOL 5 /* $ */
#define NTH_MATCH 6 /* \1 \2 ... \9 */
#define OPAREN 7 /* \( */
#define CPAREN 0x8 /* \) */
#define ANY_DIGIT 0x9 /* \d */
#define BOW 0xA /* \< */
#define EOW 0xB /* \> */
#if 0
#define NOT_LITERAL 0xC /* \~ */
#endif
#define STAR 0x80 /* * */
#define LEAST_ONCE 0x40 /* + */
#define MAYBE_ONCE 0x20 /* ? */
#define MANY 0x10 /* {n,m} */
/* The rest are additions */
#define YES_CASE (STAR | BOL)
#define NO_CASE (STAR | EOL)
#define UPPERCASE(x) (cs ? (x) : UPPER_CASE(x))
#define LOWERCASE(x) (cs ? (x) : LOWER_CASE(x))
static unsigned char Word_Chars[256];
#define IS_WORD_CHAR(x) Word_Chars[(unsigned int) (x)]
#if 0
static int ctx->open_paren_number;
static char Closed_Paren_Matches[10];
static SLRegexp_Type *This_Reg;
static unsigned char *This_Str;
#endif
typedef struct
{
SLRegexp_Type *reg;
unsigned char *str;
unsigned int len;
char closed_paren_matches[10];
int open_paren_number;
}
Re_Context_Type;
static unsigned char *do_nth_match (Re_Context_Type *ctx, int n, unsigned char *str, unsigned char *estr)
{
unsigned char *bpos;
if (ctx->closed_paren_matches[n] == 0)
return NULL;
bpos = ctx->reg->beg_matches[n] + ctx->str;
n = ctx->reg->end_matches[n];
if (n == 0) return(str);
if (n > (int) (estr - str)) return (NULL);
/* This needs fixed for case sensitive match */
if (0 != strncmp((char *) str, (char *) bpos, (unsigned int) n)) return (NULL);
str += n;
return (str);
}
/* returns pointer to the end of regexp or NULL */
static unsigned char *regexp_looking_at (Re_Context_Type *ctx, register unsigned char *str, unsigned char *estr, unsigned char *buf, register int cs)
{
register unsigned char p, p1;
unsigned char *save_str, *tmpstr;
int n, n0, n1;
int save_num_open;
char save_closed_matches[10];
p = *buf++;
while (p != 0)
{
/* p1 = UPPERCASE(*buf); */
/* if (str < estr) c = UPPERCASE(*str); */
switch((unsigned char) p)
{
case BOW:
if ((str != ctx->str)
&& ((str >= estr)
|| IS_WORD_CHAR(*(str - 1))
|| (0 == IS_WORD_CHAR(*str)))) return NULL;
break;
case EOW:
if ((str < estr)
&& IS_WORD_CHAR (*str)) return NULL;
break;
case YES_CASE: cs = 1; break;
case NO_CASE: cs = 0; break;
case OPAREN:
ctx->open_paren_number++;
ctx->reg->beg_matches[ctx->open_paren_number] = (int) (str - ctx->str);
break;
case CPAREN:
n = ctx->open_paren_number;
while (n > 0)
{
if (ctx->closed_paren_matches[n] != 0)
{
n--;
continue;
}
ctx->closed_paren_matches[n] = 1;
ctx->reg->end_matches[n] = (unsigned int) (str - (ctx->str + ctx->reg->beg_matches[n]));
break;
}
break;
#ifdef NOT_LITERAL
case NOT_LITERAL:
if ((str >= estr) || (*buf == UPPERCASE(*str))) return (NULL);
str++; buf++;
break;
case MAYBE_ONCE | NOT_LITERAL:
save_str = str;
if ((str < estr) && (*buf != UPPERCASE(*str))) str++;
buf++;
goto match_rest;
case NOT_LITERAL | LEAST_ONCE: /* match at least once */
if ((str >= estr) || (UPPERCASE(*str) == UPPERCASE(*buf))) return (NULL);
str++;
/* drop */
case STAR | NOT_LITERAL:
save_str = str; p1 = *buf;
while ((str < estr) && (UPPERCASE(*str) != p1)) str++;
buf++;
goto match_rest;
/* this type consists of the expression + two bytes that
determine number of matches to perform */
case MANY | NOT_LITERAL:
p1 = *buf; buf++;
n = n0 = (int) (unsigned char) *buf++;
/* minimum number to match--- could be 0 */
n1 = (int) (unsigned char) *buf++;
/* maximum number to match */
while (n && (str < estr) && (p1 != *str))
{
n--;
str++;
}
if (n) return (NULL);
save_str = str;
n = n1 - n0;
while (n && (str < estr) && (p1 != *str))
{
n--;
str++;
}
goto match_rest;
#endif /* NOT_LITERAL */
case LITERAL:
if ((str >= estr) || (*buf != UPPERCASE(*str))) return (NULL);
str++; buf++;
break;
case MAYBE_ONCE | LITERAL:
save_str = str;
if ((str < estr) && (*buf == UPPERCASE(*str))) str++;
buf++;
goto match_rest;
case LITERAL | LEAST_ONCE: /* match at least once */
if ((str >= estr) || (UPPERCASE(*str) != UPPERCASE(*buf))) return (NULL);
str++;
/* drop */
case STAR | LITERAL:
save_str = str; p1 = *buf;
while ((str < estr) && (UPPERCASE(*str) == p1)) str++;
buf++;
goto match_rest;
/* this type consists of the expression + two bytes that
determine number of matches to perform */
case MANY | LITERAL:
p1 = *buf; buf++;
n = n0 = (int) (unsigned char) *buf++;
/* minimum number to match--- could be 0 */
n1 = (int) (unsigned char) *buf++;
/* maximum number to match */
while (n && (str < estr) && (p1 == *str))
{
n--;
str++;
}
if (n) return (NULL);
save_str = str;
n = n1 - n0;
while (n && (str < estr) && (p1 == *str))
{
n--;
str++;
}
goto match_rest;
case NTH_MATCH:
if ((str = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)) == NULL) return(NULL);
buf++;
break;
case MAYBE_ONCE | NTH_MATCH:
save_str = str;
tmpstr = do_nth_match (ctx, (int) (unsigned char) *buf, str, estr);
buf++;
if (tmpstr != NULL)
{
str = tmpstr;
goto match_rest;
}
continue;
case LEAST_ONCE | NTH_MATCH:
if ((str = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)) == NULL) return(NULL);
/* drop */
case STAR | NTH_MATCH:
save_str = str;
while (NULL != (tmpstr = do_nth_match(ctx, (int) (unsigned char) *buf, str, estr)))
{
str = tmpstr;
}
buf++;
goto match_rest;
case MANY | NTH_MATCH: return(NULL);
/* needs done */
case RANGE:
if (str >= estr) return (NULL);
if (TEST_BIT(buf, UPPERCASE(*str)) == 0) return (NULL);
buf += 32; str++;
break;
case MAYBE_ONCE | RANGE:
save_str = str;
if ((str < estr) && TEST_BIT(buf, UPPERCASE(*str))) str++;
buf += 32;
goto match_rest;
case LEAST_ONCE | RANGE:
if ((str >= estr) || (0 == TEST_BIT(buf, UPPERCASE(*str)))) return NULL;
str++;
/* drop */
case STAR | RANGE:
save_str = str;
while ((str < estr) && TEST_BIT(buf, UPPERCASE(*str))) str++;
buf += 32;
goto match_rest;
/* The first 32 bytes correspond to the range and the two
* following bytes indicate the min and max number of matches.
*/
case MANY | RANGE:
/* minimum number to match--- could be 0 */
n = n0 = (int) (unsigned char) *(buf + 32);
/* maximum number to match */
n1 = (int) (unsigned char) *(buf + 33);
while (n && (str < estr) && (TEST_BIT(buf, UPPERCASE(*str))))
{
n--;
str++;
}
if (n) return (NULL);
save_str = str;
n = n1 - n0;
while (n && (str < estr) && (TEST_BIT(buf, UPPERCASE(*str))))
{
n--;
str++;
}
buf += 34; /* 32 + 2 */
goto match_rest;
case ANY_DIGIT:
if ((str >= estr) || (*str > '9') || (*str < '0')) return (NULL);
str++;
break;
case MAYBE_ONCE | ANY_DIGIT:
save_str = str;
if ((str < estr) && ((*str > '9') || (*str < '0'))) str++;
goto match_rest;
case LEAST_ONCE | ANY_DIGIT:
if ((str >= estr) || ((*str > '9') || (*str < '0'))) return NULL;
str++;
/* drop */
case STAR | ANY_DIGIT:
save_str = str;
while ((str < estr) && ((*str <= '9') && (*str >= '0'))) str++;
goto match_rest;
case MANY | ANY_DIGIT:
/* needs finished */
return (NULL);
case ANY:
if ((str >= estr) || (*str == '\n')) return (NULL);
str++;
break;
case MAYBE_ONCE | ANY:
save_str = str;
if ((str < estr) && (*str != '\n')) str++;
goto match_rest;
case LEAST_ONCE | ANY:
if ((str >= estr) || (*str == '\n')) return (NULL);
str++;
/* drop */
case STAR | ANY:
save_str = str;
while ((str < estr) && (*str != '\n')) str++;
goto match_rest;
case MANY | ANY:
return (NULL);
/* needs finished */
case EOL:
if ((str >= estr) || (*str == '\n')) return (str);
return(NULL);
default: return (NULL);
}
p = *buf++;
continue;
match_rest:
if (save_str == str)
{
p = *buf++;
continue;
}
/* if (p == EOL)
* {
* if (str < estr) return (NULL); else return (str);
* }
*/
SLMEMCPY(save_closed_matches, ctx->closed_paren_matches, sizeof(save_closed_matches));
save_num_open = ctx->open_paren_number;
while (str >= save_str)
{
tmpstr = regexp_looking_at (ctx, str, estr, buf, cs);
if (tmpstr != NULL) return(tmpstr);
SLMEMCPY(ctx->closed_paren_matches, save_closed_matches, sizeof(ctx->closed_paren_matches));
ctx->open_paren_number = save_num_open;
str--;
}
return NULL;
}
if ((p != 0) && (p != EOL)) return (NULL); else return (str);
}
static void
fixup_beg_end_matches (Re_Context_Type *ctx, SLRegexp_Type *r, unsigned char *str, unsigned char *epos)
{
int i;
if (str == NULL)
{
r->beg_matches[0] = -1;
r->end_matches[0] = 0;
SLMEMSET(ctx->closed_paren_matches, 0, sizeof(ctx->closed_paren_matches));
}
else
{
r->beg_matches[0] = (int) (str - ctx->str);
r->end_matches[0] = (unsigned int) (epos - str);
}
for (i = 1; i < 10; i++)
{
if (ctx->closed_paren_matches [i] == 0)
{
r->beg_matches[i] = -1;
r->end_matches[i] = 0;
}
}
}
static void init_re_context (Re_Context_Type *ctx, SLRegexp_Type *reg,
unsigned char *str, unsigned int len)
{
memset ((char *) ctx, 0, sizeof (Re_Context_Type));
ctx->reg = reg;
ctx->str = str;
ctx->len = len;
}
unsigned char *SLang_regexp_match(unsigned char *str,
unsigned int len, SLRegexp_Type *reg)
{
register unsigned char c = 0, *estr = str + len;
int cs = reg->case_sensitive, lit = 0;
unsigned char *buf = reg->buf, *epos = NULL;
Re_Context_Type ctx_buf;
if (reg->min_length > len) return NULL;
init_re_context (&ctx_buf, reg, str, len);
if (*buf == BOL)
{
if (NULL == (epos = regexp_looking_at (&ctx_buf, str, estr, buf + 1, cs)))
str = NULL;
fixup_beg_end_matches (&ctx_buf, reg, str, epos);
return str;
}
if (*buf == NO_CASE)
selectMouse => [ N_("_: Keep these entry short\nMouse"), 1, 1, '1', '', N_("Mouse") ],
setupSCSI => [ N_("_: Keep these entry short\nHard drive detection"), 1, 0, '1', '',
N_("_: Keep these entry short\nHard drive detection") ],
selectInstallClass => [ N_("_: Keep these entry short\nInstallation class"), 1, 1, '1', '',
N_("_: Keep these entry short\nInstallation class") ],
selectKeyboard => [ N_("_: Keep these entry short\nKeyboard"), 1, 1, '1', '', N_("Localization") ],
miscellaneous => [ N_("_: Keep these entry short\nSecurity"), 1, 1, '1', '', N_("Security") ],
doPartitionDisks => [ N_("_: Keep these entry short\nPartitioning"), 1, 0, '', "selectInstallClass",
N_("Partitioning") ],
formatPartitions => [ N_("_: Keep these entry short\nFormatting"), 1, -1, '1', "doPartitionDisks",
N_("_: Keep these entry short\nFormatting") ],
choosePackages => [ N_("_: Keep these entry short\nChoosing packages"), 1, -2, '1', "formatPartitions",
N_("Package Group Selection") ],
installPackages => [ N_("_: Keep these entry short\nInstalling"), 1, -1, '', ["formatPartitions", "selectInstallClass"],
N_("Installing") ],
setRootPassword_addUser
=> [ N_("_: Keep these entry short\nUsers"), 1, 1, '', "installPackages",
N_("User management") ],
configureNetwork => [ N_("_: Keep these entry short\nNetworking"), 1, 1, '1', "formatPartitions",
N_("_: Keep these entry short\nNetworking") ],
setupBootloader => [ N_("_: Keep these entry short\nBootloader"), 1, 0, '1', "installPackages",
N_("_: Keep these entry short\nBootloader") ],
configureX => [ N_("_: Keep these entry short\nConfigure X"), 1, 1, '1', ["formatPartitions", "setupBootloader"],
N_("_: Keep these entry short\nConfigure X&q