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 * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * return the next character in the string s
1N/A * \ character constants are expanded
1N/A * *p is updated to point to the next character in s
1N/A * *m is 1 if return value is wide
1N/A */
1N/A
1N/A#include <ast.h>
1N/A#include <ctype.h>
1N/A
1N/A#include <ccode.h>
1N/A#if !_PACKAGE_astsa
1N/A#include <regex.h>
1N/A#endif
1N/A
1N/Aint
1N/Achrexp(register const char* s, char** p, int* m, register int flags)
1N/A{
1N/A register const char* q;
1N/A register int c;
1N/A const char* e;
1N/A const char* b;
1N/A char* r;
1N/A int n;
1N/A int w;
1N/A
1N/A w = 0;
1N/A for (;;)
1N/A {
1N/A b = s;
1N/A switch (c = mbchar(s))
1N/A {
1N/A case 0:
1N/A s--;
1N/A break;
1N/A case '\\':
1N/A switch (c = *s++)
1N/A {
1N/A case '0': case '1': case '2': case '3':
1N/A case '4': case '5': case '6': case '7':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A c -= '0';
1N/A q = s + 2;
1N/A while (s < q)
1N/A switch (*s)
1N/A {
1N/A case '0': case '1': case '2': case '3':
1N/A case '4': case '5': case '6': case '7':
1N/A c = (c << 3) + *s++ - '0';
1N/A break;
1N/A default:
1N/A q = s;
1N/A break;
1N/A }
1N/A break;
1N/A case 'a':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A c = CC_bel;
1N/A break;
1N/A case 'b':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A c = '\b';
1N/A break;
1N/A case 'c': /*DEPRECATED*/
1N/A case 'C':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A if (c = *s)
1N/A {
1N/A s++;
1N/A if (c == '\\')
1N/A {
1N/A c = chrexp(s - 1, &r, 0, flags);
1N/A s = (const char*)r;
1N/A }
1N/A if (islower(c))
1N/A c = toupper(c);
1N/A c = ccmapc(c, CC_NATIVE, CC_ASCII);
1N/A c ^= 0x40;
1N/A c = ccmapc(c, CC_ASCII, CC_NATIVE);
1N/A }
1N/A break;
1N/A case 'e': /*DEPRECATED*/
1N/A case 'E':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A c = CC_esc;
1N/A break;
1N/A case 'f':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A c = '\f';
1N/A break;
1N/A case 'M':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A if (*s == '-')
1N/A {
1N/A s++;
1N/A c = CC_esc;
1N/A }
1N/A break;
1N/A case 'n':
1N/A if (flags & FMT_EXP_NONL)
1N/A continue;
1N/A if (!(flags & FMT_EXP_LINE))
1N/A goto noexpand;
1N/A c = '\n';
1N/A break;
1N/A case 'r':
1N/A if (flags & FMT_EXP_NOCR)
1N/A continue;
1N/A if (!(flags & FMT_EXP_LINE))
1N/A goto noexpand;
1N/A c = '\r';
1N/A break;
1N/A case 't':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A c = '\t';
1N/A break;
1N/A case 'v':
1N/A if (!(flags & FMT_EXP_CHAR))
1N/A goto noexpand;
1N/A c = CC_vt;
1N/A break;
1N/A case 'u':
1N/A case 'U':
1N/A case 'x':
1N/A if (q = c == 'u' ? (s + 4) : c == 'U' ? (s + 8) : (char*)0)
1N/A {
1N/A if (!(flags & FMT_EXP_WIDE))
1N/A goto noexpand;
1N/A w = 1;
1N/A }
1N/A b = e = s;
1N/A n = 0;
1N/A c = 0;
1N/A while (!e || !q || s < q)
1N/A {
1N/A switch (*s)
1N/A {
1N/A case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1N/A c = (c << 4) + *s++ - 'a' + 10;
1N/A n++;
1N/A continue;
1N/A case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1N/A c = (c << 4) + *s++ - 'A' + 10;
1N/A n++;
1N/A continue;
1N/A case '0': case '1': case '2': case '3': case '4':
1N/A case '5': case '6': case '7': case '8': case '9':
1N/A c = (c << 4) + *s++ - '0';
1N/A n++;
1N/A continue;
1N/A case '{':
1N/A case '[':
1N/A if (s != e)
1N/A break;
1N/A e = 0;
1N/A s++;
1N/A continue;
1N/A case '}':
1N/A case ']':
1N/A if (!e)
1N/A s++;
1N/A break;
1N/A default:
1N/A break;
1N/A }
1N/A break;
1N/A }
1N/A if (n <= 2 && !(flags & FMT_EXP_CHAR) || n > 2 && (w = 1) && !(flags & FMT_EXP_WIDE))
1N/A {
1N/A c = '\\';
1N/A s = b;
1N/A }
1N/A break;
1N/A case 0:
1N/A s--;
1N/A break;
1N/A }
1N/A break;
1N/A default:
1N/A if ((s - b) > 1)
1N/A w = 1;
1N/A break;
1N/A }
1N/A break;
1N/A }
1N/A normal:
1N/A if (p)
1N/A *p = (char*)s;
1N/A if (m)
1N/A *m = w;
1N/A return c;
1N/A noexpand:
1N/A c = '\\';
1N/A s--;
1N/A goto normal;
1N/A}
1N/A
1N/Aint
1N/Achresc(register const char* s, char** p)
1N/A{
1N/A return chrexp(s, p, NiL, FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_WIDE);
1N/A}