Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  regc_pg_locale.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * regc_pg_locale.c
 *   ctype functions adapted to work on pg_wchar (a/k/a chr),
 *   and functions to cache the results of wholesale ctype probing.
 *
 * This file is #included by regcomp.c; it's not meant to compile standalone.
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *   src/backend/regex/regc_pg_locale.c
 *
 *-------------------------------------------------------------------------
 */


#include "catalog/pg_collation.h"
#include "common/unicode_case.h"
#include "common/unicode_category.h"
#include "utils/pg_locale.h"

/*
 * For the libc provider, to provide as much functionality as possible on a
 * variety of platforms without going so far as to implement everything from
 * scratch, we use several implementation strategies depending on the
 * situation:
 *
 * 1. In C/POSIX collations, we use hard-wired code.  We can't depend on
 * the <ctype.h> functions since those will obey LC_CTYPE.  Note that these
 * collations don't give a fig about multibyte characters.
 *
 * 2. When working in UTF8 encoding, we use the <wctype.h> functions.
 * This assumes that every platform uses Unicode codepoints directly
 * as the wchar_t representation of Unicode.  (XXX: ICU makes this assumption
 * even for non-UTF8 encodings, which may be a problem.)  On some platforms
 * wchar_t is only 16 bits wide, so we have to punt for codepoints > 0xFFFF.
 *
 * 3. In all other encodings, we use the <ctype.h> functions for pg_wchar
 * values up to 255, and punt for values above that.  This is 100% correct
 * only in single-byte encodings such as LATINn.  However, non-Unicode
 * multibyte encodings are mostly Far Eastern character sets for which the
 * properties being tested here aren't very relevant for higher code values
 * anyway.  The difficulty with using the <wctype.h> functions with
 * non-Unicode multibyte encodings is that we can have no certainty that
 * the platform's wchar_t representation matches what we do in pg_wchar
 * conversions.
 *
 * As a special case, in the "default" collation, (2) and (3) force ASCII
 * letters to follow ASCII upcase/downcase rules, while in a non-default
 * collation we just let the library functions do what they will.  The case
 * where this matters is treatment of I/i in Turkish, and the behavior is
 * meant to match the upper()/lower() SQL functions.
 *
 * We store the active collation setting in static variables.  In principle
 * it could be passed down to here via the regex library's "struct vars" data
 * structure; but that would require somewhat invasive changes in the regex
 * library, and right now there's no real benefit to be gained from that.
 *
 * NB: the coding here assumes pg_wchar is an unsigned type.
 */


typedef enum
{
 PG_REGEX_STRATEGY_C,  /* C locale (encoding independent) */
 PG_REGEX_STRATEGY_BUILTIN, /* built-in Unicode semantics */
 PG_REGEX_STRATEGY_LIBC_WIDE, /* Use locale_t <wctype.h> functions */
 PG_REGEX_STRATEGY_LIBC_1BYTE, /* Use locale_t <ctype.h> functions */
 PG_REGEX_STRATEGY_ICU,  /* Use ICU uchar.h functions */
} PG_Locale_Strategy;

static PG_Locale_Strategy pg_regex_strategy;
static pg_locale_t pg_regex_locale;

/*
 * Hard-wired character properties for C locale
 */

#define PG_ISDIGIT 0x01
#define PG_ISALPHA 0x02
#define PG_ISALNUM (PG_ISDIGIT | PG_ISALPHA)
#define PG_ISUPPER 0x04
#define PG_ISLOWER 0x08
#define PG_ISGRAPH 0x10
#define PG_ISPRINT 0x20
#define PG_ISPUNCT 0x40
#define PG_ISSPACE 0x80

