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 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 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