int strexp(register char* s, int flags) { register char* t; register int c; char* b; char* e; int w; Mbstate_t q; b = t = s; while (c = *s++) { if (c == '\\') { c = chrexp(s - 1, &e, &w, flags); s = e; if (c < 0) continue; if (w) { mbinit(&q); t += mbconv(t, c, &q); continue; } } *t++ = c; } *t = 0; return t - b; }
int chrexp(register const char* s, char** p, int* m, register int flags) { register const char* q; register int c; const char* e; const char* b; char* r; int n; int w; w = 0; for (;;) { b = s; switch (c = mbchar(s)) { case 0: s--; break; case '\\': switch (c = *s++) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c -= '0'; q = s + 2; while (s < q) switch (*s) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = (c << 3) + *s++ - '0'; break; default: q = s; break; } break; case 'a': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = CC_bel; break; case 'b': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = '\b'; break; case 'c': /*DEPRECATED*/ case 'C': if (!(flags & FMT_EXP_CHAR)) goto noexpand; if (c = *s) { s++; if (c == '\\') { c = chrexp(s - 1, &r, 0, flags); s = (const char*)r; } if (islower(c)) c = toupper(c); c = ccmapc(c, CC_NATIVE, CC_ASCII); c ^= 0x40; c = ccmapc(c, CC_ASCII, CC_NATIVE); } break; case 'e': /*DEPRECATED*/ case 'E': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = CC_esc; break; case 'f': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = '\f'; break; case 'M': if (!(flags & FMT_EXP_CHAR)) goto noexpand; if (*s == '-') { s++; c = CC_esc; } break; case 'n': if (flags & FMT_EXP_NONL) continue; if (!(flags & FMT_EXP_LINE)) goto noexpand; c = '\n'; break; case 'r': if (flags & FMT_EXP_NOCR) continue; if (!(flags & FMT_EXP_LINE)) goto noexpand; c = '\r'; break; case 't': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = '\t'; break; case 'v': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = CC_vt; break; case 'u': case 'U': case 'x': if (q = c == 'u' ? (s + 4) : c == 'U' ? (s + 8) : (char*)0) { if (!(flags & FMT_EXP_WIDE)) goto noexpand; w = 1; } b = e = s; n = 0; c = 0; while (!e || !q || s < q) { switch (*s) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = (c << 4) + *s++ - 'a' + 10; n++; continue; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = (c << 4) + *s++ - 'A' + 10; n++; continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c = (c << 4) + *s++ - '0'; n++; continue; case '{': case '[': if (s != e) break; e = 0; s++; continue; case '}': case ']': if (!e) s++; break; default: break; } break; } if (n <= 2 && !(flags & FMT_EXP_CHAR) || n > 2 && (w = 1) && !(flags & FMT_EXP_WIDE)) { c = '\\'; s = b; } break; case 0: s--; break; } break; default: if ((s - b) > 1) w = 1; break; } break; } normal: if (p) *p = (char*)s; if (m) *m = w; return c; noexpand: c = '\\'; s--; goto normal; }
int chresc(register const char* s, char** p) { return chrexp(s, p, NiL, FMT_EXP_CHAR|FMT_EXP_LINE|FMT_EXP_WIDE); }
int chrexp(const char *s, char **p, int *m, int flags) { const char *t; int c; const char *e; const char *b; char *r; int n; int x; wchar_t d; Mbstate_t q; bool u; bool w; u = w = 0; mbinit(&q); for (;;) { b = s; c = mbchar(&d, (char **)&s, MB_LEN_MAX, &q); switch (c) { case 0: s = b; break; case '\\': b = s; switch (c = *s++) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c -= '0'; t = s + 2; while (s < t) { switch (*s) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = (c << 3) + *s++ - '0'; break; default: t = s; break; } } break; case 'a': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = CC_bel; break; case 'b': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = '\b'; break; case 'c': /*DEPRECATED*/ case 'C': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = *s; if (c) { s++; if (c == '\\') { c = chrexp(s - 1, &r, 0, flags); s = (const char *)r; } if (islower(c)) c = toupper(c); c ^= 0x40; } break; case 'e': /*DEPRECATED*/ case 'E': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = CC_esc; break; case 'f': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = '\f'; break; case 'M': if (!(flags & FMT_EXP_CHAR)) goto noexpand; if (*s == '-') { s++; c = CC_esc; } break; case 'n': if (flags & FMT_EXP_NONL) continue; if (!(flags & FMT_EXP_LINE)) goto noexpand; c = '\n'; break; case 'r': if (flags & FMT_EXP_NOCR) continue; if (!(flags & FMT_EXP_LINE)) goto noexpand; c = '\r'; break; case 't': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = '\t'; break; case 'v': if (!(flags & FMT_EXP_CHAR)) goto noexpand; c = CC_vt; break; case 'u': u = 1; // FALLTHRU case 'w': t = s + 4; goto wex; case 'U': u = 1; // FALLTHRU case 'W': t = s + 8; wex: if (!(flags & FMT_EXP_WIDE)) goto noexpand; w = 1; goto hex; case 'x': t = s + 2; hex: e = s; n = 0; c = 0; x = 0; while (!e || !t || s < t) { switch (*s) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = (c << 4) + *s++ - 'a' + 10; n++; continue; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = (c << 4) + *s++ - 'A' + 10; n++; continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c = (c << 4) + *s++ - '0'; n++; continue; case '{': case '[': if (s != e) break; e = 0; s++; if (w && (*s == 'U' || *s == 'W') && *(s + 1) == '+') s += 2; continue; case '-': if (e) break; if (*(s + 1) != '}' && *(s + 1) != ']') { if (!*(s + 1) || (*(s + 2) != '}' && *(s + 2) != ']')) { break; } x = *(unsigned char *)(s + 1); s += 2; } else { x = -1; s++; } /*FALLTHROUGH*/ case '}': case ']': if (!e) e = ++s; break; default: break; } break; } if (e) { if (n < 8 || (n == 8 && c >= 0)) { if (!w) { if (n > 2) { if (!(flags & FMT_EXP_WIDE)) goto noexpand; w = 1; } else if (!(flags & FMT_EXP_CHAR)) { goto noexpand; } else { break; } } if (!mbwide()) w = 0; if (c <= 0x7f) break; if (u) { uint32_t i = c; wchar_t o; if (!utf32invalid(i) && utf32stowcs(&o, &i, 1) > 0) { c = o; break; } } else if (w || c <= ast.byte_max) { break; } } if (x) { c = x; w = 0; break; } } /*FALLTHROUGH*/ case 0: goto noexpand; } break; default: if ((s - b) > 1) w = 1; break; noexpand: s = b; w = 0; c = '\\'; break; } break; } if (m) *m = w; if (p) *p = (char *)s; return c; }
int chresc(const char *s, char **p) { return chrexp(s, p, NULL, FMT_EXP_CHAR | FMT_EXP_LINE | FMT_EXP_WIDE); }