19b50d902SRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni *
49b50d902SRodney W. Grimes * Copyright (c) 1991, 1993
59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved.
69b50d902SRodney W. Grimes *
79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes * are met:
109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes * without specific prior written permission.
189b50d902SRodney W. Grimes *
199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes * SUCH DAMAGE.
309b50d902SRodney W. Grimes */
319b50d902SRodney W. Grimes
3278732475SMark Murray
339b50d902SRodney W. Grimes
349b50d902SRodney W. Grimes #include <sys/types.h>
359b50d902SRodney W. Grimes
36af647767SPhilippe Charnier #include <ctype.h>
37af647767SPhilippe Charnier #include <err.h>
38ca99cfddSTim J. Robbins #include <errno.h>
39821df508SXin LI #include <stddef.h>
40821df508SXin LI #include <stdio.h>
419b50d902SRodney W. Grimes #include <stdlib.h>
429b50d902SRodney W. Grimes #include <string.h>
43ca99cfddSTim J. Robbins #include <wchar.h>
44ca99cfddSTim J. Robbins #include <wctype.h>
459b50d902SRodney W. Grimes
469b50d902SRodney W. Grimes #include "extern.h"
479b50d902SRodney W. Grimes
4821f53e91SAndrey A. Chernov static int backslash(STR *, int *);
493f330d7dSWarner Losh static int bracket(STR *);
503f330d7dSWarner Losh static void genclass(STR *);
513f330d7dSWarner Losh static void genequiv(STR *);
525b4fa425SAndrey A. Chernov static int genrange(STR *, int);
533f330d7dSWarner Losh static void genseq(STR *);
549b50d902SRodney W. Grimes
55ca99cfddSTim J. Robbins wint_t
next(STR * s)56b173dd44SEd Schouten next(STR *s)
579b50d902SRodney W. Grimes {
58ca99cfddSTim J. Robbins int is_octal;
59ca99cfddSTim J. Robbins wint_t ch;
60ca99cfddSTim J. Robbins wchar_t wch;
61ca99cfddSTim J. Robbins size_t clen;
629b50d902SRodney W. Grimes
639b50d902SRodney W. Grimes switch (s->state) {
649b50d902SRodney W. Grimes case EOS:
659b50d902SRodney W. Grimes return (0);
669b50d902SRodney W. Grimes case INFINITE:
679b50d902SRodney W. Grimes return (1);
689b50d902SRodney W. Grimes case NORMAL:
69ca99cfddSTim J. Robbins switch (*s->str) {
709b50d902SRodney W. Grimes case '\0':
719b50d902SRodney W. Grimes s->state = EOS;
729b50d902SRodney W. Grimes return (0);
739b50d902SRodney W. Grimes case '\\':
7421f53e91SAndrey A. Chernov s->lastch = backslash(s, &is_octal);
759b50d902SRodney W. Grimes break;
769b50d902SRodney W. Grimes case '[':
779b50d902SRodney W. Grimes if (bracket(s))
789b50d902SRodney W. Grimes return (next(s));
799b50d902SRodney W. Grimes /* FALLTHROUGH */
809b50d902SRodney W. Grimes default:
81ca99cfddSTim J. Robbins clen = mbrtowc(&wch, s->str, MB_LEN_MAX, NULL);
82ca99cfddSTim J. Robbins if (clen == (size_t)-1 || clen == (size_t)-2 ||
83ca99cfddSTim J. Robbins clen == 0)
84ca99cfddSTim J. Robbins errc(1, EILSEQ, NULL);
8521f53e91SAndrey A. Chernov is_octal = 0;
86ca99cfddSTim J. Robbins s->lastch = wch;
87ca99cfddSTim J. Robbins s->str += clen;
889b50d902SRodney W. Grimes break;
899b50d902SRodney W. Grimes }
909b50d902SRodney W. Grimes
919b50d902SRodney W. Grimes /* We can start a range at any time. */
925b4fa425SAndrey A. Chernov if (s->str[0] == '-' && genrange(s, is_octal))
939b50d902SRodney W. Grimes return (next(s));
949b50d902SRodney W. Grimes return (1);
9530c11564SAndrey A. Chernov case RANGE:
9630c11564SAndrey A. Chernov if (s->cnt-- == 0) {
9730c11564SAndrey A. Chernov s->state = NORMAL;
9830c11564SAndrey A. Chernov return (next(s));
9930c11564SAndrey A. Chernov }
10030c11564SAndrey A. Chernov ++s->lastch;
10130c11564SAndrey A. Chernov return (1);
1029b50d902SRodney W. Grimes case SEQUENCE:
1039b50d902SRodney W. Grimes if (s->cnt-- == 0) {
1049b50d902SRodney W. Grimes s->state = NORMAL;
1059b50d902SRodney W. Grimes return (next(s));
1069b50d902SRodney W. Grimes }
1079b50d902SRodney W. Grimes return (1);
108ca99cfddSTim J. Robbins case CCLASS:
109ca99cfddSTim J. Robbins case CCLASS_UPPER:
110ca99cfddSTim J. Robbins case CCLASS_LOWER:
111ca99cfddSTim J. Robbins s->cnt++;
112ca99cfddSTim J. Robbins ch = nextwctype(s->lastch, s->cclass);
113ca99cfddSTim J. Robbins if (ch == -1) {
114ca99cfddSTim J. Robbins s->state = NORMAL;
115ca99cfddSTim J. Robbins return (next(s));
116ca99cfddSTim J. Robbins }
117ca99cfddSTim J. Robbins s->lastch = ch;
118ca99cfddSTim J. Robbins return (1);
1199b50d902SRodney W. Grimes case SET:
120e42eb683SAndrey A. Chernov if ((ch = s->set[s->cnt++]) == OOBCH) {
1219b50d902SRodney W. Grimes s->state = NORMAL;
1229b50d902SRodney W. Grimes return (next(s));
1239b50d902SRodney W. Grimes }
124e42eb683SAndrey A. Chernov s->lastch = ch;
1259b50d902SRodney W. Grimes return (1);
12678732475SMark Murray default:
12778732475SMark Murray return (0);
1289b50d902SRodney W. Grimes }
1299b50d902SRodney W. Grimes /* NOTREACHED */
1309b50d902SRodney W. Grimes }
1319b50d902SRodney W. Grimes
1329b50d902SRodney W. Grimes static int
bracket(STR * s)133b173dd44SEd Schouten bracket(STR *s)
1349b50d902SRodney W. Grimes {
13578732475SMark Murray char *p;
1369b50d902SRodney W. Grimes
1379b50d902SRodney W. Grimes switch (s->str[1]) {
1389b50d902SRodney W. Grimes case ':': /* "[:class:]" */
139232a0ff5STim J. Robbins if ((p = strchr(s->str + 2, ']')) == NULL)
1409b50d902SRodney W. Grimes return (0);
141232a0ff5STim J. Robbins if (*(p - 1) != ':' || p - s->str < 4)
142232a0ff5STim J. Robbins goto repeat;
143232a0ff5STim J. Robbins *(p - 1) = '\0';
1449b50d902SRodney W. Grimes s->str += 2;
1459b50d902SRodney W. Grimes genclass(s);
146232a0ff5STim J. Robbins s->str = p + 1;
1479b50d902SRodney W. Grimes return (1);
1489b50d902SRodney W. Grimes case '=': /* "[=equiv=]" */
14988deede5SJilles Tjoelker if (s->str[2] == '\0' || (p = strchr(s->str + 3, ']')) == NULL)
1509b50d902SRodney W. Grimes return (0);
151232a0ff5STim J. Robbins if (*(p - 1) != '=' || p - s->str < 4)
152232a0ff5STim J. Robbins goto repeat;
1539b50d902SRodney W. Grimes s->str += 2;
1549b50d902SRodney W. Grimes genequiv(s);
1559b50d902SRodney W. Grimes return (1);
1569b50d902SRodney W. Grimes default: /* "[\###*n]" or "[#*n]" */
157232a0ff5STim J. Robbins repeat:
1589b50d902SRodney W. Grimes if ((p = strpbrk(s->str + 2, "*]")) == NULL)
1599b50d902SRodney W. Grimes return (0);
160b3608ae1SEd Schouten if (p[0] != '*' || strchr(p, ']') == NULL)
1619b50d902SRodney W. Grimes return (0);
1629b50d902SRodney W. Grimes s->str += 1;
1639b50d902SRodney W. Grimes genseq(s);
1649b50d902SRodney W. Grimes return (1);
1659b50d902SRodney W. Grimes }
1669b50d902SRodney W. Grimes /* NOTREACHED */
1679b50d902SRodney W. Grimes }
1689b50d902SRodney W. Grimes
1699b50d902SRodney W. Grimes static void
genclass(STR * s)170b173dd44SEd Schouten genclass(STR *s)
1719b50d902SRodney W. Grimes {
1729b50d902SRodney W. Grimes
173ca99cfddSTim J. Robbins if ((s->cclass = wctype(s->str)) == 0)
174af647767SPhilippe Charnier errx(1, "unknown class %s", s->str);
1759b50d902SRodney W. Grimes s->cnt = 0;
176ca99cfddSTim J. Robbins s->lastch = -1; /* incremented before check in next() */
17700611f04SAndrey A. Chernov if (strcmp(s->str, "upper") == 0)
178ca99cfddSTim J. Robbins s->state = CCLASS_UPPER;
179035944c3SAndrey A. Chernov else if (strcmp(s->str, "lower") == 0)
180ca99cfddSTim J. Robbins s->state = CCLASS_LOWER;
181035944c3SAndrey A. Chernov else
182ca99cfddSTim J. Robbins s->state = CCLASS;
1839b50d902SRodney W. Grimes }
1849b50d902SRodney W. Grimes
1859b50d902SRodney W. Grimes static void
genequiv(STR * s)186b173dd44SEd Schouten genequiv(STR *s)
1879b50d902SRodney W. Grimes {
18885f6c317STim J. Robbins int i, p, pri;
18985f6c317STim J. Robbins char src[2], dst[3];
190ca99cfddSTim J. Robbins size_t clen;
191ca99cfddSTim J. Robbins wchar_t wc;
19285f6c317STim J. Robbins
1939b50d902SRodney W. Grimes if (*s->str == '\\') {
19421f53e91SAndrey A. Chernov s->equiv[0] = backslash(s, NULL);
1959b50d902SRodney W. Grimes if (*s->str != '=')
196af647767SPhilippe Charnier errx(1, "misplaced equivalence equals sign");
197e73c3d27STim J. Robbins s->str += 2;
1989b50d902SRodney W. Grimes } else {
199ca99cfddSTim J. Robbins clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL);
200ca99cfddSTim J. Robbins if (clen == (size_t)-1 || clen == (size_t)-2 || clen == 0)
201ca99cfddSTim J. Robbins errc(1, EILSEQ, NULL);
202ca99cfddSTim J. Robbins s->equiv[0] = wc;
203ca99cfddSTim J. Robbins if (s->str[clen] != '=')
204af647767SPhilippe Charnier errx(1, "misplaced equivalence equals sign");
205ca99cfddSTim J. Robbins s->str += clen + 2;
2069b50d902SRodney W. Grimes }
20785f6c317STim J. Robbins
20885f6c317STim J. Robbins /*
20985f6c317STim J. Robbins * Calculate the set of all characters in the same equivalence class
21085f6c317STim J. Robbins * as the specified character (they will have the same primary
21185f6c317STim J. Robbins * collation weights).
21285f6c317STim J. Robbins * XXX Knows too much about how strxfrm() is implemented. Assumes
21385f6c317STim J. Robbins * it fills the string with primary collation weight bytes. Only one-
21485f6c317STim J. Robbins * to-one mappings are supported.
215ca99cfddSTim J. Robbins * XXX Equivalence classes not supported in multibyte locales.
21685f6c317STim J. Robbins */
217ca99cfddSTim J. Robbins src[0] = (char)s->equiv[0];
21885f6c317STim J. Robbins src[1] = '\0';
219ca99cfddSTim J. Robbins if (MB_CUR_MAX == 1 && strxfrm(dst, src, sizeof(dst)) == 1) {
22085f6c317STim J. Robbins pri = (unsigned char)*dst;
221ca99cfddSTim J. Robbins for (p = 1, i = 1; i < NCHARS_SB; i++) {
22285f6c317STim J. Robbins *src = i;
22385f6c317STim J. Robbins if (strxfrm(dst, src, sizeof(dst)) == 1 && pri &&
22485f6c317STim J. Robbins pri == (unsigned char)*dst)
22585f6c317STim J. Robbins s->equiv[p++] = i;
22685f6c317STim J. Robbins }
22785f6c317STim J. Robbins s->equiv[p] = OOBCH;
22885f6c317STim J. Robbins }
22985f6c317STim J. Robbins
2309b50d902SRodney W. Grimes s->cnt = 0;
2319b50d902SRodney W. Grimes s->state = SET;
2329b50d902SRodney W. Grimes s->set = s->equiv;
2339b50d902SRodney W. Grimes }
2349b50d902SRodney W. Grimes
2359b50d902SRodney W. Grimes static int
genrange(STR * s,int was_octal)2365b4fa425SAndrey A. Chernov genrange(STR *s, int was_octal)
2379b50d902SRodney W. Grimes {
2385b4fa425SAndrey A. Chernov int stopval, octal;
2399b50d902SRodney W. Grimes char *savestart;
2405b4fa425SAndrey A. Chernov int n, cnt, *p;
241ca99cfddSTim J. Robbins size_t clen;
242ca99cfddSTim J. Robbins wchar_t wc;
2439b50d902SRodney W. Grimes
2445b4fa425SAndrey A. Chernov octal = 0;
2459b50d902SRodney W. Grimes savestart = s->str;
246ca99cfddSTim J. Robbins if (*++s->str == '\\')
2475b4fa425SAndrey A. Chernov stopval = backslash(s, &octal);
248ca99cfddSTim J. Robbins else {
249ca99cfddSTim J. Robbins clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL);
250ca99cfddSTim J. Robbins if (clen == (size_t)-1 || clen == (size_t)-2)
251ca99cfddSTim J. Robbins errc(1, EILSEQ, NULL);
252ca99cfddSTim J. Robbins stopval = wc;
253ca99cfddSTim J. Robbins s->str += clen;
254ca99cfddSTim J. Robbins }
2555b4fa425SAndrey A. Chernov /*
2565b4fa425SAndrey A. Chernov * XXX Characters are not ordered according to collating sequence in
2575b4fa425SAndrey A. Chernov * multibyte locales.
2585b4fa425SAndrey A. Chernov */
2595b4fa425SAndrey A. Chernov if (octal || was_octal || MB_CUR_MAX > 1) {
260ca99cfddSTim J. Robbins if (stopval < s->lastch) {
2619b50d902SRodney W. Grimes s->str = savestart;
2629b50d902SRodney W. Grimes return (0);
2639b50d902SRodney W. Grimes }
26430c11564SAndrey A. Chernov s->cnt = stopval - s->lastch + 1;
26530c11564SAndrey A. Chernov s->state = RANGE;
26630c11564SAndrey A. Chernov --s->lastch;
26730c11564SAndrey A. Chernov return (1);
26830c11564SAndrey A. Chernov }
2695b4fa425SAndrey A. Chernov if (charcoll((const void *)&stopval, (const void *)&(s->lastch)) < 0) {
2705b4fa425SAndrey A. Chernov s->str = savestart;
2715b4fa425SAndrey A. Chernov return (0);
2725b4fa425SAndrey A. Chernov }
2735b4fa425SAndrey A. Chernov if ((s->set = p = malloc((NCHARS_SB + 1) * sizeof(int))) == NULL)
2745b4fa425SAndrey A. Chernov err(1, "genrange() malloc");
2755b4fa425SAndrey A. Chernov for (cnt = 0; cnt < NCHARS_SB; cnt++)
2765b4fa425SAndrey A. Chernov if (charcoll((const void *)&cnt, (const void *)&(s->lastch)) >= 0 &&
2775b4fa425SAndrey A. Chernov charcoll((const void *)&cnt, (const void *)&stopval) <= 0)
2785b4fa425SAndrey A. Chernov *p++ = cnt;
2795b4fa425SAndrey A. Chernov *p = OOBCH;
2805b4fa425SAndrey A. Chernov n = p - s->set;
2815b4fa425SAndrey A. Chernov
2825b4fa425SAndrey A. Chernov s->cnt = 0;
2835b4fa425SAndrey A. Chernov s->state = SET;
2845b4fa425SAndrey A. Chernov if (n > 1)
2855b4fa425SAndrey A. Chernov mergesort(s->set, n, sizeof(*(s->set)), charcoll);
2865b4fa425SAndrey A. Chernov return (1);
2875b4fa425SAndrey A. Chernov }
2889b50d902SRodney W. Grimes
2899b50d902SRodney W. Grimes static void
genseq(STR * s)290b173dd44SEd Schouten genseq(STR *s)
2919b50d902SRodney W. Grimes {
2929b50d902SRodney W. Grimes char *ep;
293ca99cfddSTim J. Robbins wchar_t wc;
294ca99cfddSTim J. Robbins size_t clen;
2959b50d902SRodney W. Grimes
2969b50d902SRodney W. Grimes if (s->which == STRING1)
297af647767SPhilippe Charnier errx(1, "sequences only valid in string2");
2989b50d902SRodney W. Grimes
2999b50d902SRodney W. Grimes if (*s->str == '\\')
30021f53e91SAndrey A. Chernov s->lastch = backslash(s, NULL);
301ca99cfddSTim J. Robbins else {
302ca99cfddSTim J. Robbins clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL);
303ca99cfddSTim J. Robbins if (clen == (size_t)-1 || clen == (size_t)-2)
304ca99cfddSTim J. Robbins errc(1, EILSEQ, NULL);
305ca99cfddSTim J. Robbins s->lastch = wc;
306ca99cfddSTim J. Robbins s->str += clen;
307ca99cfddSTim J. Robbins }
3089b50d902SRodney W. Grimes if (*s->str != '*')
309af647767SPhilippe Charnier errx(1, "misplaced sequence asterisk");
3109b50d902SRodney W. Grimes
3119b50d902SRodney W. Grimes switch (*++s->str) {
3129b50d902SRodney W. Grimes case '\\':
31321f53e91SAndrey A. Chernov s->cnt = backslash(s, NULL);
3149b50d902SRodney W. Grimes break;
3159b50d902SRodney W. Grimes case ']':
3169b50d902SRodney W. Grimes s->cnt = 0;
3179b50d902SRodney W. Grimes ++s->str;
3189b50d902SRodney W. Grimes break;
3199b50d902SRodney W. Grimes default:
3203281f9d8SJoerg Wunsch if (isdigit((u_char)*s->str)) {
3219b50d902SRodney W. Grimes s->cnt = strtol(s->str, &ep, 0);
3229b50d902SRodney W. Grimes if (*ep == ']') {
3239b50d902SRodney W. Grimes s->str = ep + 1;
3249b50d902SRodney W. Grimes break;
3259b50d902SRodney W. Grimes }
3269b50d902SRodney W. Grimes }
327af647767SPhilippe Charnier errx(1, "illegal sequence count");
3289b50d902SRodney W. Grimes /* NOTREACHED */
3299b50d902SRodney W. Grimes }
3309b50d902SRodney W. Grimes
3319b50d902SRodney W. Grimes s->state = s->cnt ? SEQUENCE : INFINITE;
3329b50d902SRodney W. Grimes }
3339b50d902SRodney W. Grimes
3349b50d902SRodney W. Grimes /*
3359b50d902SRodney W. Grimes * Translate \??? into a character. Up to 3 octal digits, if no digits either
3369b50d902SRodney W. Grimes * an escape code or a literal character.
3379b50d902SRodney W. Grimes */
3389b50d902SRodney W. Grimes static int
backslash(STR * s,int * is_octal)33921f53e91SAndrey A. Chernov backslash(STR *s, int *is_octal)
3409b50d902SRodney W. Grimes {
34178732475SMark Murray int ch, cnt, val;
3429b50d902SRodney W. Grimes
34321f53e91SAndrey A. Chernov if (is_octal != NULL)
34421f53e91SAndrey A. Chernov *is_octal = 0;
3459b50d902SRodney W. Grimes for (cnt = val = 0;;) {
3463281f9d8SJoerg Wunsch ch = (u_char)*++s->str;
34703afb27cSJordan K. Hubbard if (!isdigit(ch) || ch > '7')
3489b50d902SRodney W. Grimes break;
3499b50d902SRodney W. Grimes val = val * 8 + ch - '0';
3509b50d902SRodney W. Grimes if (++cnt == 3) {
3519b50d902SRodney W. Grimes ++s->str;
3529b50d902SRodney W. Grimes break;
3539b50d902SRodney W. Grimes }
3549b50d902SRodney W. Grimes }
35521f53e91SAndrey A. Chernov if (cnt) {
35621f53e91SAndrey A. Chernov if (is_octal != NULL)
35721f53e91SAndrey A. Chernov *is_octal = 1;
3589b50d902SRodney W. Grimes return (val);
35921f53e91SAndrey A. Chernov }
3609b50d902SRodney W. Grimes if (ch != '\0')
3619b50d902SRodney W. Grimes ++s->str;
3629b50d902SRodney W. Grimes switch (ch) {
3639b50d902SRodney W. Grimes case 'a': /* escape characters */
3649b50d902SRodney W. Grimes return ('\7');
3659b50d902SRodney W. Grimes case 'b':
3669b50d902SRodney W. Grimes return ('\b');
3679b50d902SRodney W. Grimes case 'f':
3689b50d902SRodney W. Grimes return ('\f');
3699b50d902SRodney W. Grimes case 'n':
3709b50d902SRodney W. Grimes return ('\n');
3719b50d902SRodney W. Grimes case 'r':
3729b50d902SRodney W. Grimes return ('\r');
3739b50d902SRodney W. Grimes case 't':
3749b50d902SRodney W. Grimes return ('\t');
3759b50d902SRodney W. Grimes case 'v':
3769b50d902SRodney W. Grimes return ('\13');
3779b50d902SRodney W. Grimes case '\0': /* \" -> \ */
3789b50d902SRodney W. Grimes s->state = EOS;
3799b50d902SRodney W. Grimes return ('\\');
3809b50d902SRodney W. Grimes default: /* \x" -> x */
3819b50d902SRodney W. Grimes return (ch);
3829b50d902SRodney W. Grimes }
3839b50d902SRodney W. Grimes }
384