static const unsigned char pg_char_properties[128] = {
  /* NUL */ 0,
  /* ^A */ 0,
  /* ^B */ 0,
  /* ^C */ 0,
  /* ^D */ 0,
  /* ^E */ 0,
  /* ^F */ 0,
  /* ^G */ 0,
  /* ^H */ 0,
  /* ^I */ PG_ISSPACE,
  /* ^J */ PG_ISSPACE,
  /* ^K */ PG_ISSPACE,
  /* ^L */ PG_ISSPACE,
  /* ^M */ PG_ISSPACE,
  /* ^N */ 0,
  /* ^O */ 0,
  /* ^P */ 0,
  /* ^Q */ 0,
  /* ^R */ 0,
  /* ^S */ 0,
  /* ^T */ 0,
  /* ^U */ 0,
  /* ^V */ 0,
  /* ^W */ 0,
  /* ^X */ 0,
  /* ^Y */ 0,
  /* ^Z */ 0,
  /* ^[ */ 0,
  /* ^\ */ 0,
  /* ^] */ 0,
  /* ^^ */ 0,
  /* ^_ */ 0,
  /* */ PG_ISPRINT | PG_ISSPACE,
  /* !  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* "  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* #  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* $  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* %  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* &  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* '  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* (  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* )  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* *  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* +  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* ,  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* -  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* .  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* /  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* 0  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 1  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 2  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 3  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 4  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 5  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 6  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 7  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 8  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* 9  */ PG_ISDIGIT | PG_ISGRAPH | PG_ISPRINT,
  /* :  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* ;  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* <  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* =  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* >  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* ?  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* @  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* A  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* B  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* C  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* D  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* E  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* F  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* G  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* H  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* I  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* J  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* K  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* L  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* M  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* N  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* O  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* P  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* Q  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* R  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* S  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* T  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* U  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* V  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* W  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* X  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* Y  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* Z  */ PG_ISALPHA | PG_ISUPPER | PG_ISGRAPH | PG_ISPRINT,
  /* [  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* \  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* ]  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* ^  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* _  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* `  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* a  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* b  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* c  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* d  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* e  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* f  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* g  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* h  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* i  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* j  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* k  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* l  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* m  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* n  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* o  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* p  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* q  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* r  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* s  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* t  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* u  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* v  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* w  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* x  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* y  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* z  */ PG_ISALPHA | PG_ISLOWER | PG_ISGRAPH | PG_ISPRINT,
  /* {  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* |  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* }  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* ~  */ PG_ISGRAPH | PG_ISPRINT | PG_ISPUNCT,
  /* DEL */ 0
};


/*
 * pg_set_regex_collation: set collation for these functions to obey
 *
 * This is called when beginning compilation or execution of a regexp.
 * Since there's no need for reentrancy of regexp operations, it's okay
 * to store the results in static variables.
 */

void
pg_set_regex_collation(Oid collation)
{
 pg_locale_t locale = 0;
 PG_Locale_Strategy strategy;

 if (!OidIsValid(collation))
 {
  /*
   * This typically means that the parser could not resolve a conflict
   * of implicit collations, so report it that way.
 */

  ereport(ERROR,
    (errcode(ERRCODE_INDETERMINATE_COLLATION),
     errmsg("could not determine which collation to use for regular expression"),
     errhint("Use the COLLATE clause to set the collation explicitly.")));
 }

 if (collation == C_COLLATION_OID)
 {
  /*
   * Some callers expect regexes to work for C_COLLATION_OID before
   * catalog access is available, so we can't call
   * pg_newlocale_from_collation().
 */

  strategy = PG_REGEX_STRATEGY_C;
  locale = 0;
 }
 else
 {
  locale = pg_newlocale_from_collation(collation);

  if (!locale->deterministic)
   ereport(ERROR,
     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      errmsg("nondeterministic collations are not supported for regular expressions")));

  if (locale->ctype_is_c)
  {
   /*
    * C/POSIX collations use this path regardless of database
    * encoding
 */

   strategy = PG_REGEX_STRATEGY_C;
   locale = 0;
  }
  else if (locale->provider == COLLPROVIDER_BUILTIN)
  {
   Assert(GetDatabaseEncoding() == PG_UTF8);
   strategy = PG_REGEX_STRATEGY_BUILTIN;
  }
#ifdef USE_ICU
  else if (locale->provider == COLLPROVIDER_ICU)
  {
   strategy = PG_REGEX_STRATEGY_ICU;
  }
#endif
  else
  {
   Assert(locale->provider == COLLPROVIDER_LIBC);
   if (GetDatabaseEncoding() == PG_UTF8)
    strategy = PG_REGEX_STRATEGY_LIBC_WIDE;
   else
    strategy = PG_REGEX_STRATEGY_LIBC_1BYTE;
  }
 }

 pg_regex_strategy = strategy;
 pg_regex_locale = locale;
}

