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