1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * RE character class support
1N/A */
1N/A
1N/A#include "reglib.h"
1N/A
1N/Astruct Ctype_s; typedef struct Ctype_s Ctype_t;
1N/A
1N/Astruct Ctype_s
1N/A{
1N/A const char* name;
1N/A size_t size;
1N/A regclass_t ctype;
1N/A Ctype_t* next;
1N/A#if _lib_wctype
1N/A wctype_t wtype;
1N/A#endif
1N/A};
1N/A
1N/Astatic Ctype_t* ctypes;
1N/A
1N/A/*
1N/A * this stuff gets around posix failure to define isblank,
1N/A * and the fact that ctype functions are macros
1N/A * and any local extensions that may not even have functions or macros
1N/A */
1N/A
1N/A#if _need_iswblank
1N/A
1N/Aint
1N/A_reg_iswblank(wint_t wc)
1N/A{
1N/A static int initialized;
1N/A static wctype_t wt;
1N/A
1N/A if (!initialized)
1N/A {
1N/A initialized = 1;
1N/A wt = wctype("blank");
1N/A }
1N/A return iswctype(wc, wt);
1N/A}
1N/A
1N/A#endif
1N/A
1N/Astatic int Isalnum(int c) { return iswalnum(c); }
1N/Astatic int Isalpha(int c) { return iswalpha(c); }
1N/Astatic int Isblank(int c) { return iswblank(c); }
1N/Astatic int Iscntrl(int c) { return iswcntrl(c); }
1N/Astatic int Isdigit(int c) { return iswdigit(c); }
1N/Astatic int Notdigit(int c) { return !iswdigit(c); }
1N/Astatic int Isgraph(int c) { return iswgraph(c); }
1N/Astatic int Islower(int c) { return iswlower(c); }
1N/Astatic int Isprint(int c) { return iswprint(c); }
1N/Astatic int Ispunct(int c) { return iswpunct(c); }
1N/Astatic int Isspace(int c) { return iswspace(c); }
1N/Astatic int Notspace(int c) { return !iswspace(c); }
1N/Astatic int Isupper(int c) { return iswupper(c); }
1N/Astatic int Isword(int c) { return iswalnum(c) || c == '_'; }
1N/Astatic int Notword(int c) { return !iswalnum(c) && c != '_'; }
1N/Astatic int Isxdigit(int c) { return iswxdigit(c);}
1N/A
1N/A#if _lib_wctype
1N/A
1N/Astatic int Is_wc_1(int);
1N/Astatic int Is_wc_2(int);
1N/Astatic int Is_wc_3(int);
1N/Astatic int Is_wc_4(int);
1N/Astatic int Is_wc_5(int);
1N/Astatic int Is_wc_6(int);
1N/Astatic int Is_wc_7(int);
1N/Astatic int Is_wc_8(int);
1N/Astatic int Is_wc_9(int);
1N/Astatic int Is_wc_10(int);
1N/Astatic int Is_wc_11(int);
1N/Astatic int Is_wc_12(int);
1N/Astatic int Is_wc_13(int);
1N/Astatic int Is_wc_14(int);
1N/Astatic int Is_wc_15(int);
1N/Astatic int Is_wc_16(int);
1N/A
1N/A#endif
1N/A
1N/A#define SZ(s) s,(sizeof(s)-1)
1N/A
1N/Astatic Ctype_t ctype[] =
1N/A{
1N/A { SZ("alnum"), Isalnum },
1N/A { SZ("alpha"), Isalpha },
1N/A { SZ("blank"), Isblank },
1N/A { SZ("cntrl"), Iscntrl },
1N/A { SZ("digit"), Isdigit },
1N/A { SZ("graph"), Isgraph },
1N/A { SZ("lower"), Islower },
1N/A { SZ("print"), Isprint },
1N/A { SZ("punct"), Ispunct },
1N/A { SZ("space"), Isspace },
1N/A { SZ("upper"), Isupper },
1N/A { SZ("word"), Isword },
1N/A { SZ("xdigit"),Isxdigit},
1N/A
1N/A#define CTYPES 13
1N/A
1N/A#if _lib_wctype
1N/A { 0, 0, Is_wc_1 },
1N/A { 0, 0, Is_wc_2 },
1N/A { 0, 0, Is_wc_3 },
1N/A { 0, 0, Is_wc_4 },
1N/A { 0, 0, Is_wc_5 },
1N/A { 0, 0, Is_wc_6 },
1N/A { 0, 0, Is_wc_7 },
1N/A { 0, 0, Is_wc_8 },
1N/A { 0, 0, Is_wc_9 },
1N/A { 0, 0, Is_wc_10 },
1N/A { 0, 0, Is_wc_11 },
1N/A { 0, 0, Is_wc_12 },
1N/A { 0, 0, Is_wc_13 },
1N/A { 0, 0, Is_wc_14 },
1N/A { 0, 0, Is_wc_15 },
1N/A { 0, 0, Is_wc_16 },
1N/A
1N/A#define WTYPES 16
1N/A
1N/A#else
1N/A
1N/A#define WTYPES 0
1N/A
1N/A#endif
1N/A};
1N/A
1N/A#if _lib_wctype
1N/A
1N/Astatic int Is_wc_1(int c) { return iswctype(c, ctype[CTYPES+0].wtype); }
1N/Astatic int Is_wc_2(int c) { return iswctype(c, ctype[CTYPES+1].wtype); }
1N/Astatic int Is_wc_3(int c) { return iswctype(c, ctype[CTYPES+2].wtype); }
1N/Astatic int Is_wc_4(int c) { return iswctype(c, ctype[CTYPES+3].wtype); }
1N/Astatic int Is_wc_5(int c) { return iswctype(c, ctype[CTYPES+4].wtype); }
1N/Astatic int Is_wc_6(int c) { return iswctype(c, ctype[CTYPES+5].wtype); }
1N/Astatic int Is_wc_7(int c) { return iswctype(c, ctype[CTYPES+6].wtype); }
1N/Astatic int Is_wc_8(int c) { return iswctype(c, ctype[CTYPES+7].wtype); }
1N/Astatic int Is_wc_9(int c) { return iswctype(c, ctype[CTYPES+8].wtype); }
1N/Astatic int Is_wc_10(int c) { return iswctype(c, ctype[CTYPES+9].wtype); }
1N/Astatic int Is_wc_11(int c) { return iswctype(c, ctype[CTYPES+10].wtype); }
1N/Astatic int Is_wc_12(int c) { return iswctype(c, ctype[CTYPES+11].wtype); }
1N/Astatic int Is_wc_13(int c) { return iswctype(c, ctype[CTYPES+12].wtype); }
1N/Astatic int Is_wc_14(int c) { return iswctype(c, ctype[CTYPES+13].wtype); }
1N/Astatic int Is_wc_15(int c) { return iswctype(c, ctype[CTYPES+14].wtype); }
1N/Astatic int Is_wc_16(int c) { return iswctype(c, ctype[CTYPES+15].wtype); }
1N/A
1N/A#endif
1N/A
1N/A/*
1N/A * return pointer to ctype function for :class:] in s
1N/A * s points to the first char after the initial [
1N/A * dynamic wctype classes are locale-specific
1N/A * dynamic entry locale is punned in Ctype_t.next
1N/A * the search does a lazy (one entry at a time) flush on locale mismatch
1N/A * if e!=0 it points to next char in s
1N/A * 0 returned on error
1N/A */
1N/A
1N/Aregclass_t
1N/Aregclass(const char* s, char** e)
1N/A{
1N/A register Ctype_t* cp;
1N/A register int c;
1N/A register size_t n;
1N/A register const char* t;
1N/A Ctype_t* lc;
1N/A Ctype_t* xp;
1N/A Ctype_t* zp;
1N/A
1N/A if (!(c = *s++))
1N/A return 0;
1N/A for (t = s; *t && (*t != c || *(t + 1) != ']'); t++);
1N/A if (*t != c || !(n = t - s))
1N/A return 0;
1N/A for (cp = ctypes; cp; cp = cp->next)
1N/A if (n == cp->size && strneq(s, cp->name, n))
1N/A goto found;
1N/A xp = zp = 0;
1N/A lc = (Ctype_t*)setlocale(LC_CTYPE, NiL);
1N/A for (cp = ctype; cp < &ctype[elementsof(ctype)]; cp++)
1N/A {
1N/A#if _lib_wctype
1N/A if (!zp)
1N/A {
1N/A if (!cp->size)
1N/A zp = cp;
1N/A else if (!xp && cp->next && cp->next != lc)
1N/A xp = cp;
1N/A }
1N/A#endif
1N/A if (n == cp->size && strneq(s, cp->name, n) && (!cp->next || cp->next == lc))
1N/A goto found;
1N/A }
1N/A#if _lib_wctype
1N/A if (!(cp = zp))
1N/A {
1N/A if (!(cp = xp))
1N/A return 0;
1N/A cp->size = 0;
1N/A if (!streq(cp->name, s))
1N/A {
1N/A free((char*)cp->name);
1N/A cp->name = 0;
1N/A }
1N/A }
1N/A if (!cp->name)
1N/A {
1N/A if (!(cp->name = (const char*)memdup(s, n + 1)))
1N/A return 0;
1N/A *((char*)cp->name + n) = 0;
1N/A }
1N/A /* mvs.390 needs the (char*) cast -- barf */
1N/A if (!(cp->wtype = wctype((char*)cp->name)))
1N/A {
1N/A free((char*)cp->name);
1N/A cp->name = 0;
1N/A return 0;
1N/A }
1N/A cp->size = n;
1N/A cp->next = lc;
1N/A#endif
1N/A found:
1N/A if (e)
1N/A *e = (char*)t + 2;
1N/A return cp->ctype;
1N/A}
1N/A
1N/A/*
1N/A * associate the ctype function fun with name
1N/A */
1N/A
1N/Aint
1N/Aregaddclass(const char* name, regclass_t fun)
1N/A{
1N/A register Ctype_t* cp;
1N/A register Ctype_t* np;
1N/A register size_t n;
1N/A
1N/A n = strlen(name);
1N/A for (cp = ctypes; cp; cp = cp->next)
1N/A if (cp->size == n && strneq(name, cp->name, n))
1N/A {
1N/A cp->ctype = fun;
1N/A return 0;
1N/A }
1N/A if (!(np = newof(0, Ctype_t, 1, n + 1)))
1N/A return REG_ESPACE;
1N/A np->size = n;
1N/A np->name = strcpy((char*)(np + 1), name);
1N/A np->ctype = fun;
1N/A np->next = ctypes;
1N/A ctypes = np;
1N/A return 0;
1N/A}
1N/A
1N/A/*
1N/A * return pointer to ctype function for token
1N/A */
1N/A
1N/Aregclass_t
1N/Aclassfun(int type)
1N/A{
1N/A switch (type)
1N/A {
1N/A case T_ALNUM: return Isword;
1N/A case T_ALNUM_NOT: return Notword;
1N/A case T_DIGIT: return Isdigit;
1N/A case T_DIGIT_NOT: return Notdigit;
1N/A case T_SPACE: return Isspace;
1N/A case T_SPACE_NOT: return Notspace;
1N/A }
1N/A return 0;
1N/A}