1*163bd69bSGarrett D'Amore /* 2*163bd69bSGarrett D'Amore * Copyright (c) 1991, 1993 3*163bd69bSGarrett D'Amore * The Regents of the University of California. All rights reserved. 4*163bd69bSGarrett D'Amore * 5*163bd69bSGarrett D'Amore * Redistribution and use in source and binary forms, with or without 6*163bd69bSGarrett D'Amore * modification, are permitted provided that the following conditions 7*163bd69bSGarrett D'Amore * are met: 8*163bd69bSGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 9*163bd69bSGarrett D'Amore * notice, this list of conditions and the following disclaimer. 10*163bd69bSGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 11*163bd69bSGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 12*163bd69bSGarrett D'Amore * documentation and/or other materials provided with the distribution. 13*163bd69bSGarrett D'Amore * 3. All advertising materials mentioning features or use of this software 14*163bd69bSGarrett D'Amore * must display the following acknowledgement: 15*163bd69bSGarrett D'Amore * This product includes software developed by the University of 16*163bd69bSGarrett D'Amore * California, Berkeley and its contributors. 17*163bd69bSGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 18*163bd69bSGarrett D'Amore * may be used to endorse or promote products derived from this software 19*163bd69bSGarrett D'Amore * without specific prior written permission. 20*163bd69bSGarrett D'Amore * 21*163bd69bSGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22*163bd69bSGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*163bd69bSGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*163bd69bSGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25*163bd69bSGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26*163bd69bSGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27*163bd69bSGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28*163bd69bSGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29*163bd69bSGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30*163bd69bSGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*163bd69bSGarrett D'Amore * SUCH DAMAGE. 32*163bd69bSGarrett D'Amore */ 33*163bd69bSGarrett D'Amore 34*163bd69bSGarrett D'Amore #include <sys/types.h> 35*163bd69bSGarrett D'Amore 36*163bd69bSGarrett D'Amore #include <ctype.h> 37*163bd69bSGarrett D'Amore #include <err.h> 38*163bd69bSGarrett D'Amore #include <errno.h> 39*163bd69bSGarrett D'Amore #include <stddef.h> 40*163bd69bSGarrett D'Amore #include <stdio.h> 41*163bd69bSGarrett D'Amore #include <stdlib.h> 42*163bd69bSGarrett D'Amore #include <string.h> 43*163bd69bSGarrett D'Amore #include <strings.h> 44*163bd69bSGarrett D'Amore #include <wchar.h> 45*163bd69bSGarrett D'Amore #include <wctype.h> 46*163bd69bSGarrett D'Amore 47*163bd69bSGarrett D'Amore #include "extern.h" 48*163bd69bSGarrett D'Amore 49*163bd69bSGarrett D'Amore static int backslash(STR *, int *); 50*163bd69bSGarrett D'Amore static int bracket(STR *); 51*163bd69bSGarrett D'Amore static void genclass(STR *); 52*163bd69bSGarrett D'Amore static void genequiv(STR *); 53*163bd69bSGarrett D'Amore static int genrange(STR *, int); 54*163bd69bSGarrett D'Amore static void genseq(STR *); 55*163bd69bSGarrett D'Amore 56*163bd69bSGarrett D'Amore wint_t 57*163bd69bSGarrett D'Amore next(s) 58*163bd69bSGarrett D'Amore STR *s; 59*163bd69bSGarrett D'Amore { 60*163bd69bSGarrett D'Amore int is_octal; 61*163bd69bSGarrett D'Amore wint_t ch; 62*163bd69bSGarrett D'Amore wchar_t wch; 63*163bd69bSGarrett D'Amore size_t clen; 64*163bd69bSGarrett D'Amore 65*163bd69bSGarrett D'Amore switch (s->state) { 66*163bd69bSGarrett D'Amore case EOS: 67*163bd69bSGarrett D'Amore return (0); 68*163bd69bSGarrett D'Amore case INFINITE: 69*163bd69bSGarrett D'Amore return (1); 70*163bd69bSGarrett D'Amore case NORMAL: 71*163bd69bSGarrett D'Amore switch (*s->str) { 72*163bd69bSGarrett D'Amore case '\0': 73*163bd69bSGarrett D'Amore s->state = EOS; 74*163bd69bSGarrett D'Amore return (0); 75*163bd69bSGarrett D'Amore case '\\': 76*163bd69bSGarrett D'Amore s->lastch = backslash(s, &is_octal); 77*163bd69bSGarrett D'Amore break; 78*163bd69bSGarrett D'Amore case '[': 79*163bd69bSGarrett D'Amore if (bracket(s)) 80*163bd69bSGarrett D'Amore return (next(s)); 81*163bd69bSGarrett D'Amore /* FALLTHROUGH */ 82*163bd69bSGarrett D'Amore default: 83*163bd69bSGarrett D'Amore clen = mbrtowc(&wch, s->str, MB_LEN_MAX, NULL); 84*163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2 || 85*163bd69bSGarrett D'Amore clen == 0) { 86*163bd69bSGarrett D'Amore (void) fprintf(stderr, "Illegal seqeunce.\n"); 87*163bd69bSGarrett D'Amore exit(1); 88*163bd69bSGarrett D'Amore } 89*163bd69bSGarrett D'Amore is_octal = 0; 90*163bd69bSGarrett D'Amore s->lastch = wch; 91*163bd69bSGarrett D'Amore s->str += clen; 92*163bd69bSGarrett D'Amore break; 93*163bd69bSGarrett D'Amore } 94*163bd69bSGarrett D'Amore 95*163bd69bSGarrett D'Amore /* We can start a range at any time. */ 96*163bd69bSGarrett D'Amore if (s->str[0] == '-' && genrange(s, is_octal)) 97*163bd69bSGarrett D'Amore return (next(s)); 98*163bd69bSGarrett D'Amore return (1); 99*163bd69bSGarrett D'Amore case RANGE: 100*163bd69bSGarrett D'Amore if (s->cnt-- == 0) { 101*163bd69bSGarrett D'Amore s->state = NORMAL; 102*163bd69bSGarrett D'Amore return (next(s)); 103*163bd69bSGarrett D'Amore } 104*163bd69bSGarrett D'Amore ++s->lastch; 105*163bd69bSGarrett D'Amore return (1); 106*163bd69bSGarrett D'Amore case SEQUENCE: 107*163bd69bSGarrett D'Amore if (s->cnt-- == 0) { 108*163bd69bSGarrett D'Amore s->state = NORMAL; 109*163bd69bSGarrett D'Amore return (next(s)); 110*163bd69bSGarrett D'Amore } 111*163bd69bSGarrett D'Amore return (1); 112*163bd69bSGarrett D'Amore case CCLASS: 113*163bd69bSGarrett D'Amore case CCLASS_UPPER: 114*163bd69bSGarrett D'Amore case CCLASS_LOWER: 115*163bd69bSGarrett D'Amore s->cnt++; 116*163bd69bSGarrett D'Amore ch = nextwctype(s->lastch, s->cclass); 117*163bd69bSGarrett D'Amore if (ch == -1) { 118*163bd69bSGarrett D'Amore s->state = NORMAL; 119*163bd69bSGarrett D'Amore return (next(s)); 120*163bd69bSGarrett D'Amore } 121*163bd69bSGarrett D'Amore s->lastch = ch; 122*163bd69bSGarrett D'Amore return (1); 123*163bd69bSGarrett D'Amore case SET: 124*163bd69bSGarrett D'Amore if ((ch = s->set[s->cnt++]) == OOBCH) { 125*163bd69bSGarrett D'Amore s->state = NORMAL; 126*163bd69bSGarrett D'Amore return (next(s)); 127*163bd69bSGarrett D'Amore } 128*163bd69bSGarrett D'Amore s->lastch = ch; 129*163bd69bSGarrett D'Amore return (1); 130*163bd69bSGarrett D'Amore default: 131*163bd69bSGarrett D'Amore return (0); 132*163bd69bSGarrett D'Amore } 133*163bd69bSGarrett D'Amore /* NOTREACHED */ 134*163bd69bSGarrett D'Amore } 135*163bd69bSGarrett D'Amore 136*163bd69bSGarrett D'Amore static int 137*163bd69bSGarrett D'Amore bracket(s) 138*163bd69bSGarrett D'Amore STR *s; 139*163bd69bSGarrett D'Amore { 140*163bd69bSGarrett D'Amore char *p; 141*163bd69bSGarrett D'Amore 142*163bd69bSGarrett D'Amore switch (s->str[1]) { 143*163bd69bSGarrett D'Amore case ':': /* "[:class:]" */ 144*163bd69bSGarrett D'Amore if ((p = strchr(s->str + 2, ']')) == NULL) 145*163bd69bSGarrett D'Amore return (0); 146*163bd69bSGarrett D'Amore if (*(p - 1) != ':' || p - s->str < 4) 147*163bd69bSGarrett D'Amore goto repeat; 148*163bd69bSGarrett D'Amore *(p - 1) = '\0'; 149*163bd69bSGarrett D'Amore s->str += 2; 150*163bd69bSGarrett D'Amore genclass(s); 151*163bd69bSGarrett D'Amore s->str = p + 1; 152*163bd69bSGarrett D'Amore return (1); 153*163bd69bSGarrett D'Amore case '=': /* "[=equiv=]" */ 154*163bd69bSGarrett D'Amore if ((p = strchr(s->str + 2, ']')) == NULL) 155*163bd69bSGarrett D'Amore return (0); 156*163bd69bSGarrett D'Amore if (*(p - 1) != '=' || p - s->str < 4) 157*163bd69bSGarrett D'Amore goto repeat; 158*163bd69bSGarrett D'Amore s->str += 2; 159*163bd69bSGarrett D'Amore genequiv(s); 160*163bd69bSGarrett D'Amore return (1); 161*163bd69bSGarrett D'Amore default: /* "[\###*n]" or "[#*n]" */ 162*163bd69bSGarrett D'Amore repeat: 163*163bd69bSGarrett D'Amore if ((p = strpbrk(s->str + 2, "*]")) == NULL) 164*163bd69bSGarrett D'Amore return (0); 165*163bd69bSGarrett D'Amore if (p[0] != '*' || index(p, ']') == NULL) 166*163bd69bSGarrett D'Amore return (0); 167*163bd69bSGarrett D'Amore s->str += 1; 168*163bd69bSGarrett D'Amore genseq(s); 169*163bd69bSGarrett D'Amore return (1); 170*163bd69bSGarrett D'Amore } 171*163bd69bSGarrett D'Amore /* NOTREACHED */ 172*163bd69bSGarrett D'Amore } 173*163bd69bSGarrett D'Amore 174*163bd69bSGarrett D'Amore static void 175*163bd69bSGarrett D'Amore genclass(s) 176*163bd69bSGarrett D'Amore STR *s; 177*163bd69bSGarrett D'Amore { 178*163bd69bSGarrett D'Amore 179*163bd69bSGarrett D'Amore if ((s->cclass = wctype(s->str)) == 0) 180*163bd69bSGarrett D'Amore errx(1, "unknown class %s", s->str); 181*163bd69bSGarrett D'Amore s->cnt = 0; 182*163bd69bSGarrett D'Amore s->lastch = -1; /* incremented before check in next() */ 183*163bd69bSGarrett D'Amore if (strcmp(s->str, "upper") == 0) 184*163bd69bSGarrett D'Amore s->state = CCLASS_UPPER; 185*163bd69bSGarrett D'Amore else if (strcmp(s->str, "lower") == 0) 186*163bd69bSGarrett D'Amore s->state = CCLASS_LOWER; 187*163bd69bSGarrett D'Amore else 188*163bd69bSGarrett D'Amore s->state = CCLASS; 189*163bd69bSGarrett D'Amore } 190*163bd69bSGarrett D'Amore 191*163bd69bSGarrett D'Amore static void 192*163bd69bSGarrett D'Amore genequiv(s) 193*163bd69bSGarrett D'Amore STR *s; 194*163bd69bSGarrett D'Amore { 195*163bd69bSGarrett D'Amore int i, p, pri; 196*163bd69bSGarrett D'Amore char src[2], dst[3]; 197*163bd69bSGarrett D'Amore size_t clen; 198*163bd69bSGarrett D'Amore wchar_t wc; 199*163bd69bSGarrett D'Amore 200*163bd69bSGarrett D'Amore if (*s->str == '\\') { 201*163bd69bSGarrett D'Amore s->equiv[0] = backslash(s, NULL); 202*163bd69bSGarrett D'Amore if (*s->str != '=') 203*163bd69bSGarrett D'Amore errx(1, "misplaced equivalence equals sign"); 204*163bd69bSGarrett D'Amore s->str += 2; 205*163bd69bSGarrett D'Amore } else { 206*163bd69bSGarrett D'Amore clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL); 207*163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2 || clen == 0) { 208*163bd69bSGarrett D'Amore errno = EILSEQ; 209*163bd69bSGarrett D'Amore err(1, NULL); 210*163bd69bSGarrett D'Amore } 211*163bd69bSGarrett D'Amore s->equiv[0] = wc; 212*163bd69bSGarrett D'Amore if (s->str[clen] != '=') 213*163bd69bSGarrett D'Amore errx(1, "misplaced equivalence equals sign"); 214*163bd69bSGarrett D'Amore s->str += clen + 2; 215*163bd69bSGarrett D'Amore } 216*163bd69bSGarrett D'Amore 217*163bd69bSGarrett D'Amore /* 218*163bd69bSGarrett D'Amore * Calculate the set of all characters in the same equivalence class 219*163bd69bSGarrett D'Amore * as the specified character (they will have the same primary 220*163bd69bSGarrett D'Amore * collation weights). 221*163bd69bSGarrett D'Amore * XXX Knows too much about how strxfrm() is implemented. Assumes 222*163bd69bSGarrett D'Amore * it fills the string with primary collation weight bytes. Only one- 223*163bd69bSGarrett D'Amore * to-one mappings are supported. 224*163bd69bSGarrett D'Amore * XXX Equivalence classes not supported in multibyte locales. 225*163bd69bSGarrett D'Amore */ 226*163bd69bSGarrett D'Amore src[0] = (char)s->equiv[0]; 227*163bd69bSGarrett D'Amore src[1] = '\0'; 228*163bd69bSGarrett D'Amore if (MB_CUR_MAX == 1 && strxfrm(dst, src, sizeof (dst)) == 1) { 229*163bd69bSGarrett D'Amore pri = (unsigned char)*dst; 230*163bd69bSGarrett D'Amore for (p = 1, i = 1; i < NCHARS_SB; i++) { 231*163bd69bSGarrett D'Amore *src = i; 232*163bd69bSGarrett D'Amore if (strxfrm(dst, src, sizeof (dst)) == 1 && pri && 233*163bd69bSGarrett D'Amore pri == (unsigned char)*dst) 234*163bd69bSGarrett D'Amore s->equiv[p++] = i; 235*163bd69bSGarrett D'Amore } 236*163bd69bSGarrett D'Amore s->equiv[p] = OOBCH; 237*163bd69bSGarrett D'Amore } 238*163bd69bSGarrett D'Amore 239*163bd69bSGarrett D'Amore s->cnt = 0; 240*163bd69bSGarrett D'Amore s->state = SET; 241*163bd69bSGarrett D'Amore s->set = s->equiv; 242*163bd69bSGarrett D'Amore } 243*163bd69bSGarrett D'Amore 244*163bd69bSGarrett D'Amore static int 245*163bd69bSGarrett D'Amore genrange(STR *s, int was_octal) 246*163bd69bSGarrett D'Amore { 247*163bd69bSGarrett D'Amore int stopval, octal; 248*163bd69bSGarrett D'Amore char *savestart; 249*163bd69bSGarrett D'Amore int n, cnt, *p; 250*163bd69bSGarrett D'Amore size_t clen; 251*163bd69bSGarrett D'Amore wchar_t wc; 252*163bd69bSGarrett D'Amore 253*163bd69bSGarrett D'Amore octal = 0; 254*163bd69bSGarrett D'Amore savestart = s->str; 255*163bd69bSGarrett D'Amore if (*++s->str == '\\') 256*163bd69bSGarrett D'Amore stopval = backslash(s, &octal); 257*163bd69bSGarrett D'Amore else { 258*163bd69bSGarrett D'Amore clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL); 259*163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2) { 260*163bd69bSGarrett D'Amore errno = EILSEQ; 261*163bd69bSGarrett D'Amore err(1, NULL); 262*163bd69bSGarrett D'Amore } 263*163bd69bSGarrett D'Amore stopval = wc; 264*163bd69bSGarrett D'Amore s->str += clen; 265*163bd69bSGarrett D'Amore } 266*163bd69bSGarrett D'Amore /* 267*163bd69bSGarrett D'Amore * XXX Characters are not ordered according to collating sequence in 268*163bd69bSGarrett D'Amore * multibyte locales. 269*163bd69bSGarrett D'Amore */ 270*163bd69bSGarrett D'Amore if (octal || was_octal || MB_CUR_MAX > 1) { 271*163bd69bSGarrett D'Amore if (stopval < s->lastch) { 272*163bd69bSGarrett D'Amore s->str = savestart; 273*163bd69bSGarrett D'Amore return (0); 274*163bd69bSGarrett D'Amore } 275*163bd69bSGarrett D'Amore s->cnt = stopval - s->lastch + 1; 276*163bd69bSGarrett D'Amore s->state = RANGE; 277*163bd69bSGarrett D'Amore --s->lastch; 278*163bd69bSGarrett D'Amore return (1); 279*163bd69bSGarrett D'Amore } 280*163bd69bSGarrett D'Amore if (charcoll((const void *)&stopval, (const void *)&(s->lastch)) < 0) { 281*163bd69bSGarrett D'Amore s->str = savestart; 282*163bd69bSGarrett D'Amore return (0); 283*163bd69bSGarrett D'Amore } 284*163bd69bSGarrett D'Amore p = malloc((NCHARS_SB + 1) * sizeof (int)); 285*163bd69bSGarrett D'Amore if ((s = (void *)p) == NULL) 286*163bd69bSGarrett D'Amore err(1, "genrange() malloc"); 287*163bd69bSGarrett D'Amore for (cnt = 0; cnt < NCHARS_SB; cnt++) 288*163bd69bSGarrett D'Amore if (charcoll((const void *)&cnt, (const void *)&(s->lastch)) >= 289*163bd69bSGarrett D'Amore 0 && 290*163bd69bSGarrett D'Amore charcoll((const void *)&cnt, (const void *)&stopval) <= 0) 291*163bd69bSGarrett D'Amore *p++ = cnt; 292*163bd69bSGarrett D'Amore *p = OOBCH; 293*163bd69bSGarrett D'Amore n = (int *)p - (int *)s->set; 294*163bd69bSGarrett D'Amore 295*163bd69bSGarrett D'Amore s->cnt = 0; 296*163bd69bSGarrett D'Amore s->state = SET; 297*163bd69bSGarrett D'Amore if (n > 1) 298*163bd69bSGarrett D'Amore qsort(s->set, n, sizeof (*(s->set)), charcoll); 299*163bd69bSGarrett D'Amore return (1); 300*163bd69bSGarrett D'Amore } 301*163bd69bSGarrett D'Amore 302*163bd69bSGarrett D'Amore static void 303*163bd69bSGarrett D'Amore genseq(s) 304*163bd69bSGarrett D'Amore STR *s; 305*163bd69bSGarrett D'Amore { 306*163bd69bSGarrett D'Amore char *ep; 307*163bd69bSGarrett D'Amore wchar_t wc; 308*163bd69bSGarrett D'Amore size_t clen; 309*163bd69bSGarrett D'Amore 310*163bd69bSGarrett D'Amore if (s->which == STRING1) 311*163bd69bSGarrett D'Amore errx(1, "sequences only valid in string2"); 312*163bd69bSGarrett D'Amore 313*163bd69bSGarrett D'Amore if (*s->str == '\\') 314*163bd69bSGarrett D'Amore s->lastch = backslash(s, NULL); 315*163bd69bSGarrett D'Amore else { 316*163bd69bSGarrett D'Amore clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL); 317*163bd69bSGarrett D'Amore if (clen == (size_t)-1 || clen == (size_t)-2) { 318*163bd69bSGarrett D'Amore errno = EILSEQ; 319*163bd69bSGarrett D'Amore err(1, NULL); 320*163bd69bSGarrett D'Amore } 321*163bd69bSGarrett D'Amore s->lastch = wc; 322*163bd69bSGarrett D'Amore s->str += clen; 323*163bd69bSGarrett D'Amore } 324*163bd69bSGarrett D'Amore if (*s->str != '*') 325*163bd69bSGarrett D'Amore errx(1, "misplaced sequence asterisk"); 326*163bd69bSGarrett D'Amore 327*163bd69bSGarrett D'Amore switch (*++s->str) { 328*163bd69bSGarrett D'Amore case '\\': 329*163bd69bSGarrett D'Amore s->cnt = backslash(s, NULL); 330*163bd69bSGarrett D'Amore break; 331*163bd69bSGarrett D'Amore case ']': 332*163bd69bSGarrett D'Amore s->cnt = 0; 333*163bd69bSGarrett D'Amore ++s->str; 334*163bd69bSGarrett D'Amore break; 335*163bd69bSGarrett D'Amore default: 336*163bd69bSGarrett D'Amore if (isdigit((uchar_t)*s->str)) { 337*163bd69bSGarrett D'Amore s->cnt = strtol(s->str, &ep, 0); 338*163bd69bSGarrett D'Amore if (*ep == ']') { 339*163bd69bSGarrett D'Amore s->str = ep + 1; 340*163bd69bSGarrett D'Amore break; 341*163bd69bSGarrett D'Amore } 342*163bd69bSGarrett D'Amore } 343*163bd69bSGarrett D'Amore errx(1, "illegal sequence count"); 344*163bd69bSGarrett D'Amore /* NOTREACHED */ 345*163bd69bSGarrett D'Amore } 346*163bd69bSGarrett D'Amore 347*163bd69bSGarrett D'Amore s->state = s->cnt ? SEQUENCE : INFINITE; 348*163bd69bSGarrett D'Amore } 349*163bd69bSGarrett D'Amore 350*163bd69bSGarrett D'Amore /* 351*163bd69bSGarrett D'Amore * Translate \??? into a character. Up to 3 octal digits, if no digits either 352*163bd69bSGarrett D'Amore * an escape code or a literal character. 353*163bd69bSGarrett D'Amore */ 354*163bd69bSGarrett D'Amore static int 355*163bd69bSGarrett D'Amore backslash(STR *s, int *is_octal) 356*163bd69bSGarrett D'Amore { 357*163bd69bSGarrett D'Amore int ch, cnt, val; 358*163bd69bSGarrett D'Amore 359*163bd69bSGarrett D'Amore if (is_octal != NULL) 360*163bd69bSGarrett D'Amore *is_octal = 0; 361*163bd69bSGarrett D'Amore for (cnt = val = 0; ; ) { 362*163bd69bSGarrett D'Amore ch = (uchar_t)*++s->str; 363*163bd69bSGarrett D'Amore if (!isdigit(ch) || ch > '7') 364*163bd69bSGarrett D'Amore break; 365*163bd69bSGarrett D'Amore val = val * 8 + ch - '0'; 366*163bd69bSGarrett D'Amore if (++cnt == 3) { 367*163bd69bSGarrett D'Amore ++s->str; 368*163bd69bSGarrett D'Amore break; 369*163bd69bSGarrett D'Amore } 370*163bd69bSGarrett D'Amore } 371*163bd69bSGarrett D'Amore if (cnt) { 372*163bd69bSGarrett D'Amore if (is_octal != NULL) 373*163bd69bSGarrett D'Amore *is_octal = 1; 374*163bd69bSGarrett D'Amore return (val); 375*163bd69bSGarrett D'Amore } 376*163bd69bSGarrett D'Amore if (ch != '\0') 377*163bd69bSGarrett D'Amore ++s->str; 378*163bd69bSGarrett D'Amore switch (ch) { 379*163bd69bSGarrett D'Amore case 'a': /* escape characters */ 380*163bd69bSGarrett D'Amore return ('\7'); 381*163bd69bSGarrett D'Amore case 'b': 382*163bd69bSGarrett D'Amore return ('\b'); 383*163bd69bSGarrett D'Amore case 'f': 384*163bd69bSGarrett D'Amore return ('\f'); 385*163bd69bSGarrett D'Amore case 'n': 386*163bd69bSGarrett D'Amore return ('\n'); 387*163bd69bSGarrett D'Amore case 'r': 388*163bd69bSGarrett D'Amore return ('\r'); 389*163bd69bSGarrett D'Amore case 't': 390*163bd69bSGarrett D'Amore return ('\t'); 391*163bd69bSGarrett D'Amore case 'v': 392*163bd69bSGarrett D'Amore return ('\13'); 393*163bd69bSGarrett D'Amore case '\0': /* \" -> \ */ 394*163bd69bSGarrett D'Amore s->state = EOS; 395*163bd69bSGarrett D'Amore return ('\\'); 396*163bd69bSGarrett D'Amore default: /* \x" -> x */ 397*163bd69bSGarrett D'Amore return (ch); 398*163bd69bSGarrett D'Amore } 399*163bd69bSGarrett D'Amore } 400