1163bd69bSGarrett D'Amore /* 2163bd69bSGarrett D'Amore * Copyright (c) 1991, 1993 3163bd69bSGarrett D'Amore * The Regents of the University of California. All rights reserved. 4163bd69bSGarrett D'Amore * 5163bd69bSGarrett D'Amore * Redistribution and use in source and binary forms, with or without 6163bd69bSGarrett D'Amore * modification, are permitted provided that the following conditions 7163bd69bSGarrett D'Amore * are met: 8163bd69bSGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 9163bd69bSGarrett D'Amore * notice, this list of conditions and the following disclaimer. 10163bd69bSGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 11163bd69bSGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 12163bd69bSGarrett D'Amore * documentation and/or other materials provided with the distribution. 13163bd69bSGarrett D'Amore * 3. All advertising materials mentioning features or use of this software 14163bd69bSGarrett D'Amore * must display the following acknowledgement: 15163bd69bSGarrett D'Amore * This product includes software developed by the University of 16163bd69bSGarrett D'Amore * California, Berkeley and its contributors. 17163bd69bSGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 18163bd69bSGarrett D'Amore * may be used to endorse or promote products derived from this software 19163bd69bSGarrett D'Amore * without specific prior written permission. 20163bd69bSGarrett D'Amore * 21163bd69bSGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22163bd69bSGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23163bd69bSGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24163bd69bSGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25163bd69bSGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26163bd69bSGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27163bd69bSGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28163bd69bSGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29163bd69bSGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30163bd69bSGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31163bd69bSGarrett D'Amore * SUCH DAMAGE. 32163bd69bSGarrett D'Amore */ 33163bd69bSGarrett D'Amore 34163bd69bSGarrett D'Amore #include <sys/types.h> 35163bd69bSGarrett D'Amore 36163bd69bSGarrett D'Amore #include <ctype.h> 37163bd69bSGarrett D'Amore #include <err.h> 38163bd69bSGarrett D'Amore #include <errno.h> 39163bd69bSGarrett D'Amore #include <stddef.h> 40163bd69bSGarrett D'Amore #include <stdio.h> 41163bd69bSGarrett D'Amore #include <stdlib.h> 42163bd69bSGarrett D'Amore #include <string.h> 43163bd69bSGarrett D'Amore #include <strings.h> 44163bd69bSGarrett D'Amore #include <wchar.h> 45163bd69bSGarrett D'Amore #include <wctype.h> 46163bd69bSGarrett D'Amore 47163bd69bSGarrett D'Amore #include "extern.h" 48163bd69bSGarrett D'Amore 49163bd69bSGarrett D'Amore static int backslash(STR *, int *); 50163bd69bSGarrett D'Amore static int bracket(STR *); 51163bd69bSGarrett D'Amore static void genclass(STR *); 52163bd69bSGarrett D'Amore static void genequiv(STR *); 53163bd69bSGarrett D'Amore static int genrange(STR *, int); 54163bd69bSGarrett D'Amore static void genseq(STR *); 55163bd69bSGarrett D'Amore 56163bd69bSGarrett D'Amore wint_t 57163bd69bSGarrett D'Amore next(s) 58163bd69bSGarrett D'Amore STR *s; 59163bd69bSGarrett D'Amore { 60163bd69bSGarrett D'Amore int is_octal; 61163bd69bSGarrett D'Amore wint_t ch; 62163bd69bSGarrett D'Amore wchar_t wch; 63163bd69bSGarrett D'Amore size_t clen; 64163bd69bSGarrett D'Amore 65163bd69bSGarrett D'Amore switch (s->state) { 66163bd69bSGarrett D'Amore case EOS: 67163bd69bSGarrett D'Amore return (0); 68163bd69bSGarrett D'Amore case INFINITE: 69163bd69bSGarrett D'Amore return (1); 70163bd69bSGarrett D'Amore case NORMAL: 71163bd69bSGarrett D'Amore switch (*s->str) { 72163bd69bSGarrett D'Amore case '\0': 73163bd69bSGarrett D'Amore s->state = EOS; 74163bd69bSGarrett D'Amore return (0); 75163bd69bSGarrett D'Amore case '\\': 76163bd69bSGarrett D'Amore s->lastch = backslash(s, &is_octal); 77163bd69bSGarrett D'Amore break; 78163bd69bSGarrett D'Amore case '[': 79163bd69bSGarrett D'Amore if (bracket(s)) 80163bd69bSGarrett D'Amore return (next(s)); 81163bd69bSGarrett D'Amore /* FALLTHROUGH */ 82163bd69bSGarrett D'Amore default: 83163bd69bSGarrett D'Amore clen = mbrtowc(&wch, s->str, MB_LEN_MAX, NULL); 84163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2 || 85163bd69bSGarrett D'Amore clen == 0) { 86163bd69bSGarrett D'Amore (void) fprintf(stderr, "Illegal seqeunce.\n"); 87163bd69bSGarrett D'Amore exit(1); 88163bd69bSGarrett D'Amore } 89163bd69bSGarrett D'Amore is_octal = 0; 90163bd69bSGarrett D'Amore s->lastch = wch; 91163bd69bSGarrett D'Amore s->str += clen; 92163bd69bSGarrett D'Amore break; 93163bd69bSGarrett D'Amore } 94163bd69bSGarrett D'Amore 95163bd69bSGarrett D'Amore /* We can start a range at any time. */ 96163bd69bSGarrett D'Amore if (s->str[0] == '-' && genrange(s, is_octal)) 97163bd69bSGarrett D'Amore return (next(s)); 98163bd69bSGarrett D'Amore return (1); 99163bd69bSGarrett D'Amore case RANGE: 100163bd69bSGarrett D'Amore if (s->cnt-- == 0) { 101163bd69bSGarrett D'Amore s->state = NORMAL; 102163bd69bSGarrett D'Amore return (next(s)); 103163bd69bSGarrett D'Amore } 104163bd69bSGarrett D'Amore ++s->lastch; 105163bd69bSGarrett D'Amore return (1); 106163bd69bSGarrett D'Amore case SEQUENCE: 107163bd69bSGarrett D'Amore if (s->cnt-- == 0) { 108163bd69bSGarrett D'Amore s->state = NORMAL; 109163bd69bSGarrett D'Amore return (next(s)); 110163bd69bSGarrett D'Amore } 111163bd69bSGarrett D'Amore return (1); 112163bd69bSGarrett D'Amore case CCLASS: 113163bd69bSGarrett D'Amore case CCLASS_UPPER: 114163bd69bSGarrett D'Amore case CCLASS_LOWER: 115163bd69bSGarrett D'Amore s->cnt++; 116163bd69bSGarrett D'Amore ch = nextwctype(s->lastch, s->cclass); 117163bd69bSGarrett D'Amore if (ch == -1) { 118163bd69bSGarrett D'Amore s->state = NORMAL; 119163bd69bSGarrett D'Amore return (next(s)); 120163bd69bSGarrett D'Amore } 121163bd69bSGarrett D'Amore s->lastch = ch; 122163bd69bSGarrett D'Amore return (1); 123163bd69bSGarrett D'Amore case SET: 124163bd69bSGarrett D'Amore if ((ch = s->set[s->cnt++]) == OOBCH) { 125163bd69bSGarrett D'Amore s->state = NORMAL; 126163bd69bSGarrett D'Amore return (next(s)); 127163bd69bSGarrett D'Amore } 128163bd69bSGarrett D'Amore s->lastch = ch; 129163bd69bSGarrett D'Amore return (1); 130163bd69bSGarrett D'Amore default: 131163bd69bSGarrett D'Amore return (0); 132163bd69bSGarrett D'Amore } 133163bd69bSGarrett D'Amore /* NOTREACHED */ 134163bd69bSGarrett D'Amore } 135163bd69bSGarrett D'Amore 136163bd69bSGarrett D'Amore static int 137163bd69bSGarrett D'Amore bracket(s) 138163bd69bSGarrett D'Amore STR *s; 139163bd69bSGarrett D'Amore { 140163bd69bSGarrett D'Amore char *p; 141163bd69bSGarrett D'Amore 142163bd69bSGarrett D'Amore switch (s->str[1]) { 143163bd69bSGarrett D'Amore case ':': /* "[:class:]" */ 144163bd69bSGarrett D'Amore if ((p = strchr(s->str + 2, ']')) == NULL) 145163bd69bSGarrett D'Amore return (0); 146163bd69bSGarrett D'Amore if (*(p - 1) != ':' || p - s->str < 4) 147163bd69bSGarrett D'Amore goto repeat; 148163bd69bSGarrett D'Amore *(p - 1) = '\0'; 149163bd69bSGarrett D'Amore s->str += 2; 150163bd69bSGarrett D'Amore genclass(s); 151163bd69bSGarrett D'Amore s->str = p + 1; 152163bd69bSGarrett D'Amore return (1); 153163bd69bSGarrett D'Amore case '=': /* "[=equiv=]" */ 154163bd69bSGarrett D'Amore if ((p = strchr(s->str + 2, ']')) == NULL) 155163bd69bSGarrett D'Amore return (0); 156163bd69bSGarrett D'Amore if (*(p - 1) != '=' || p - s->str < 4) 157163bd69bSGarrett D'Amore goto repeat; 158163bd69bSGarrett D'Amore s->str += 2; 159163bd69bSGarrett D'Amore genequiv(s); 160163bd69bSGarrett D'Amore return (1); 161163bd69bSGarrett D'Amore default: /* "[\###*n]" or "[#*n]" */ 162163bd69bSGarrett D'Amore repeat: 163163bd69bSGarrett D'Amore if ((p = strpbrk(s->str + 2, "*]")) == NULL) 164163bd69bSGarrett D'Amore return (0); 165163bd69bSGarrett D'Amore if (p[0] != '*' || index(p, ']') == NULL) 166163bd69bSGarrett D'Amore return (0); 167163bd69bSGarrett D'Amore s->str += 1; 168163bd69bSGarrett D'Amore genseq(s); 169163bd69bSGarrett D'Amore return (1); 170163bd69bSGarrett D'Amore } 171163bd69bSGarrett D'Amore /* NOTREACHED */ 172163bd69bSGarrett D'Amore } 173163bd69bSGarrett D'Amore 174163bd69bSGarrett D'Amore static void 175163bd69bSGarrett D'Amore genclass(s) 176163bd69bSGarrett D'Amore STR *s; 177163bd69bSGarrett D'Amore { 178163bd69bSGarrett D'Amore 179163bd69bSGarrett D'Amore if ((s->cclass = wctype(s->str)) == 0) 180163bd69bSGarrett D'Amore errx(1, "unknown class %s", s->str); 181163bd69bSGarrett D'Amore s->cnt = 0; 182163bd69bSGarrett D'Amore s->lastch = -1; /* incremented before check in next() */ 183163bd69bSGarrett D'Amore if (strcmp(s->str, "upper") == 0) 184163bd69bSGarrett D'Amore s->state = CCLASS_UPPER; 185163bd69bSGarrett D'Amore else if (strcmp(s->str, "lower") == 0) 186163bd69bSGarrett D'Amore s->state = CCLASS_LOWER; 187163bd69bSGarrett D'Amore else 188163bd69bSGarrett D'Amore s->state = CCLASS; 189163bd69bSGarrett D'Amore } 190163bd69bSGarrett D'Amore 191163bd69bSGarrett D'Amore static void 192163bd69bSGarrett D'Amore genequiv(s) 193163bd69bSGarrett D'Amore STR *s; 194163bd69bSGarrett D'Amore { 195163bd69bSGarrett D'Amore int i, p, pri; 196163bd69bSGarrett D'Amore char src[2], dst[3]; 197163bd69bSGarrett D'Amore size_t clen; 198163bd69bSGarrett D'Amore wchar_t wc; 199163bd69bSGarrett D'Amore 200163bd69bSGarrett D'Amore if (*s->str == '\\') { 201163bd69bSGarrett D'Amore s->equiv[0] = backslash(s, NULL); 202163bd69bSGarrett D'Amore if (*s->str != '=') 203163bd69bSGarrett D'Amore errx(1, "misplaced equivalence equals sign"); 204163bd69bSGarrett D'Amore s->str += 2; 205163bd69bSGarrett D'Amore } else { 206163bd69bSGarrett D'Amore clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL); 207163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2 || clen == 0) { 208163bd69bSGarrett D'Amore errno = EILSEQ; 209163bd69bSGarrett D'Amore err(1, NULL); 210163bd69bSGarrett D'Amore } 211163bd69bSGarrett D'Amore s->equiv[0] = wc; 212163bd69bSGarrett D'Amore if (s->str[clen] != '=') 213163bd69bSGarrett D'Amore errx(1, "misplaced equivalence equals sign"); 214163bd69bSGarrett D'Amore s->str += clen + 2; 215163bd69bSGarrett D'Amore } 216163bd69bSGarrett D'Amore 217163bd69bSGarrett D'Amore /* 218163bd69bSGarrett D'Amore * Calculate the set of all characters in the same equivalence class 219163bd69bSGarrett D'Amore * as the specified character (they will have the same primary 220163bd69bSGarrett D'Amore * collation weights). 221163bd69bSGarrett D'Amore * XXX Knows too much about how strxfrm() is implemented. Assumes 222163bd69bSGarrett D'Amore * it fills the string with primary collation weight bytes. Only one- 223163bd69bSGarrett D'Amore * to-one mappings are supported. 224163bd69bSGarrett D'Amore * XXX Equivalence classes not supported in multibyte locales. 225163bd69bSGarrett D'Amore */ 226163bd69bSGarrett D'Amore src[0] = (char)s->equiv[0]; 227163bd69bSGarrett D'Amore src[1] = '\0'; 228163bd69bSGarrett D'Amore if (MB_CUR_MAX == 1 && strxfrm(dst, src, sizeof (dst)) == 1) { 229163bd69bSGarrett D'Amore pri = (unsigned char)*dst; 230163bd69bSGarrett D'Amore for (p = 1, i = 1; i < NCHARS_SB; i++) { 231163bd69bSGarrett D'Amore *src = i; 232163bd69bSGarrett D'Amore if (strxfrm(dst, src, sizeof (dst)) == 1 && pri && 233163bd69bSGarrett D'Amore pri == (unsigned char)*dst) 234163bd69bSGarrett D'Amore s->equiv[p++] = i; 235163bd69bSGarrett D'Amore } 236163bd69bSGarrett D'Amore s->equiv[p] = OOBCH; 237163bd69bSGarrett D'Amore } 238163bd69bSGarrett D'Amore 239163bd69bSGarrett D'Amore s->cnt = 0; 240163bd69bSGarrett D'Amore s->state = SET; 241163bd69bSGarrett D'Amore s->set = s->equiv; 242163bd69bSGarrett D'Amore } 243163bd69bSGarrett D'Amore 244163bd69bSGarrett D'Amore static int 245163bd69bSGarrett D'Amore genrange(STR *s, int was_octal) 246163bd69bSGarrett D'Amore { 247163bd69bSGarrett D'Amore int stopval, octal; 248163bd69bSGarrett D'Amore char *savestart; 249163bd69bSGarrett D'Amore int n, cnt, *p; 250163bd69bSGarrett D'Amore size_t clen; 251163bd69bSGarrett D'Amore wchar_t wc; 252163bd69bSGarrett D'Amore 253163bd69bSGarrett D'Amore octal = 0; 254163bd69bSGarrett D'Amore savestart = s->str; 255163bd69bSGarrett D'Amore if (*++s->str == '\\') 256163bd69bSGarrett D'Amore stopval = backslash(s, &octal); 257163bd69bSGarrett D'Amore else { 258163bd69bSGarrett D'Amore clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL); 259163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2) { 260163bd69bSGarrett D'Amore errno = EILSEQ; 261163bd69bSGarrett D'Amore err(1, NULL); 262163bd69bSGarrett D'Amore } 263163bd69bSGarrett D'Amore stopval = wc; 264163bd69bSGarrett D'Amore s->str += clen; 265163bd69bSGarrett D'Amore } 266163bd69bSGarrett D'Amore /* 267163bd69bSGarrett D'Amore * XXX Characters are not ordered according to collating sequence in 268163bd69bSGarrett D'Amore * multibyte locales. 269163bd69bSGarrett D'Amore */ 270163bd69bSGarrett D'Amore if (octal || was_octal || MB_CUR_MAX > 1) { 271163bd69bSGarrett D'Amore if (stopval < s->lastch) { 272163bd69bSGarrett D'Amore s->str = savestart; 273163bd69bSGarrett D'Amore return (0); 274163bd69bSGarrett D'Amore } 275163bd69bSGarrett D'Amore s->cnt = stopval - s->lastch + 1; 276163bd69bSGarrett D'Amore s->state = RANGE; 277163bd69bSGarrett D'Amore --s->lastch; 278163bd69bSGarrett D'Amore return (1); 279163bd69bSGarrett D'Amore } 280163bd69bSGarrett D'Amore if (charcoll((const void *)&stopval, (const void *)&(s->lastch)) < 0) { 281163bd69bSGarrett D'Amore s->str = savestart; 282163bd69bSGarrett D'Amore return (0); 283163bd69bSGarrett D'Amore } 284163bd69bSGarrett D'Amore p = malloc((NCHARS_SB + 1) * sizeof (int)); 285*f5b8ba47SGarrett D'Amore if ((s->set = (void *)p) == NULL) 286163bd69bSGarrett D'Amore err(1, "genrange() malloc"); 287163bd69bSGarrett D'Amore for (cnt = 0; cnt < NCHARS_SB; cnt++) 288163bd69bSGarrett D'Amore if (charcoll((const void *)&cnt, (const void *)&(s->lastch)) >= 289163bd69bSGarrett D'Amore 0 && 290163bd69bSGarrett D'Amore charcoll((const void *)&cnt, (const void *)&stopval) <= 0) 291163bd69bSGarrett D'Amore *p++ = cnt; 292163bd69bSGarrett D'Amore *p = OOBCH; 293163bd69bSGarrett D'Amore n = (int *)p - (int *)s->set; 294163bd69bSGarrett D'Amore 295163bd69bSGarrett D'Amore s->cnt = 0; 296163bd69bSGarrett D'Amore s->state = SET; 297163bd69bSGarrett D'Amore if (n > 1) 298163bd69bSGarrett D'Amore qsort(s->set, n, sizeof (*(s->set)), charcoll); 299163bd69bSGarrett D'Amore return (1); 300163bd69bSGarrett D'Amore } 301163bd69bSGarrett D'Amore 302163bd69bSGarrett D'Amore static void 303163bd69bSGarrett D'Amore genseq(s) 304163bd69bSGarrett D'Amore STR *s; 305163bd69bSGarrett D'Amore { 306163bd69bSGarrett D'Amore char *ep; 307163bd69bSGarrett D'Amore wchar_t wc; 308163bd69bSGarrett D'Amore size_t clen; 309163bd69bSGarrett D'Amore 310163bd69bSGarrett D'Amore if (s->which == STRING1) 311163bd69bSGarrett D'Amore errx(1, "sequences only valid in string2"); 312163bd69bSGarrett D'Amore 313163bd69bSGarrett D'Amore if (*s->str == '\\') 314163bd69bSGarrett D'Amore s->lastch = backslash(s, NULL); 315163bd69bSGarrett D'Amore else { 316163bd69bSGarrett D'Amore clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL); 317163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2) { 318163bd69bSGarrett D'Amore errno = EILSEQ; 319163bd69bSGarrett D'Amore err(1, NULL); 320163bd69bSGarrett D'Amore } 321163bd69bSGarrett D'Amore s->lastch = wc; 322163bd69bSGarrett D'Amore s->str += clen; 323163bd69bSGarrett D'Amore } 324163bd69bSGarrett D'Amore if (*s->str != '*') 325163bd69bSGarrett D'Amore errx(1, "misplaced sequence asterisk"); 326163bd69bSGarrett D'Amore 327163bd69bSGarrett D'Amore switch (*++s->str) { 328163bd69bSGarrett D'Amore case '\\': 329163bd69bSGarrett D'Amore s->cnt = backslash(s, NULL); 330163bd69bSGarrett D'Amore break; 331163bd69bSGarrett D'Amore case ']': 332163bd69bSGarrett D'Amore s->cnt = 0; 333163bd69bSGarrett D'Amore ++s->str; 334163bd69bSGarrett D'Amore break; 335163bd69bSGarrett D'Amore default: 336163bd69bSGarrett D'Amore if (isdigit((uchar_t)*s->str)) { 337163bd69bSGarrett D'Amore s->cnt = strtol(s->str, &ep, 0); 338163bd69bSGarrett D'Amore if (*ep == ']') { 339163bd69bSGarrett D'Amore s->str = ep + 1; 340163bd69bSGarrett D'Amore break; 341163bd69bSGarrett D'Amore } 342163bd69bSGarrett D'Amore } 343163bd69bSGarrett D'Amore errx(1, "illegal sequence count"); 344163bd69bSGarrett D'Amore /* NOTREACHED */ 345163bd69bSGarrett D'Amore } 346163bd69bSGarrett D'Amore 347163bd69bSGarrett D'Amore s->state = s->cnt ? SEQUENCE : INFINITE; 348163bd69bSGarrett D'Amore } 349163bd69bSGarrett D'Amore 350163bd69bSGarrett D'Amore /* 351163bd69bSGarrett D'Amore * Translate \??? into a character. Up to 3 octal digits, if no digits either 352163bd69bSGarrett D'Amore * an escape code or a literal character. 353163bd69bSGarrett D'Amore */ 354163bd69bSGarrett D'Amore static int 355163bd69bSGarrett D'Amore backslash(STR *s, int *is_octal) 356163bd69bSGarrett D'Amore { 357163bd69bSGarrett D'Amore int ch, cnt, val; 358163bd69bSGarrett D'Amore 359163bd69bSGarrett D'Amore if (is_octal != NULL) 360163bd69bSGarrett D'Amore *is_octal = 0; 361163bd69bSGarrett D'Amore for (cnt = val = 0; ; ) { 362163bd69bSGarrett D'Amore ch = (uchar_t)*++s->str; 363163bd69bSGarrett D'Amore if (!isdigit(ch) || ch > '7') 364163bd69bSGarrett D'Amore break; 365163bd69bSGarrett D'Amore val = val * 8 + ch - '0'; 366163bd69bSGarrett D'Amore if (++cnt == 3) { 367163bd69bSGarrett D'Amore ++s->str; 368163bd69bSGarrett D'Amore break; 369163bd69bSGarrett D'Amore } 370163bd69bSGarrett D'Amore } 371163bd69bSGarrett D'Amore if (cnt) { 372163bd69bSGarrett D'Amore if (is_octal != NULL) 373163bd69bSGarrett D'Amore *is_octal = 1; 374163bd69bSGarrett D'Amore return (val); 375163bd69bSGarrett D'Amore } 376163bd69bSGarrett D'Amore if (ch != '\0') 377163bd69bSGarrett D'Amore ++s->str; 378163bd69bSGarrett D'Amore switch (ch) { 379163bd69bSGarrett D'Amore case 'a': /* escape characters */ 380163bd69bSGarrett D'Amore return ('\7'); 381163bd69bSGarrett D'Amore case 'b': 382163bd69bSGarrett D'Amore return ('\b'); 383163bd69bSGarrett D'Amore case 'f': 384163bd69bSGarrett D'Amore return ('\f'); 385163bd69bSGarrett D'Amore case 'n': 386163bd69bSGarrett D'Amore return ('\n'); 387163bd69bSGarrett D'Amore case 'r': 388163bd69bSGarrett D'Amore return ('\r'); 389163bd69bSGarrett D'Amore case 't': 390163bd69bSGarrett D'Amore return ('\t'); 391163bd69bSGarrett D'Amore case 'v': 392163bd69bSGarrett D'Amore return ('\13'); 393163bd69bSGarrett D'Amore case '\0': /* \" -> \ */ 394163bd69bSGarrett D'Amore s->state = EOS; 395163bd69bSGarrett D'Amore return ('\\'); 396163bd69bSGarrett D'Amore default: /* \x" -> x */ 397163bd69bSGarrett D'Amore return (ch); 398163bd69bSGarrett D'Amore } 399163bd69bSGarrett D'Amore } 400