#pragma weak _regcmp = regcmp
#include "lint.h"
#include "mtlib.h"
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <thread.h>
#include <wctype.h>
#include <widec.h>
#include <string.h>
#include "tsd.h"
#include "regex.h"
#define BACKSLASH '\\'
#define CIRCUMFLEX '^'
#define COMMA ','
#define DASH '-'
#define DOLLAR_SIGN '$'
#define DOT '.'
#define LEFT_CURLY_BRACE '{'
#define LEFT_PAREN '('
#define LEFT_SQUARE_BRACKET '['
#define PLUS '+'
#define RIGHT_CURLY_BRACE '}'
#define RIGHT_PAREN ')'
#define RIGHT_SQUARE_BRACKET ']'
#define SINGLE_BYTE_MASK 0xff
#define STRINGP_STACK_SIZE 50
#define STAR '*'
static char *compilep_stack[STRINGP_STACK_SIZE];
static char **compilep_stackp;
static mutex_t regcmp_lock = DEFAULTMUTEX;
static int add_char(char *compilep, wchar_t wchar);
static int add_single_char_expr(char *compilep, wchar_t wchar);
#define ERROR_EXIT(mutex_lockp, arg_listp, compile_startp) \
\
va_end(arg_listp); \
lmutex_unlock(mutex_lockp); \
if ((compile_startp) != (char *)0) \
free((void *)compile_startp); \
return ((char *)0)
static int get_count(int *countp, const char *regexp);
static int get_digit(const char *regexp);
static int get_wchar(wchar_t *wchar, const char *regexp);
static char *pop_compilep(void);
static char *push_compilep(char *compilep);
static boolean_t valid_range(wchar_t lower_char, wchar_t upper_char);
int __i_size;
int *
___i_size(void)
{
if (thr_main())
return (&__i_size);
return ((int *)tsdalloc(_T_REGCMP_ISIZE, sizeof (int), NULL));
}
#define __i_size (*(___i_size()))
extern char *
regcmp(const char *regexp, ...)
{
va_list arg_listp;
size_t arg_strlen;
boolean_t can_repeat;
int char_size;
unsigned int class_length;
char *compilep;
char *compile_startp = (char *)0;
int count_length;
wchar_t current_char;
int expr_length;
int groupn;
unsigned int group_length;
unsigned int high_bits;
boolean_t dash_indicates_range;
unsigned int low_bits;
int max_count;
int min_count;
const char *next_argp;
wchar_t first_char_in_range;
char *regex_typep;
int return_arg_number;
int substringn;
if (___i_size() == (int *)0)
return ((char *)0);
va_start(arg_listp, regexp);
next_argp = regexp;
arg_strlen = 0;
while (next_argp != (char *)0) {
arg_strlen += strlen(next_argp);
next_argp = va_arg(arg_listp, char *);
}
va_end(arg_listp);
if (arg_strlen == 0)
return ((char *)0);
compile_startp = (char *)malloc(3 * arg_strlen + 1);
if (compile_startp == (char *)0)
return ((char *)0);
lmutex_lock(®cmp_lock);
__i_size = 0;
compilep = compile_startp;
compilep_stackp = &compilep_stack[STRINGP_STACK_SIZE];
va_start(arg_listp, regexp);
next_argp = va_arg(arg_listp, char *);
char_size = get_wchar(¤t_char, regexp);
if (char_size < 0) {
ERROR_EXIT(®cmp_lock, arg_listp, compile_startp);
} else if (char_size > 0) {
regexp += char_size;
} else {
regexp = next_argp;
next_argp = va_arg(arg_listp, char *);
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock, arg_listp, compile_startp);
} else {
regexp += char_size;
}
}
if (current_char == CIRCUMFLEX) {
char_size = get_wchar(¤t_char, regexp);
if (char_size < 0) {
ERROR_EXIT(®cmp_lock, arg_listp, compile_startp);
} else if (char_size > 0) {
regexp += char_size;
*compilep = (unsigned char)START_OF_STRING_MARK;
compilep++;
} else if (next_argp != (char *)0) {
regexp = next_argp;
next_argp = va_arg(arg_listp, char *);
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
regexp += char_size;
}
*compilep = (unsigned char)START_OF_STRING_MARK;
compilep++;
} else {
*compilep = (unsigned char)START_OF_STRING_MARK;
compilep++;
*compilep = (unsigned char)END_REGEX;
compilep++;
*compilep = '\0';
compilep++;
__i_size = (int)(compilep - compile_startp);
va_end(arg_listp);
lmutex_unlock(®cmp_lock);
return (compile_startp);
}
}
groupn = 0;
substringn = 0;
can_repeat = B_FALSE;
for (;;) {
switch (current_char) {
case DOLLAR_SIGN:
char_size = get_wchar(¤t_char, regexp);
if ((char_size == 0) && (next_argp == (char *)0)) {
can_repeat = B_FALSE;
*compilep = (unsigned char)END_OF_STRING_MARK;
compilep++;
} else {
can_repeat = B_TRUE;
*compilep = (unsigned char)ASCII_CHAR;
regex_typep = compilep;
compilep++;
*compilep = DOLLAR_SIGN;
compilep++;
}
break;
case DOT:
can_repeat = B_TRUE;
*compilep = (unsigned char)ANY_CHAR;
regex_typep = compilep;
compilep++;
break;
case BACKSLASH:
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
regexp += char_size;
can_repeat = B_TRUE;
expr_length = add_single_char_expr(
compilep, current_char);
regex_typep = compilep;
compilep += expr_length;
}
break;
case LEFT_SQUARE_BRACKET:
can_repeat = B_TRUE;
regex_typep = compilep;
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else if (current_char == CIRCUMFLEX) {
regexp++;
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
} else {
regexp += char_size;
if (!multibyte) {
*compilep = (unsigned char)
NOT_IN_ASCII_CHAR_CLASS;
} else {
*compilep = (unsigned char)
NOT_IN_MULTIBYTE_CHAR_CLASS;
}
compilep += 2;
}
} else {
regexp += char_size;
if (!multibyte) {
*compilep = (unsigned char)
IN_ASCII_CHAR_CLASS;
} else {
*compilep = (unsigned char)
IN_MULTIBYTE_CHAR_CLASS;
}
compilep += 2;
}
if (current_char == RIGHT_SQUARE_BRACKET) {
dash_indicates_range = B_TRUE;
first_char_in_range = current_char;
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
} else {
regexp += char_size;
*compilep = RIGHT_SQUARE_BRACKET;
compilep++;
}
} else {
dash_indicates_range = B_FALSE;
}
while (current_char != RIGHT_SQUARE_BRACKET) {
if (current_char != DASH) {
dash_indicates_range = B_TRUE;
first_char_in_range = current_char;
expr_length = add_char(
compilep, current_char);
compilep += expr_length;
} else if
(dash_indicates_range == B_FALSE) {
*compilep = DASH;
compilep ++;
dash_indicates_range = B_TRUE;
first_char_in_range = current_char;
} else {
char_size = get_wchar(
¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
} else if (current_char ==
RIGHT_SQUARE_BRACKET) {
*compilep = DASH;
compilep++;
} else if (valid_range(
first_char_in_range,
current_char) == B_FALSE) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
} else {
regexp += char_size;
*compilep = (unsigned char)
THRU;
compilep++;
expr_length = add_char(
compilep, current_char);
compilep += expr_length;
dash_indicates_range =
B_FALSE;
}
}
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
} else {
regexp += char_size;
}
}
class_length = (unsigned int)
(compilep - regex_typep - 1);
if ((class_length < 2) ||
(class_length > MAX_SINGLE_BYTE_INT)) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
*(regex_typep + 1) = (unsigned char)
class_length;
}
break;
case LEFT_PAREN:
if (push_compilep(compilep) == (char *)0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
can_repeat = B_FALSE;
*compilep = '\0';
compilep++;
*compilep = '\0';
compilep++;
}
break;
case RIGHT_PAREN:
regex_typep = pop_compilep();
if (regex_typep == (char *)0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
}
char_size = get_wchar(¤t_char, regexp);
if (char_size < 0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else if (char_size == 0) {
*regex_typep = SIMPLE_GROUP;
can_repeat = B_TRUE;
*compilep = (unsigned char)END_GROUP;
regex_typep = compilep;
compilep++;
*compilep = (unsigned char)groupn;
groupn++;
compilep++;
} else if (current_char == DOLLAR_SIGN) {
*regex_typep = SAVED_GROUP;
regex_typep++;
*regex_typep = (char)substringn;
can_repeat = B_FALSE;
regexp ++;
return_arg_number = get_digit(regexp);
if ((return_arg_number < 0) ||
(substringn >= NSUBSTRINGS)) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
}
regexp++;
*compilep = (unsigned char)END_SAVED_GROUP;
compilep++;
*compilep = (unsigned char)substringn;
substringn++;
compilep++;
*compilep = (unsigned char)return_arg_number;
compilep++;
} else {
switch (current_char) {
case STAR:
*regex_typep = ZERO_OR_MORE_GROUP;
break;
case PLUS:
*regex_typep = ONE_OR_MORE_GROUP;
break;
case LEFT_CURLY_BRACE:
*regex_typep = COUNTED_GROUP;
break;
default:
*regex_typep = SIMPLE_GROUP;
}
if (*regex_typep != SIMPLE_GROUP) {
group_length = (unsigned int)
(compilep - regex_typep);
if (group_length >= 1024) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
}
high_bits = group_length >>
TIMES_256_SHIFT;
low_bits = group_length &
SINGLE_BYTE_MASK;
*regex_typep =
(unsigned char)
((unsigned int)
*regex_typep | high_bits);
regex_typep++;
*regex_typep =
(unsigned char)low_bits;
}
can_repeat = B_TRUE;
*compilep = (unsigned char)END_GROUP;
regex_typep = compilep;
compilep++;
*compilep = (unsigned char)groupn;
groupn++;
compilep++;
}
break;
case STAR:
if (can_repeat == B_FALSE) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
can_repeat = B_FALSE;
*regex_typep = (unsigned char)
((unsigned int)*regex_typep | ZERO_OR_MORE);
}
break;
case PLUS:
if (can_repeat == B_FALSE) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
can_repeat = B_FALSE;
*regex_typep =
(unsigned char)((unsigned int)*
regex_typep | ONE_OR_MORE);
}
break;
case LEFT_CURLY_BRACE:
if (can_repeat == B_FALSE) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
}
can_repeat = B_FALSE;
*regex_typep = (unsigned char)((unsigned int)*
regex_typep | COUNT);
count_length = get_count(&min_count, regexp);
if (count_length <= 0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
}
regexp += count_length;
if (*regexp == RIGHT_CURLY_BRACE) {
regexp++;
max_count = min_count;
} else if (*regexp == COMMA) {
regexp++;
if (*regexp == RIGHT_CURLY_BRACE) {
regexp++;
max_count = UNLIMITED;
} else {
count_length = get_count(
&max_count, regexp);
if (count_length <= 0) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
}
regexp += count_length;
if (*regexp != RIGHT_CURLY_BRACE) {
ERROR_EXIT(®cmp_lock,
arg_listp, compile_startp);
}
regexp++;
}
} else {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
}
if ((min_count > MAX_SINGLE_BYTE_INT) ||
((max_count != UNLIMITED) &&
(min_count > max_count))) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
*compilep = (unsigned char)min_count;
compilep++;
*compilep = (unsigned char)max_count;
compilep++;
}
break;
default:
can_repeat = B_TRUE;
regex_typep = compilep;
expr_length = add_single_char_expr(compilep,
current_char);
compilep += expr_length;
}
char_size = get_wchar(¤t_char, regexp);
if (char_size < 0) {
ERROR_EXIT(®cmp_lock, arg_listp, compile_startp);
} else if (char_size > 0) {
regexp += char_size;
} else if (next_argp != (char *)0) {
regexp = next_argp;
next_argp = va_arg(arg_listp, char *);
char_size = get_wchar(¤t_char, regexp);
if (char_size <= 0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
} else {
regexp += char_size;
}
} else {
if (pop_compilep() != (char *)0) {
ERROR_EXIT(®cmp_lock, arg_listp,
compile_startp);
}
*compilep = (unsigned char)END_REGEX;
compilep++;
*compilep = '\0';
compilep++;
__i_size = (int)(compilep - compile_startp);
va_end(arg_listp);
lmutex_unlock(®cmp_lock);
return (compile_startp);
}
}
}
static int
add_char(char *compilep, wchar_t wchar)
{
int expr_length;
if ((unsigned int)wchar <= (unsigned int)0x7f) {
*compilep = (unsigned char)wchar;
expr_length = 1;
} else {
expr_length = wctomb(compilep, wchar);
}
return (expr_length);
}
static int
add_single_char_expr(char *compilep, wchar_t wchar)
{
int expr_length = 0;
if ((unsigned int)wchar <= (unsigned int)0x7f) {
*compilep = (unsigned char)ASCII_CHAR;
compilep++;
*compilep = (unsigned char)wchar;
expr_length += 2;
} else {
*compilep = (unsigned char)MULTIBYTE_CHAR;
compilep++;
expr_length++;
expr_length += wctomb(compilep, wchar);
}
return (expr_length);
}
static int
get_count(int *countp, const char *regexp)
{
char count_char = '0';
int count = 0;
int count_length = 0;
if (regexp == (char *)0) {
return ((int)0);
} else {
count_char = *regexp;
while (('0' <= count_char) && (count_char <= '9')) {
count = (10 * count) + (int)(count_char - '0');
count_length++;
regexp++;
count_char = *regexp;
}
}
*countp = count;
return (count_length);
}
static int
get_digit(const char *regexp)
{
char digit;
if (regexp == (char *)0) {
return ((int)-1);
} else {
digit = *regexp;
if (('0' <= digit) && (digit <= '9')) {
return ((int)(digit - '0'));
} else {
return ((int)-1);
}
}
}
static int
get_wchar(wchar_t *wcharp, const char *regexp)
{
int char_size;
if (regexp == (char *)0) {
char_size = 0;
*wcharp = (wchar_t)((unsigned int)'\0');
} else if (*regexp == '\0') {
char_size = 0;
*wcharp = (wchar_t)((unsigned int)*regexp);
} else if ((unsigned char)*regexp <= (unsigned char)0x7f) {
char_size = 1;
*wcharp = (wchar_t)((unsigned int)*regexp);
} else {
char_size = mbtowc(wcharp, regexp, MB_LEN_MAX);
}
return (char_size);
}
static char *
pop_compilep(void)
{
char *compilep;
if (compilep_stackp >= &compilep_stack[STRINGP_STACK_SIZE]) {
return ((char *)0);
} else {
compilep = *compilep_stackp;
compilep_stackp++;
return (compilep);
}
}
static char *
push_compilep(char *compilep)
{
if (compilep_stackp <= &compilep_stack[0]) {
return ((char *)0);
} else {
compilep_stackp--;
*compilep_stackp = compilep;
return (compilep);
}
}
static boolean_t
valid_range(wchar_t lower_char, wchar_t upper_char)
{
return (((lower_char <= 0x7f) && (upper_char <= 0x7f) &&
!iswcntrl(lower_char) && !iswcntrl(upper_char) &&
(lower_char < upper_char)) ||
(((lower_char & WCHAR_CSMASK) ==
(upper_char & WCHAR_CSMASK)) &&
(lower_char < upper_char)));
}