Update contrib.
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 /* Portions Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).All rights reserved. */
38 #if defined(LIBC_SCCS) && !defined(lint)
39 static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
40 #endif /* LIBC_SCCS and not lint */
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.23 2005/09/14 19:14:32 ache Exp $");
46 * glob(3) -- a superset of the one defined in POSIX 1003.2.
48 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
50 * Optional extra services, controlled by flags not defined by POSIX:
53 * Escaping convention: \ inhibits any special meaning the following
54 * character might have (except \ at end of string is retained).
56 * Set in gl_flags if pattern contained a globbing character.
58 * Same as GLOB_NOCHECK, but it will only append pattern if it did
59 * not contain any magic characters. [Used in csh style globbing]
61 * Use alternately specified directory access functions.
63 * expand ~user/foo to the /home/dir/of/user/foo
65 * expand {1,2}{a,b} to 1a 1b 2a 2b
67 * Number of matches in the current invocation of glob.
71 * Some notes on multibyte character support:
72 * 1. Patterns with illegal byte sequences match nothing - even if
73 * GLOB_NOCHECK is specified.
74 * 2. Illegal byte sequences in filenames are handled by treating them as
75 * single-byte characters with a value of the first byte of the sequence
77 * 3. State-dependent encodings are not currently supported.
80 #include <sys/param.h>
96 #include "libc_collate.h"
99 #if (defined(__SYMBIAN32__) && (defined(__WINSCW__) || defined(__WINS__)))
101 #include "libc_wsd_defs.h"
104 #endif //defined(__SYMBIAN32__) && (defined(__WINSCW__) || defined(__WINS__))
110 extern char LC_COLLATE_LocaleName[30];
112 char *GET_WSD_VAR_NAME(LC_COLLATE_LocaleName, g)();
113 #define LC_COLLATE_LocaleName (GET_WSD_VAR_NAME(LC_COLLATE_LocaleName, g)())
116 //Declared and defined from libc_collate.h and vfscanf.c
117 extern int __collate_range_cmp(int , int );
118 #endif //__SYMBIAN32__
132 // For Symbian Environment the path is specified using the '\'
133 // unlike in the Linux where the path seprator '/' is used.
134 // Since '\\' as path seprator is used the escaping flag
135 // 'QUOTE' cannot be used here.
136 // For e.g. ..\\test\\hollows\\*
142 #endif //__SYMBIAN32__
147 #define UNDERSCORE '_'
154 #ifndef __SYMBIAN32__
158 #define M_QUOTE 0x8000000000ULL
159 #define M_PROTECT 0x4000000000ULL
160 #define M_MASK 0xffffffffffULL
161 #define M_CHAR 0x00ffffffffULL
163 typedef uint_fast64_t Char;
168 #define M_PROTECT 0x40
176 #else //__SYMBIAN32__
179 #define M_PROTECT 0x40
183 typedef unsigned char Char;
185 #endif //__SYMBIAN32__
187 #define CHAR(c) ((Char)((c)&M_CHAR))
188 #define META(c) ((Char)((c)|M_QUOTE))
189 #define M_ALL META('*')
190 #define M_END META(']')
191 #define M_NOT META('!')
192 #define M_ONE META('?')
193 #define M_RNG META('-')
194 #define M_SET META('[')
195 #define ismeta(c) (((c)&M_QUOTE) != 0)
198 static int compare(const void *, const void *);
199 static int g_Ctoc(const Char *, char *, u_int);
200 static int g_lstat(Char *, struct stat *, glob_t *);
201 static DIR *g_opendir(Char *, glob_t *);
202 static Char *g_strchr(Char *, wchar_t);
204 static Char *g_strcat(Char *, const Char *);
206 static int g_stat(Char *, struct stat *, glob_t *);
207 static int glob0(const Char *, glob_t *, int *);
208 static int glob1(Char *, glob_t *, int *);
209 static int glob2(Char *, Char *, Char *, Char *, glob_t *, int *);
210 static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, int *);
211 static int globextend(const Char *, glob_t *, int *);
213 globtilde(const Char *, Char *, size_t, glob_t *);
214 static int globexp1(const Char *, glob_t *, int *);
215 static int globexp2(const Char *, const Char *, glob_t *, int *, int *);
216 static int match(Char *, Char *, Char *);
218 static void qprintf(const char *, Char *);
221 // EXTERNAL FUNCTION PROTOTYPES
224 //--------------------------------------------------------------------------------------------
225 //Function Name : int glob(glob(const char *, int flags, int (*)(const char *, int), glob_t *)
226 //Description : It takes pattern to be searched, flags and the structure of the type glob_t.
227 // It can optionally also take If errfunc is not NULL, it will be called in
228 // error with the arguments epath, a pointer to the case of an path which
231 //Return Value : If successful returns the pathnames of the searched pattern contained
232 // in the glob_t structure member reference pointer gl_pathv. In case
233 // failure, gl_pathv is NULL.
234 //----------------------------------------------------------------------------------------------
237 glob(pattern, flags, errfunc, pglob)
239 int flags, (*errfunc)(const char *, int);
242 const u_char *patnext;
244 Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
249 patnext = (u_char *) pattern;
251 // Since we are using '\\' as path seprator, this flag needs to be mentioned
252 // by default in Symbian. Instead this can be hardcoded here.
255 flags = flags | GLOB_NOESCAPE;
258 if (!(flags & GLOB_APPEND)) {
260 pglob->gl_pathv = NULL;
261 if (!(flags & GLOB_DOOFFS))
264 if (flags & GLOB_LIMIT) {
265 limit = pglob->gl_matchc;
270 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
271 pglob->gl_errfunc = errfunc;
272 pglob->gl_matchc = 0;
275 bufend = bufnext + MAXPATHLEN - 1;
276 if (flags & GLOB_NOESCAPE) {
277 memset(&mbs, 0, sizeof(mbs));
278 while (bufend - bufnext >= MB_CUR_MAX) {
279 clen = mbrtowc(&wc,(char*)patnext, MB_LEN_MAX, &mbs);
280 if (clen == (size_t)-1 || clen == (size_t)-2)
281 return (GLOB_NOMATCH);
288 /* Protect the quoted characters. */
289 memset(&mbs, 0, sizeof(mbs));
290 while (bufend - bufnext >= MB_CUR_MAX) {
291 if (*patnext == QUOTE) {
292 if (*++patnext == EOS) {
293 *bufnext++ = QUOTE | M_PROTECT;
299 clen = mbrtowc(&wc, (char*)patnext, MB_LEN_MAX, &mbs);
300 if (clen == (size_t)-1 || clen == (size_t)-2)
301 return (GLOB_NOMATCH);
304 *bufnext++ = wc | prot;
310 if (flags & GLOB_BRACE)
311 return globexp1(patbuf, pglob, &limit);
313 return glob0(patbuf, pglob, &limit);
317 * Expand recursively a glob {} pattern. When there is no more expansion
318 * invoke the standard globbing routine to glob the rest of the magic
322 globexp1(pattern, pglob, limit)
327 const Char* ptr = pattern;
330 /* Protect a single {}, for find(1), like csh */
331 if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
332 return glob0(pattern, pglob, limit);
334 while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
335 if (!globexp2(ptr, pattern, pglob, &rv, limit))
338 return glob0(pattern, pglob, limit);
343 * Recursive brace globbing helper. Tries to expand a single brace.
344 * If it succeeds then it invokes globexp1 with the new pattern.
345 * If it fails then it tries to glob the rest of the pattern and returns.
348 globexp2(ptr, pattern, pglob, rv, limit)
349 const Char *ptr, *pattern;
355 const Char *pe, *pm, *pm1, *pl;
356 Char patbuf[MAXPATHLEN];
358 /* copy part up to the brace */
359 for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
364 /* Find the balanced brace */
365 for (i = 0, pe = ++ptr; *pe; pe++)
366 if (*pe == LBRACKET) {
367 /* Ignore everything between [] */
368 for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
372 * We could not find a matching RBRACKET.
373 * Ignore and just look for RBRACE
378 else if (*pe == LBRACE)
380 else if (*pe == RBRACE) {
386 /* Non matching braces; just glob the pattern */
387 if (i != 0 || *pe == EOS) {
388 *rv = glob0(patbuf, pglob, limit);
392 for (i = 0, pl = pm = ptr; pm <= pe; pm++)
395 /* Ignore everything between [] */
396 for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++)
400 * We could not find a matching RBRACKET.
401 * Ignore and just look for RBRACE
418 if (i && *pm == COMMA)
421 /* Append the current string */
422 for (lm = ls; (pl < pm); *lm++ = *pl++)
425 * Append the rest of the pattern after the
428 for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
431 /* Expand the current pattern */
433 qprintf("globexp2:", patbuf);
435 *rv = globexp1(patbuf, pglob, limit);
437 /* move after the comma, to the next string */
451 * expand tilde from the passwd file.
455 globtilde(pattern, patbuf, patbuf_len, pglob)
462 #ifndef __SYMBIAN32__
470 if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
474 * Copy up to the end of the string or /
477 eb = &patbuf[patbuf_len - 1];
481 for (p = pattern + 1, h = (char *) patbuf;
482 h < (char *)eb && *p && *p != SEP ; *h++ = *p++)
487 if (((char *) patbuf)[0] == EOS) {
489 * handle a plain ~ or ~\\ by getting the
490 * secure Id for this process. It shall
491 * return the path as C:\\private\\<secureId>
492 * on emulator and Z:\\private\\<secureId>
495 if( NULL == getcwd(h, patbuf_len) )
501 * Its ~<path>\\.. This will not be handled. Returns the
509 for (p = pattern + 1, h = (char *) patbuf;
510 h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
515 if (((char *) patbuf)[0] == EOS) {
517 * handle a plain ~ or ~/ by expanding $HOME first (iff
518 * we're not running setuid or setgid) and then trying
521 if (issetugid() != 0 ||
522 (h = getenv("HOME")) == NULL) {
523 if (((h = getlogin()) != NULL &&
524 (pwd = getpwnam(h)) != NULL) ||
525 (pwd = getpwuid(getuid())) != NULL)
535 if ((pwd = getpwnam((char*) patbuf)) == NULL)
541 #endif //__SYMBIAN32__
544 /* Copy the home directory */
545 for (b = patbuf; b < eb && *h; *b++ = *h++)
548 /* Append the rest of the pattern */
549 while (b < eb && (*b++ = *p++) != EOS)
558 * The main glob() routine: compiles the pattern (optionally processing
559 * quotes), calls glob1() to do the real pattern matching, and finally
560 * sorts the list (unless unsorted operation is requested). Returns 0
561 * if things went well, nonzero if errors occurred.
564 glob0(pattern, pglob, limit)
569 const Char *qpatnext;
570 int c, err, oldpathc;
571 Char *bufnext, patbuf[MAXPATHLEN];
573 qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
574 oldpathc = pglob->gl_pathc;
577 /* We don't need to check for buffer overflow any more. */
578 while ((c = *qpatnext++) != EOS) {
584 if (*qpatnext == EOS ||
585 g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
586 *bufnext++ = LBRACKET;
596 *bufnext++ = CHAR(c);
597 if (*qpatnext == RANGE &&
598 (c = qpatnext[1]) != RBRACKET) {
600 *bufnext++ = CHAR(c);
603 } while ((c = *qpatnext++) != RBRACKET);
604 pglob->gl_flags |= GLOB_MAGCHAR;
608 pglob->gl_flags |= GLOB_MAGCHAR;
612 pglob->gl_flags |= GLOB_MAGCHAR;
613 /* collapse adjacent stars to one,
614 * to avoid exponential behavior
616 if (bufnext == patbuf || bufnext[-1] != M_ALL)
620 *bufnext++ = CHAR(c);
626 qprintf("glob0:", patbuf);
629 if ((err = glob1(patbuf, pglob, limit)) != 0)
633 * If there was no match we are going to append the pattern
634 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
635 * and the pattern did not contain any magic characters
636 * GLOB_NOMAGIC is there just for compatibility with csh.
638 if (pglob->gl_pathc == oldpathc) {
639 if (((pglob->gl_flags & GLOB_NOCHECK) ||
640 ((pglob->gl_flags & GLOB_NOMAGIC) &&
641 !(pglob->gl_flags & GLOB_MAGCHAR))))
642 return(globextend(pattern, pglob, limit));
644 return(GLOB_NOMATCH);
646 if (!(pglob->gl_flags & GLOB_NOSORT))
647 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
648 pglob->gl_pathc - oldpathc, sizeof(char *), compare);
656 return(strcmp(*(char **)p, *(char **)q));
660 glob1(pattern, pglob, limit)
665 Char pathbuf[MAXPATHLEN];
667 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
670 return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
671 pattern, pglob, limit));
675 * The functions glob2 and glob3 are mutually recursive; there is one level
676 * of recursion for each segment in the pattern that contains one or more
680 glob2(pathbuf, pathend, pathend_last, pattern, pglob, limit)
681 Char *pathbuf, *pathend, *pathend_last, *pattern;
690 * Loop over pattern segments until end of pattern or until
691 * segment with meta character found.
693 for (anymeta = 0;;) {
694 if (*pattern == EOS) { /* End of pattern? */
696 if (g_lstat(pathbuf, &sb, pglob))
699 if (((pglob->gl_flags & GLOB_MARK) &&
700 pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
701 || (S_ISLNK(sb.st_mode) &&
702 (g_stat(pathbuf, &sb, pglob) == 0) &&
703 S_ISDIR(sb.st_mode)))) {
704 if (pathend + 1 > pathend_last)
705 return (GLOB_ABORTED);
710 return(globextend(pathbuf, pglob, limit));
713 /* Find end of next segment, copy tentatively to pathend. */
716 while (*p != EOS && *p != SEP) {
719 if (q + 1 > pathend_last)
720 return (GLOB_ABORTED);
724 if (!anymeta) { /* No expansion, do next segment. */
727 while (*pattern == SEP) {
728 if (pathend + 1 > pathend_last)
729 return (GLOB_ABORTED);
730 *pathend++ = *pattern++;
732 } else /* Need expansion, recurse. */
733 return(glob3(pathbuf, pathend, pathend_last, pattern, p,
740 glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit)
741 Char *pathbuf, *pathend, *pathend_last, *pattern, *restpattern;
748 char buf[MAXPATHLEN];
751 * The readdirfunc declaration can't be prototyped, because it is
752 * assigned, below, to two functions which are prototyped in glob.h
753 * and dirent.h as taking pointers to differently typed opaque
756 struct dirent *(*readdirfunc)();
758 if (pathend > pathend_last)
759 return (GLOB_ABORTED);
763 if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
764 /* TODO: don't call for ENOENT or ENOTDIR? */
765 if (pglob->gl_errfunc) {
766 if (g_Ctoc(pathbuf, buf, sizeof(buf)))
767 return (GLOB_ABORTED);
768 if (pglob->gl_errfunc(buf, errno) ||
769 pglob->gl_flags & GLOB_ERR)
770 return (GLOB_ABORTED);
777 /* Search directory for matching names. */
778 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
779 readdirfunc = pglob->gl_readdir;
781 readdirfunc = readdir;
782 while (NULL != (dp = (*readdirfunc)(dirp))) {
789 /* Initial DOT must be matched literally. */
790 if (dp->d_name[0] == DOT && *pattern != DOT)
792 memset(&mbs, 0, sizeof(mbs));
794 sc = (u_char *) dp->d_name;
795 while (dc < pathend_last) {
796 clen = mbrtowc(&wc,(char*)sc, MB_LEN_MAX, &mbs);
797 if (clen == (size_t)-1 || clen == (size_t)-2) {
800 memset(&mbs, 0, sizeof(mbs));
802 if ((*dc++ = wc) == EOS)
806 if (!match(pathend, pattern, restpattern)) {
810 err = glob2(pathbuf, --dc, pathend_last, restpattern,
816 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
817 (*pglob->gl_closedir)(dirp);
825 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
826 * add the new item, and update gl_pathc.
828 * This assumes the BSD realloc, which only copies the block when its size
829 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
832 * Return 0 if new item added, error code if memory couldn't be allocated.
834 * Invariant of the glob_t structure:
835 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
836 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
839 globextend(path, pglob, limit)
850 if (*limit && pglob->gl_pathc > *limit) {
852 return (GLOB_NOSPACE);
855 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
856 pathv = pglob->gl_pathv ?
857 realloc((char *)pglob->gl_pathv, newsize) :
860 if (pglob->gl_pathv) {
861 free(pglob->gl_pathv);
862 pglob->gl_pathv = NULL;
864 return(GLOB_NOSPACE);
867 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
868 /* first time around -- clear initial gl_offs items */
869 pathv += pglob->gl_offs;
870 for (i = pglob->gl_offs; --i >= 0; )
873 pglob->gl_pathv = pathv;
875 for (p = path; *p++;)
877 len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
878 if ((copy = malloc(len)) != NULL) {
879 if (g_Ctoc(path, copy, len)) {
881 return (GLOB_NOSPACE);
883 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
885 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
886 return(copy == NULL ? GLOB_NOSPACE : 0);
890 * pattern matching function for filenames. Each occurrence of the *
891 * pattern causes a recursion level.
894 match(name, pat, patend)
895 Char *name, *pat, *patend;
897 int ok, negate_range;
900 while (pat < patend) {
902 switch (c & M_MASK) {
907 if (match(name, pat, patend))
909 while (*name++ != EOS);
917 if ((k = *name++) == EOS)
919 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
921 while (((c = *pat++) & M_MASK) != M_END)
922 if ((*pat & M_MASK) == M_RNG) {
924 // As used in vfscanf.c
925 #ifndef __SYMBIAN32__
926 __collate_load_error ?
928 ((strcmp("C",(const char*) LC_COLLATE_LocaleName)==0) ||(strcmp("POSIX", (const char*) LC_COLLATE_LocaleName)==0 )) ?
930 CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
931 __collate_range_cmp(CHAR(c), CHAR(k)) <= 0
932 && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
938 if (ok == negate_range)
947 return(*name == EOS);
953 // EXTERNAL FUNCTION PROTOTYPES
954 //-----------------------------------------------------------------------------
955 //Function Name : void globfree(struct glob_t*)
957 //Description : Free allocated data belonging to a glob_t structure. Memory
958 // which was dynamically allocated storage from an earlier call to glob()
960 //Return Value : None
962 //-----------------------------------------------------------------------------
972 if (pglob->gl_pathv != NULL) {
973 pp = pglob->gl_pathv + pglob->gl_offs;
974 for (i = pglob->gl_pathc; i--; ++pp)
977 free(pglob->gl_pathv);
978 pglob->gl_pathv = NULL;
983 g_opendir(str, pglob)
987 char buf[MAXPATHLEN];
992 if (g_Ctoc(str, buf, sizeof(buf)))
996 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
997 return((*pglob->gl_opendir)(buf));
999 return(opendir(buf));
1003 g_lstat(fn, sb, pglob)
1008 char buf[MAXPATHLEN];
1010 if (g_Ctoc(fn, buf, sizeof(buf))) {
1011 errno = ENAMETOOLONG;
1014 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1015 return((*pglob->gl_lstat)(buf, sb));
1016 return(lstat(buf, sb));
1020 g_stat(fn, sb, pglob)
1025 char buf[MAXPATHLEN];
1027 if (g_Ctoc(fn, buf, sizeof(buf))) {
1028 errno = ENAMETOOLONG;
1031 if (pglob->gl_flags & GLOB_ALTDIRFUNC)
1032 return((*pglob->gl_stat)(buf, sb));
1033 return(stat(buf, sb));
1037 g_strchr(Char *str, wchar_t ch)
1047 g_Ctoc(str, buf, len)
1055 memset(&mbs, 0, sizeof(mbs));
1056 while (len >= MB_CUR_MAX) {
1057 clen = wcrtomb(buf, *str, &mbs);
1058 if (clen == (size_t)-1)
1077 (void)printf("%s:\n", str);
1078 for (p = s; *p; p++)
1079 (void)printf("%c", CHAR(*p));
1081 for (p = s; *p; p++)
1082 (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
1084 for (p = s; *p; p++)
1085 (void)printf("%c", ismeta(*p) ? '_' : ' ');