/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* IMPORTANT NOTE:
*
* regcmp() WORKS **ONLY** WITH THE ASCII AND THE Solaris EUC CHARACTER SETS.
* IT IS **NOT** CHARACTER SET INDEPENDENT.
*
*/
#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"
/* CONSTANTS SHARED WITH regex() */
#include "regex.h"
/* PRIVATE CONSTANTS */
/* PRIVATE GLOBAL VARIABLES */
static char **compilep_stackp;
/* DECLARATIONS OF PRIVATE FUNCTIONS */
\
if ((compile_startp) != (char *)0) \
free((void *)compile_startp); \
return ((char *)0)
static char *pop_compilep(void);
static char *push_compilep(char *compilep);
/* DEFINITIONS OF PUBLIC VARIABLES */
int __i_size;
/*
* define thread-specific storage for __i_size
*
*/
int *
___i_size(void)
{
if (thr_main())
return (&__i_size);
}
/* DEFINITION OF regcmp() */
extern char *
{
int char_size;
unsigned int class_length;
char *compilep;
char *compile_startp = (char *)0;
int count_length;
int expr_length;
int groupn;
unsigned int group_length;
unsigned int high_bits;
unsigned int low_bits;
int max_count;
int min_count;
const char *next_argp;
char *regex_typep;
int return_arg_number;
int substringn;
if (___i_size() == (int *)0)
return ((char *)0);
/*
* When compiling a regular expression, regcmp() generates at most
* two extra single-byte characters for each character in the
* expression, so allocating three times the number of bytes in all
* the strings that comprise the regular expression will ensure that
* regcmp() won't overwrite the end of the allocated block when
* compiling the expression.
*/
arg_strlen = 0;
while (next_argp != (char *)0) {
}
if (arg_strlen == 0)
return ((char *)0);
if (compile_startp == (char *)0)
return ((char *)0);
__i_size = 0;
/* GET THE FIRST CHARACTER IN THE REGULAR EXPRESSION */
if (char_size < 0) {
} else if (char_size > 0) {
} else /* (char_size == 0 ) */ {
if (char_size <= 0) {
} else {
}
}
/* FIND OUT IF THE EXPRESSION MUST START AT THE START OF A STRING */
if (current_char == CIRCUMFLEX) {
if (char_size < 0) {
} else if (char_size > 0) {
*compilep = (unsigned char)START_OF_STRING_MARK;
compilep++;
} else if /* (char_size == 0) && */ (next_argp != (char *)0) {
if (char_size <= 0) {
} else {
}
*compilep = (unsigned char)START_OF_STRING_MARK;
compilep++;
} else {
/* ((char_size==0) && (next_argp==(char *)0)) */
/*
* the regular expression is "^"
*/
*compilep = (unsigned char)START_OF_STRING_MARK;
compilep++;
compilep++;
*compilep = '\0';
compilep++;
return (compile_startp);
}
}
/* COMPILE THE REGULAR EXPRESSION */
groupn = 0;
substringn = 0;
for (;;) {
/*
* At the end of each iteration get the next character
* from the regular expression and increment regexp to
* point to the following character. Exit when all
* the characters in all the strings in the argument
* list have been read.
*/
switch (current_char) {
/*
* No fall-through. Each case ends with either
* a break or an error exit. Each case starts
* with compilep addressing the next location to
* be written in the compiled regular expression,
* and with regexp addressing the next character
* to be read from the regular expression being
* compiled. Each case that doesn't return
* increments regexp to address the next character
* to be read from the regular expression and
* increments compilep to address the next
* location to be written in the compiled
* regular expression.
*
* NOTE: The comments for each case give the meaning
* of the regular expression compiled by the case
* and the character string written to the compiled
* regular expression by the case. Each single
* character
* written to the compiled regular expression is
* shown enclosed in angle brackets (<>). Each
* compiled regular expression begins with a marker
* character which is shown as a named constant
* (e.g. <ASCII_CHAR>). Character constants are
* shown enclosed in single quotes (e.g. <'$'>).
* All other single characters written to the
* compiled regular expression are shown as lower
* case variable names (e.g. <ascii_char> or
* <multibyte_char>). Multicharacter
* strings written to the compiled regular expression
* are shown as variable names followed by elipses
* (e.g. <regex...>).
*/
case DOLLAR_SIGN:
/* end of string marker or simple dollar sign */
/* compiles to <END_OF_STRING_MARK> or */
/* <ASCII_CHAR><'$'> */
*compilep = (unsigned char)END_OF_STRING_MARK;
compilep++;
} else {
can_repeat = B_TRUE;
*compilep = (unsigned char)ASCII_CHAR;
compilep++;
*compilep = DOLLAR_SIGN;
compilep++;
}
break; /* end case DOLLAR_SIGN */
case DOT: /* any character */
/* compiles to <ANY_CHAR> */
can_repeat = B_TRUE;
compilep++;
break; /* end case DOT */
case BACKSLASH: /* escaped character */
/*
* compiles to <ASCII_CHAR><ascii_char> or
* <MULTIBYTE_CHAR><multibyte_char>
*/
if (char_size <= 0) {
} else {
can_repeat = B_TRUE;
compilep += expr_length;
}
break; /* end case '\\' */
case LEFT_SQUARE_BRACKET:
/* start of a character class expression */
/*
* [^...c...] compiles to
* <NOT_IN_CLASS><class_length><...c...>
* [^...a-z...] compiles to
* <NOT_IN_CLASS><class_length><...a<THRU>z...>
* [...c...] compiles to
* <IN_CLASS><class_length><...c...>
* [...a-z...] compiles to
* <IN_CLASS><class_length><...a<THRU>z...>
*
* NOTE: <class_length> includes the
* <class_length> byte
*/
can_repeat = B_TRUE;
/* DETERMINE THE CLASS TYPE */
/*
* NOTE: This algorithm checks the value of the
* "multibyte"
* to find out if regcmp()
* is compiling the regular expression in a
* multibyte locale.
*/
if (char_size <= 0) {
} else if (current_char == CIRCUMFLEX) {
regexp++;
if (char_size <= 0) {
} else {
if (!multibyte) {
*compilep = (unsigned char)
} else {
*compilep = (unsigned char)
}
/* leave space for <class_length> */
compilep += 2;
}
} else {
if (!multibyte) {
*compilep = (unsigned char)
} else {
*compilep = (unsigned char)
}
/* leave space for <class_length> */
compilep += 2;
}
/* COMPILE THE CLASS */
/*
* check for a leading right square bracket,
* which is allowed
*/
if (current_char == RIGHT_SQUARE_BRACKET) {
/*
* the leading RIGHT_SQUARE_BRACKET may
* be part of a character range
* expression like "[]-\]"
*/
if (char_size <= 0) {
} else {
compilep++;
}
} else {
/*
* decode the character in the following
* while loop and decide then if it can
* be the first character
* in a character range expression
*/
}
while (current_char != RIGHT_SQUARE_BRACKET) {
if (current_char != DASH) {
/*
* if a DASH follows current_char,
* current_char, the DASH and the
* character that follows the DASH
* may form a character range
* expression
*/
compilep += expr_length;
} else if /* (current_char == DASH) && */
(dash_indicates_range == B_FALSE) {
/*
* current_char is a DASH, but
* either begins the entire
* character class or follows a
* character that's already
* part of a character range
* expression, so it simply
* represents the DASH character
* itself
*/
compilep ++;
/*
* if another DASH follows this
* one, this DASH is part
* of a character range expression
* like "[--\]"
*/
} else {
/*
* ((current_char == DASH &&/
* (dash_indicates_range == B_TRUE))
*/
/*
* the DASH appears after a single
* character that isn't
* already part of a character
* range expression, so it
* and the characters preceding
* and following it can form a
* character range expression
* like "[a-z]"
*/
¤t_char, regexp);
if (char_size <= 0) {
} else if (current_char ==
/*
* the preceding DASH is
* the last character in the
* class and represents the
* DASH character itself
*/
compilep++;
} else if (valid_range(
current_char) == B_FALSE) {
} else {
/*
* the DASH is part of a
* character range
* expression; encode the
* rest of the expression
*/
*compilep = (unsigned char)
THRU;
compilep++;
compilep += expr_length;
/*
* if a DASH follows this
* character range
* expression,
* it represents the DASH
* character itself
*/
}
}
/* GET THE NEXT CHARACTER */
if (char_size <= 0) {
} else {
}
}
/* end while (current_char != RIGHT_SQUARE_BRACKET) */
/* INSERT THE LENGTH OF THE CLASS INTO THE */
/* COMPILED EXPRESSION */
class_length = (unsigned int)
if ((class_length < 2) ||
(class_length > MAX_SINGLE_BYTE_INT)) {
} else {
*(regex_typep + 1) = (unsigned char)
}
break; /* end case LEFT_SQUARE_BRACKET */
case LEFT_PAREN:
/*
* start of a parenthesized group of regular
* expressions compiles to <'\0'><'\0'>, leaving
* space in the compiled regular expression for
* <group_type|ADDED_LENGTH_BITS><group_length>
*/
if (push_compilep(compilep) == (char *)0) {
/*
* groups can contain groups, so group
* start pointers
* must be saved and restored in sequence
*/
} else {
compilep++;
compilep++;
}
break; /* end case LEFT_PAREN */
case RIGHT_PAREN:
/* end of a marked group of regular expressions */
/*
* (<regex>)$0-9 compiles to
* <SAVED_GROUP><substringn><compiled_regex...>\
* <END_SAVED_GROUP><substringn><return_arg_number>
* (<regex>)* compiles to
* <ZERO_OR_MORE_GROUP|ADDED_LENGTH_BITS>
* <group_length> <compiled_regex...>
* <END_GROUP|ZERO_OR_MORE><groupn>
* (<regex>)+ compiles to
* <ONE_OR_MORE_GROUP|ADDED_LENGTH_BITS>
* <group_length>\
* <compiled_regex...><END_GROUP|ONE_OR_MORE>
* <groupn>
* (<regex>){...} compiles to
* <COUNTED_GROUP|ADDED_LENGTH_BITS><group_length>\
* <compiled_regex...><END_GROUP|COUNT><groupn>\
* <minimum_repeat_count><maximum_repeat_count>
* otherwise (<regex>) compiles to
* <SIMPLE_GROUP><blank><compiled_regex...>
* <END_GROUP><groupn>
*
* NOTE:
*
* group_length + (256 * ADDED_LENGTH_BITS) ==
* length_of(<compiled_regex...><END_GROUP|...>
* <groupn>)
* which also ==
* length_of(<group_type|ADDED_LENGTH_BITS>
* <group_length>\ <compiled_regex...>)
* groupn no longer seems to be used, but the code
* still computes it to preserve backward
* compatibility
* with earlier versions of regex().
*/
/* RETRIEVE THE ADDRESS OF THE START OF THE GROUP */
regex_typep = pop_compilep();
if (regex_typep == (char *)0) {
}
if (char_size < 0) {
} else if (char_size == 0) {
can_repeat = B_TRUE;
compilep++;
groupn++;
compilep++;
} else if (current_char == DOLLAR_SIGN) {
regex_typep++;
*regex_typep = (char)substringn;
regexp ++;
if ((return_arg_number < 0) ||
(substringn >= NSUBSTRINGS)) {
}
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:
break;
case PLUS:
break;
case LEFT_CURLY_BRACE:
break;
default:
}
if (*regex_typep != SIMPLE_GROUP) {
group_length = (unsigned int)
(compilep - regex_typep);
if (group_length >= 1024) {
}
high_bits = group_length >>
low_bits = group_length &
*regex_typep =
(unsigned char)
((unsigned int)
*regex_typep | high_bits);
regex_typep++;
*regex_typep =
(unsigned char)low_bits;
}
can_repeat = B_TRUE;
compilep++;
groupn++;
compilep++;
}
break; /* end case RIGHT_PAREN */
case STAR: /* zero or more repetitions of the */
/* preceding expression */
/*
* <regex...>* compiles to <regex_type|ZERO_OR_MORE>\
* <compiled_regex...>
* (<regex...>)* compiles to
* <ZERO_OR_MORE_GROUP|ADDED_LENGTH_BITS>\
* <group_length><compiled_regex...>\
* <END_GROUP|ZERO_OR_MORE><groupn>
*/
if (can_repeat == B_FALSE) {
} else {
*regex_typep = (unsigned char)
((unsigned int)*regex_typep | ZERO_OR_MORE);
}
break; /* end case '*' */
case PLUS:
/* one or more repetitions of the preceding */
/* expression */
/*
* <regex...>+ compiles to <regex_type|ONE_OR_MORE>\
* <compiled_regex...> (<regex...>)+ compiles to
* <ONE_OR_MORE_GROUP|ADDED_LENGTH_BITS>\
* <group_length><compiled_regex...>\
* <END_GROUP|ONE_OR_MORE><groupn>
*/
if (can_repeat == B_FALSE) {
} else {
*regex_typep =
(unsigned char)((unsigned int)*
}
break; /* end case '+' */
case LEFT_CURLY_BRACE:
/*
* repeat the preceding regular expression
* at least min_count times
* and at most max_count times
*
* <regex...>{min_count} compiles to
* <regex type|COUNT><compiled_regex...>
* <min_count><min_count>
*
* <regex...>{min_count,} compiles to
* <regex type|COUNT><compiled_regex...>
* <min_count><UNLIMITED>
*
* <regex...>{min_count,max_count} compiles to
* <regex type>|COUNT><compiled_regex...>
* <min_count><max_count>
*
* (<regex...>){min_count,max_count} compiles to
* <COUNTED_GROUP|ADDED_LENGTH_BITS><group_length>\
* <compiled_regex...><END_GROUP|COUNT><groupn>\
* <minimum_match_count><maximum_match_count>
*/
if (can_repeat == B_FALSE) {
}
*regex_typep = (unsigned char)((unsigned int)*
regex_typep | COUNT);
if (count_length <= 0) {
}
regexp += count_length;
regexp++;
regexp++;
/* {min_count,} */
if (*regexp == RIGHT_CURLY_BRACE) {
regexp++;
} else { /* {min_count,max_count} */
if (count_length <= 0) {
}
regexp += count_length;
if (*regexp != RIGHT_CURLY_BRACE) {
}
regexp++;
}
} else { /* invalid expression */
}
if ((min_count > MAX_SINGLE_BYTE_INT) ||
} else {
compilep++;
compilep++;
}
break; /* end case LEFT_CURLY_BRACE */
default: /* a single non-special character */
/*
* compiles to <ASCII_CHAR><ascii_char> or
* <MULTIBYTE_CHAR><multibyte_char>
*/
can_repeat = B_TRUE;
compilep += expr_length;
} /* end switch (current_char) */
/* GET THE NEXT CHARACTER FOR THE WHILE LOOP */
if (char_size < 0) {
} else if (char_size > 0) {
} else if /* (char_size == 0) && */ (next_argp != (char *)0) {
if (char_size <= 0) {
} else {
}
} else /* ((char_size == 0) && (next_argp == (char *)0)) */ {
if (pop_compilep() != (char *)0) {
/* unmatched parentheses */
}
compilep++;
*compilep = '\0';
compilep++;
return (compile_startp);
}
} /* end for (;;) */
} /* regcmp() */
/* DEFINITIONS OF PRIVATE FUNCTIONS */
static int
{
int expr_length;
if ((unsigned int)wchar <= (unsigned int)0x7f) {
expr_length = 1;
} else {
}
return (expr_length);
}
static int
{
int expr_length = 0;
if ((unsigned int)wchar <= (unsigned int)0x7f) {
*compilep = (unsigned char)ASCII_CHAR;
compilep++;
expr_length += 2;
} else {
*compilep = (unsigned char)MULTIBYTE_CHAR;
compilep++;
expr_length++;
}
return (expr_length);
}
static int
{
int count = 0;
int count_length = 0;
if (regexp == (char *)0) {
return ((int)0);
} else {
count_char = *regexp;
count_length++;
regexp++;
count_char = *regexp;
}
}
return (count_length);
}
static int
{
char digit;
if (regexp == (char *)0) {
return ((int)-1);
} else {
return ((int)(digit - '0'));
} else {
return ((int)-1);
}
}
}
static int
{
int char_size;
if (regexp == (char *)0) {
char_size = 0;
} else if (*regexp == '\0') {
char_size = 0;
} else if ((unsigned char)*regexp <= (unsigned char)0x7f) {
char_size = 1;
} else {
}
return (char_size);
}
static char *
pop_compilep(void)
{
char *compilep;
return ((char *)0);
} else {
return (compilep);
}
}
static char *
{
if (compilep_stackp <= &compilep_stack[0]) {
return ((char *)0);
} else {
return (compilep);
}
}
static boolean_t
{
(lower_char < upper_char)) ||
(((lower_char & WCHAR_CSMASK) ==
(upper_char & WCHAR_CSMASK)) &&
(lower_char < upper_char)));
}