static int
pg_wc_isdigit(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISDIGIT));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_isdigit(c, !pg_regex_locale->info.builtin.casemap_full);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswdigit_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     isdigit_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_isdigit(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_isalpha(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISALPHA));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_isalpha(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswalpha_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     isalpha_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_isalpha(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_isalnum(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISALNUM));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_isalnum(c, !pg_regex_locale->info.builtin.casemap_full);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswalnum_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     isalnum_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_isalnum(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_isword(pg_wchar c)
{
 /* We define word characters as alnum class plus underscore */
 if (c == CHR('_'))
  return 1;
 return pg_wc_isalnum(c);
}

static int
pg_wc_isupper(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISUPPER));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_isupper(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswupper_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     isupper_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_isupper(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_islower(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISLOWER));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_islower(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswlower_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     islower_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_islower(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_isgraph(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISGRAPH));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_isgraph(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswgraph_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     isgraph_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_isgraph(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_isprint(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISPRINT));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_isprint(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswprint_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     isprint_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_isprint(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_ispunct(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISPUNCT));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_ispunct(c, !pg_regex_locale->info.builtin.casemap_full);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswpunct_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     ispunct_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_ispunct(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static int
pg_wc_isspace(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   return (c <= (pg_wchar) 127 &&
     (pg_char_properties[c] & PG_ISSPACE));
  case PG_REGEX_STRATEGY_BUILTIN:
   return pg_u_isspace(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return iswspace_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   return (c <= (pg_wchar) UCHAR_MAX &&
     isspace_l((unsigned char) c, pg_regex_locale->info.lt));
   break;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_isspace(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static pg_wchar
pg_wc_toupper(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   if (c <= (pg_wchar) 127)
    return pg_ascii_toupper((unsigned char) c);
   return c;
  case PG_REGEX_STRATEGY_BUILTIN:
   return unicode_uppercase_simple(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   /* force C behavior for ASCII characters, per comments above */
   if (pg_regex_locale->is_default && c <= (pg_wchar) 127)
    return pg_ascii_toupper((unsigned char) c);
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return towupper_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   /* force C behavior for ASCII characters, per comments above */
   if (pg_regex_locale->is_default && c <= (pg_wchar) 127)
    return pg_ascii_toupper((unsigned char) c);
   if (c <= (pg_wchar) UCHAR_MAX)
    return toupper_l((unsigned char) c, pg_regex_locale->info.lt);
   return c;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_toupper(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}

static pg_wchar
pg_wc_tolower(pg_wchar c)
{
 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
   if (c <= (pg_wchar) 127)
    return pg_ascii_tolower((unsigned char) c);
   return c;
  case PG_REGEX_STRATEGY_BUILTIN:
   return unicode_lowercase_simple(c);
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   /* force C behavior for ASCII characters, per comments above */
   if (pg_regex_locale->is_default && c <= (pg_wchar) 127)
    return pg_ascii_tolower((unsigned char) c);
   if (sizeof(wchar_t) >= 4 || c <= (pg_wchar) 0xFFFF)
    return towlower_l((wint_t) c, pg_regex_locale->info.lt);
   /* FALL THRU */
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
   /* force C behavior for ASCII characters, per comments above */
   if (pg_regex_locale->is_default && c <= (pg_wchar) 127)
    return pg_ascii_tolower((unsigned char) c);
   if (c <= (pg_wchar) UCHAR_MAX)
    return tolower_l((unsigned char) c, pg_regex_locale->info.lt);
   return c;
  case PG_REGEX_STRATEGY_ICU:
#ifdef USE_ICU
   return u_tolower(c);
#endif
   break;
 }
 return 0;     /* can't get here, but keep compiler quiet */
}


/*
 * These functions cache the results of probing libc's ctype behavior for
 * all character codes of interest in a given encoding/collation.  The
 * result is provided as a "struct cvec", but notice that the representation
 * is a touch different from a cvec created by regc_cvec.c: we allocate the
 * chrs[] and ranges[] arrays separately from the struct so that we can
 * realloc them larger at need.  This is okay since the cvecs made here
 * should never be freed by freecvec().
 *
 * We use malloc not palloc since we mustn't lose control on out-of-memory;
 * the main regex code expects us to return a failure indication instead.
 */


typedef int (*pg_wc_probefunc) (pg_wchar c);

typedef struct pg_ctype_cache
{
 pg_wc_probefunc probefunc; /* pg_wc_isalpha or a sibling */
 pg_locale_t locale;   /* locale this entry is for */
 struct cvec cv;    /* cache entry contents */
 struct pg_ctype_cache *next; /* chain link */
} pg_ctype_cache;

static pg_ctype_cache *pg_ctype_cache_list = NULL;

/*
 * Add a chr or range to pcc->cv; return false if run out of memory
 */

static bool
store_match(pg_ctype_cache *pcc, pg_wchar chr1, int nchrs)
{
 chr     *newchrs;

 if (nchrs > 1)
 {
  if (pcc->cv.nranges >= pcc->cv.rangespace)
  {
   pcc->cv.rangespace *= 2;
   newchrs = (chr *) realloc(pcc->cv.ranges,
           pcc->cv.rangespace * sizeof(chr) * 2);
   if (newchrs == NULL)
    return false;
   pcc->cv.ranges = newchrs;
  }
  pcc->cv.ranges[pcc->cv.nranges * 2] = chr1;
  pcc->cv.ranges[pcc->cv.nranges * 2 + 1] = chr1 + nchrs - 1;
  pcc->cv.nranges++;
 }
 else
 {
  assert(nchrs == 1);
  if (pcc->cv.nchrs >= pcc->cv.chrspace)
  {
   pcc->cv.chrspace *= 2;
   newchrs = (chr *) realloc(pcc->cv.chrs,
           pcc->cv.chrspace * sizeof(chr));
   if (newchrs == NULL)
    return false;
   pcc->cv.chrs = newchrs;
  }
  pcc->cv.chrs[pcc->cv.nchrs++] = chr1;
 }
 return true;
}

/*
 * Given a probe function (e.g., pg_wc_isalpha) get a struct cvec for all
 * chrs satisfying the probe function.  The active collation is the one
 * previously set by pg_set_regex_collation.  Return NULL if out of memory.
 *
 * Note that the result must not be freed or modified by caller.
 */

static struct cvec *
pg_ctype_get_cache(pg_wc_probefunc probefunc, int cclasscode)
{
 pg_ctype_cache *pcc;
 pg_wchar max_chr;
 pg_wchar cur_chr;
 int   nmatches;
 chr     *newchrs;

 /*
  * Do we already have the answer cached?
 */

 for (pcc = pg_ctype_cache_list; pcc != NULL; pcc = pcc->next)
 {
  if (pcc->probefunc == probefunc &&
   pcc->locale == pg_regex_locale)
   return &pcc->cv;
 }

 /*
  * Nope, so initialize some workspace ...
 */

 pcc = (pg_ctype_cache *) malloc(sizeof(pg_ctype_cache));
 if (pcc == NULL)
  return NULL;
 pcc->probefunc = probefunc;
 pcc->locale = pg_regex_locale;
 pcc->cv.nchrs = 0;
 pcc->cv.chrspace = 128;
 pcc->cv.chrs = (chr *) malloc(pcc->cv.chrspace * sizeof(chr));
 pcc->cv.nranges = 0;
 pcc->cv.rangespace = 64;
 pcc->cv.ranges = (chr *) malloc(pcc->cv.rangespace * sizeof(chr) * 2);
 if (pcc->cv.chrs == NULL || pcc->cv.ranges == NULL)
  goto out_of_memory;
 pcc->cv.cclasscode = cclasscode;

 /*
  * Decide how many character codes we ought to look through.  In general
  * we don't go past MAX_SIMPLE_CHR; chr codes above that are handled at
  * runtime using the "high colormap" mechanism.  However, in C locale
  * there's no need to go further than 127, and if we only have a 1-byte
  * <ctype.h> API there's no need to go further than that can handle.
  *
  * If it's not MAX_SIMPLE_CHR that's constraining the search, mark the
  * output cvec as not having any locale-dependent behavior, since there
  * will be no need to do any run-time locale checks.  (The #if's here
  * would always be true for production values of MAX_SIMPLE_CHR, but it's
  * useful to allow it to be small for testing purposes.)
 */

 switch (pg_regex_strategy)
 {
  case PG_REGEX_STRATEGY_C:
#if MAX_SIMPLE_CHR >= 127
   max_chr = (pg_wchar) 127;
   pcc->cv.cclasscode = -1;
#else
   max_chr = (pg_wchar) MAX_SIMPLE_CHR;
#endif
   break;
  case PG_REGEX_STRATEGY_BUILTIN:
   max_chr = (pg_wchar) MAX_SIMPLE_CHR;
   break;
  case PG_REGEX_STRATEGY_LIBC_WIDE:
   max_chr = (pg_wchar) MAX_SIMPLE_CHR;
   break;
  case PG_REGEX_STRATEGY_LIBC_1BYTE:
#if MAX_SIMPLE_CHR >= UCHAR_MAX
   max_chr = (pg_wchar) UCHAR_MAX;
   pcc->cv.cclasscode = -1;
#else
   max_chr = (pg_wchar) MAX_SIMPLE_CHR;
#endif
   break;
  case PG_REGEX_STRATEGY_ICU:
   max_chr = (pg_wchar) MAX_SIMPLE_CHR;
   break;
  default:
   Assert(false);
   max_chr = 0;  /* can't get here, but keep compiler quiet */
   break;
 }

 /*
  * And scan 'em ...
 */

 nmatches = 0;    /* number of consecutive matches */

 for (cur_chr = 0; cur_chr <= max_chr; cur_chr++)
 {
  if ((*probefunc) (cur_chr))
   nmatches++;
  else if (nmatches > 0)
  {
   if (!store_match(pcc, cur_chr - nmatches, nmatches))
    goto out_of_memory;
   nmatches = 0;
  }
 }

 if (nmatches > 0)
  if (!store_match(pcc, cur_chr - nmatches, nmatches))
   goto out_of_memory;

 /*
  * We might have allocated more memory than needed, if so free it
 */

 if (pcc->cv.nchrs == 0)
 {
  free(pcc->cv.chrs);
  pcc->cv.chrs = NULL;
  pcc->cv.chrspace = 0;
 }
 else if (pcc->cv.nchrs < pcc->cv.chrspace)
 {
  newchrs = (chr *) realloc(pcc->cv.chrs,
          pcc->cv.nchrs * sizeof(chr));
  if (newchrs == NULL)
   goto out_of_memory;
  pcc->cv.chrs = newchrs;
  pcc->cv.chrspace = pcc->cv.nchrs;
 }
 if (pcc->cv.nranges == 0)
 {
  free(pcc->cv.ranges);
  pcc->cv.ranges = NULL;
  pcc->cv.rangespace = 0;
 }
 else if (pcc->cv.nranges < pcc->cv.rangespace)
 {
  newchrs = (chr *) realloc(pcc->cv.ranges,
          pcc->cv.nranges * sizeof(chr) * 2);
  if (newchrs == NULL)
   goto out_of_memory;
  pcc->cv.ranges = newchrs;
  pcc->cv.rangespace = pcc->cv.nranges;
 }

 /*
  * Success, link it into cache chain
 */

 pcc->next = pg_ctype_cache_list;
 pg_ctype_cache_list = pcc;

 return &pcc->cv;

 /*
  * Failure, clean up
 */

out_of_memory:
 free(pcc->cv.chrs);
 free(pcc->cv.ranges);
 free(pcc);

 return NULL;
}

Messung V0.5 in Prozent
C=79 H=97 G=88

¤ Dauer der Verarbeitung: 0.18 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=738142