1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24 * Glenn Fowler
25 * AT&T Research
26 *
27 * return the next character in the string s
28 * \ character constants are expanded
29 * *p is updated to point to the next character in s
30 * *m is 1 if return value is wide
31 */
32
33 #include <ast.h>
34 #include <ctype.h>
35
36 #include <ccode.h>
37 #if !_PACKAGE_astsa
38 #include <regex.h>
39 #endif
40
41 int
chrexp(register const char * s,char ** p,int * m,register int flags)42 chrexp(register const char* s, char** p, int* m, register int flags)
43 {
44 register const char* q;
45 register int c;
46 const char* e;
47 const char* b;
48 char* r;
49 int n;
50 int w;
51
52 w = 0;
53 for (;;)
54 {
55 b = s;
56 switch (c = mbchar(s))
57 {
58 case 0:
59 s--;
60 break;
61 case '\\':
62 switch (c = *s++)
63 {
64 case '0': case '1': case '2': case '3':
65 case '4': case '5': case '6': case '7':
66 if (!(flags & FMT_EXP_CHAR))
67 goto noexpand;
68 c -= '0';
69 q = s + 2;
70 while (s < q)
71 switch (*s)
72 {
73 case '0': case '1': case '2': case '3':
74 case '4': case '5': case '6': case '7':
75 c = (c << 3) + *s++ - '0';
76 break;
77 default:
78 q = s;
79 break;
80 }
81 break;
82 case 'a':
83 if (!(flags & FMT_EXP_CHAR))
84 goto noexpand;
85 c = CC_bel;
86 break;
87 case 'b':
88 if (!(flags & FMT_EXP_CHAR))
89 goto noexpand;
90 c = '\b';
91 break;
92 case 'c': /*DEPRECATED*/
93 case 'C':
94 if (!(flags & FMT_EXP_CHAR))
95 goto noexpand;
96 if (c = *s)
97 {
98 s++;
99 if (c == '\\')
100 {
101 c = chrexp(s - 1, &r, 0, flags);
102 s = (const char*)r;
103 }
104 if (islower(c))
105 c = toupper(c);
106 c = ccmapc(c, CC_NATIVE, CC_ASCII);
107 c ^= 0x40;
108 c = ccmapc(c, CC_ASCII, CC_NATIVE);
109 }
110 break;
111 case 'e': /*DEPRECATED*/
112 case 'E':
113 if (!(flags & FMT_EXP_CHAR))
114 goto noexpand;
115 c = CC_esc;
116 break;
117 case 'f':
118 if (!(flags & FMT_EXP_CHAR))
119 goto noexpand;
120 c = '\f';
121 break;
122 case 'M':
123 if (!(flags & FMT_EXP_CHAR))
124 goto noexpand;
125 if (*s == '-')
126 {
127 s++;
128 c = CC_esc;
129 }
130 break;
131 case 'n':
132 if (flags & FMT_EXP_NONL)
133 continue;
134 if (!(flags & FMT_EXP_LINE))
135 goto noexpand;
136 c = '\n';
137 break;
138 case 'r':
139 if (flags & FMT_EXP_NOCR)
140 continue;
141 if (!(flags & FMT_EXP_LINE))
142 goto noexpand;
143 c = '\r';
144 break;
145 case 't':
146 if (!(flags & FMT_EXP_CHAR))
147 goto noexpand;
148 c = '\t';
149 break;
150 case 'v':
151 if (!(flags & FMT_EXP_CHAR))
152 goto noexpand;
153 c = CC_vt;
154 break;
155 case 'u':
156 case 'U':
157 case 'x':
158 if (q = c == 'u' ? (s + 4) : c == 'U' ? (s + 8) : (char*)0)
159 {
160 if (!(flags & FMT_EXP_WIDE))
161 goto noexpand;
162 w = 1;
163 }
164 b = e = s;
165 n = 0;
166 c = 0;
167 while (!e || !q || s < q)
168 {
169 switch (*s)
170 {
171 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
172 c = (c << 4) + *s++ - 'a' + 10;
173 n++;
174 continue;
175 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
176 c = (c << 4) + *s++ - 'A' + 10;
177 n++;
178 continue;
179 case '0': case '1': case '2': case '3': case '4':
180 case '5': case '6': case '7': case '8': case '9':
181 c = (c << 4) + *s++ - '0';
182 n++;
183 continue;
184 case '{':
185 case '[':
186 if (s != e)
187 break;
188 e = 0;
189 s++;
190 if (w && *s == 'U' && *(s + 1) == '+')
191 s += 2;
192 continue;
193 case '}':
194 case ']':
195 if (!e)
196 s++;
197 break;
198 default:
199 break;
200 }
201 break;
202 }
203 if (n <= 2 && !(flags & FMT_EXP_CHAR) || n > 2 && (w = 1) && !(flags & FMT_EXP_WIDE))
204 {
205 c = '\\';
206 s = b;
207 }
208 break;
209 case 0:
210 s--;
211 break;
212 }
213 break;
214 default:
215 if ((s - b) > 1)
216 w = 1;
217 break;
218 }
219 break;
220 }
221 normal:
222 if (p)
223 *p = (char*)s;
224 if (m)
225 *m = w;
226 return c;
227 noexpand:
228 c = '\\';
229 s--;
230 goto normal;
231 }
232
233 int
chresc(register const char * s,char ** p)234 chresc(register const char* s, char** p)
235 {
236 return chrexp(s, p, NiL, FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_WIDE);
237 }
238