xref: /csrg-svn/lib/libc/gen/glob.c (revision 50050)
140087Sbostic /*
240087Sbostic  * Copyright (c) 1989 The Regents of the University of California.
340087Sbostic  * All rights reserved.
440087Sbostic  *
540087Sbostic  * This code is derived from software contributed to Berkeley by
640087Sbostic  * Guido van Rossum.
740087Sbostic  *
842625Sbostic  * %sccs.include.redist.c%
940087Sbostic  */
1040087Sbostic 
1140087Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*50050Sbostic static char sccsid[] = "@(#)glob.c	5.10 (Berkeley) 06/17/91";
1340087Sbostic #endif /* LIBC_SCCS and not lint */
1440087Sbostic 
1540087Sbostic /*
16*50050Sbostic  * glob(3) -- a superset of the one defined in POSIX 1003.2.
1740087Sbostic  *
1840087Sbostic  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
1940087Sbostic  *
2040087Sbostic  * Optional extra services, controlled by flags not defined by POSIX:
2147590Sbostic  *
2247590Sbostic  * GLOB_QUOTE:
2347590Sbostic  *	Escaping convention: \ inhibits any special meaning the following
2447590Sbostic  *	character might have (except \ at end of string is retained).
2547590Sbostic  * GLOB_MAGCHAR:
2648540Sbostic  *	Set in gl_flags if pattern contained a globbing character.
2747590Sbostic  * gl_matchc:
2847590Sbostic  *	Number of matches in the current invocation of glob.
2940087Sbostic  */
3040087Sbostic 
3148540Sbostic #include <sys/cdefs.h>
3240087Sbostic #include <sys/param.h>
3340087Sbostic #include <sys/stat.h>
3440087Sbostic #include <dirent.h>
3540087Sbostic #include <glob.h>
3640087Sbostic #include <ctype.h>
3740087Sbostic #include <errno.h>
3840087Sbostic #include <string.h>
3940087Sbostic #include <stdio.h>
4046597Sdonn #include <stdlib.h>
4140087Sbostic 
4240087Sbostic #define	DOLLAR		'$'
4340087Sbostic #define	DOT		'.'
4440087Sbostic #define	EOS		'\0'
4540087Sbostic #define	LBRACKET	'['
4640087Sbostic #define	NOT		'!'
4740087Sbostic #define	QUESTION	'?'
4840087Sbostic #define	QUOTE		'\\'
4940087Sbostic #define	RANGE		'-'
5040087Sbostic #define	RBRACKET	']'
5140087Sbostic #define	SEP		'/'
5240087Sbostic #define	STAR		'*'
5340087Sbostic #define	TILDE		'~'
5440087Sbostic #define	UNDERSCORE	'_'
5540087Sbostic 
5650049Sbostic #define	M_QUOTE		0x8000
5750049Sbostic #define	M_PROTECT	0x4000
5848540Sbostic #define	M_MASK		0xffff
5948540Sbostic 
6050049Sbostic #define	META(c)		((c)|M_QUOTE)
6140087Sbostic #define	M_ALL		META('*')
6240087Sbostic #define	M_END		META(']')
6340087Sbostic #define	M_NOT		META('!')
6440087Sbostic #define	M_ONE		META('?')
6540087Sbostic #define	M_RNG		META('-')
6640087Sbostic #define	M_SET		META('[')
6750049Sbostic #define	ismeta(c)	(((c)&M_QUOTE) != 0)
6840087Sbostic 
69*50050Sbostic typedef u_short Char;
7050049Sbostic 
71*50050Sbostic static int	 compare __P((const void *, const void *));
72*50050Sbostic static void	 g_Ctoc __P((Char *, char *));
73*50050Sbostic static int	 g_lstat __P((Char *, struct stat *));
74*50050Sbostic static DIR	*g_opendir __P((Char *));
75*50050Sbostic static Char	*g_strchr __P((Char *, int));
76*50050Sbostic static int	 g_stat __P((Char *, struct stat *));
77*50050Sbostic static int	 glob1 __P((Char *, glob_t *));
78*50050Sbostic static int	 glob2 __P((Char *, Char *, Char *, glob_t *));
79*50050Sbostic static int	 glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
80*50050Sbostic static int	 globextend __P((Char *, glob_t *));
81*50050Sbostic static int	 match __P((Char *, Char *, Char *));
8250049Sbostic #ifdef DEBUG
83*50050Sbostic static void	 qprintf __P((Char *));
8450049Sbostic #endif
8550049Sbostic 
8640087Sbostic /*
8740087Sbostic  * The main glob() routine: compiles the pattern (optionally processing
8840087Sbostic  * quotes), calls glob1() to do the real pattern matching, and finally
8940087Sbostic  * sorts the list (unless unsorted operation is requested).  Returns 0
9040087Sbostic  * if things went well, nonzero if errors occurred.  It is not an error
9140087Sbostic  * to find no matches.
9240087Sbostic  */
9340087Sbostic glob(pattern, flags, errfunc, pglob)
9446597Sdonn 	const char *pattern;
95*50050Sbostic 	int flags, (*errfunc) __P((char *, int));
9640087Sbostic 	glob_t *pglob;
9740087Sbostic {
98*50050Sbostic 	const char *compilepat, *patnext;
9940087Sbostic 	int err, oldpathc;
100*50050Sbostic 	Char *bufnext, *bufend, *compilebuf, *qpatnext, patbuf[MAXPATHLEN+1];
10148540Sbostic 	char c;
10240087Sbostic 
10340087Sbostic 	patnext = pattern;
10440087Sbostic 	if (!(flags & GLOB_APPEND)) {
10540087Sbostic 		pglob->gl_pathc = 0;
10640087Sbostic 		pglob->gl_pathv = NULL;
10740087Sbostic 		if (!(flags & GLOB_DOOFFS))
10840087Sbostic 			pglob->gl_offs = 0;
10940087Sbostic 	}
11047590Sbostic 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
11140087Sbostic 	pglob->gl_errfunc = errfunc;
11240087Sbostic 	oldpathc = pglob->gl_pathc;
11347590Sbostic 	pglob->gl_matchc = 0;
11440087Sbostic 
11540087Sbostic 	bufnext = patbuf;
11650049Sbostic 	bufend = bufnext + MAXPATHLEN;
117*50050Sbostic 	compilebuf = bufnext;
118*50050Sbostic 	compilepat = patnext;
11950049Sbostic 	if (flags & GLOB_QUOTE) {
120*50050Sbostic 		/* Protect the quoted characters. */
12150049Sbostic 		while (bufnext < bufend && (c = *patnext++) != EOS)
12250049Sbostic 			if (c == QUOTE) {
12350049Sbostic 				if ((c = *patnext++) == EOS) {
12450049Sbostic 					c = QUOTE;
12550049Sbostic 					--patnext;
12650049Sbostic 				}
12750049Sbostic 				*bufnext++ = c | M_PROTECT;
12850049Sbostic 			}
12950049Sbostic 			else
13050049Sbostic 				*bufnext++ = c;
13150049Sbostic 	}
13250049Sbostic 	else
13350049Sbostic 	    while (bufnext < bufend && (c = *patnext++) != EOS)
13450049Sbostic 		    *bufnext++ = c;
13550049Sbostic 	*bufnext = EOS;
13640087Sbostic 
13750049Sbostic 	bufnext = patbuf;
13850049Sbostic 	qpatnext = patbuf;
139*50050Sbostic 	/* We don't need to check for buffer overflow any more. */
14050049Sbostic 	while ((c = *qpatnext++) != EOS) {
14140087Sbostic 		switch (c) {
14240087Sbostic 		case LBRACKET:
14347590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
14450049Sbostic 			c = *qpatnext;
14540087Sbostic 			if (c == NOT)
14650049Sbostic 				++qpatnext;
14750049Sbostic 			if (*qpatnext == EOS ||
148*50050Sbostic 			    g_strchr(qpatnext+1, RBRACKET) == NULL) {
14940087Sbostic 				*bufnext++ = LBRACKET;
15040087Sbostic 				if (c == NOT)
15150049Sbostic 					--qpatnext;
15240087Sbostic 				break;
15340087Sbostic 			}
15440087Sbostic 			*bufnext++ = M_SET;
15540087Sbostic 			if (c == NOT)
15640087Sbostic 				*bufnext++ = M_NOT;
15750049Sbostic 			c = *qpatnext++;
15840087Sbostic 			do {
15940087Sbostic 				*bufnext++ = c;
16050049Sbostic 				if (*qpatnext == RANGE &&
16150049Sbostic 				    (c = qpatnext[1]) != RBRACKET) {
16240087Sbostic 					*bufnext++ = M_RNG;
16340087Sbostic 					*bufnext++ = c;
16450049Sbostic 					qpatnext += 2;
16540087Sbostic 				}
16650049Sbostic 			} while ((c = *qpatnext++) != RBRACKET);
16740087Sbostic 			*bufnext++ = M_END;
16840087Sbostic 			break;
16940087Sbostic 		case QUESTION:
17047590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
17140087Sbostic 			*bufnext++ = M_ONE;
17240087Sbostic 			break;
17340087Sbostic 		case STAR:
17447590Sbostic 			pglob->gl_flags |= GLOB_MAGCHAR;
17540087Sbostic 			*bufnext++ = M_ALL;
17640087Sbostic 			break;
17740087Sbostic 		default:
17840087Sbostic 			*bufnext++ = c;
17940087Sbostic 			break;
18040087Sbostic 		}
18140087Sbostic 	}
18240087Sbostic 	*bufnext = EOS;
18350049Sbostic #ifdef DEBUG
18450049Sbostic 	qprintf(patbuf);
18550049Sbostic #endif
18640087Sbostic 
18740087Sbostic 	if ((err = glob1(patbuf, pglob)) != 0)
18840087Sbostic 		return(err);
18940087Sbostic 
19040087Sbostic 	if (pglob->gl_pathc == oldpathc && flags & GLOB_NOCHECK) {
19148540Sbostic 		if (!(flags & GLOB_QUOTE)) {
192*50050Sbostic 			Char *dp = compilebuf;
19348540Sbostic 			const char *sp = compilepat;
19448540Sbostic 			while (*dp++ = (u_char)*sp++);
19548540Sbostic 		}
19640087Sbostic 		else {
19740087Sbostic 			/*
198*50050Sbostic 			 * Copy pattern, interpreting quotes; this is slightly
19940087Sbostic 			 * different than the interpretation of quotes above
20040087Sbostic 			 * -- which should prevail?
20140087Sbostic 			 */
20240087Sbostic 			while (*compilepat != EOS) {
20340087Sbostic 				if (*compilepat == QUOTE) {
20440087Sbostic 					if (*++compilepat == EOS)
20540087Sbostic 						--compilepat;
20640087Sbostic 				}
20748540Sbostic 				*compilebuf++ = (u_char)*compilepat++;
20840087Sbostic 			}
20940087Sbostic 			*compilebuf = EOS;
21040087Sbostic 		}
21140087Sbostic 		return(globextend(patbuf, pglob));
21248540Sbostic 	} else if (!(flags & GLOB_NOSORT))
213*50050Sbostic 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
214*50050Sbostic 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
21540087Sbostic 	return(0);
21640087Sbostic }
21740087Sbostic 
218*50050Sbostic static int
219*50050Sbostic compare(p, q)
220*50050Sbostic 	const void *p, *q;
221*50050Sbostic {
222*50050Sbostic 	return(strcmp(*(char **)p, *(char **)q));
223*50050Sbostic }
224*50050Sbostic 
22540087Sbostic static
22640087Sbostic glob1(pattern, pglob)
227*50050Sbostic 	Char *pattern;
22840087Sbostic 	glob_t *pglob;
22940087Sbostic {
230*50050Sbostic 	Char pathbuf[MAXPATHLEN+1];
23140087Sbostic 
232*50050Sbostic 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
23340087Sbostic 	if (*pattern == EOS)
23440087Sbostic 		return(0);
23540087Sbostic 	return(glob2(pathbuf, pathbuf, pattern, pglob));
23640087Sbostic }
23740087Sbostic 
23840087Sbostic /*
239*50050Sbostic  * The functions glob2 and glob3 are mutually recursive; there is one level
240*50050Sbostic  * of recursion for each segment in the pattern that contains one or more
241*50050Sbostic  * meta characters.
24240087Sbostic  */
24340087Sbostic static
24440087Sbostic glob2(pathbuf, pathend, pattern, pglob)
245*50050Sbostic 	Char *pathbuf, *pathend, *pattern;
24640087Sbostic 	glob_t *pglob;
24740087Sbostic {
248*50050Sbostic 	struct stat sb;
249*50050Sbostic 	Char *p, *q;
25048540Sbostic 	int anymeta;
25140087Sbostic 
25240087Sbostic 	/*
253*50050Sbostic 	 * Loop over pattern segments until end of pattern or until
25440087Sbostic 	 * segment with meta character found.
25540087Sbostic 	 */
25648357Sbostic 	for (anymeta = 0;;) {
257*50050Sbostic 		if (*pattern == EOS) {		/* End of pattern? */
25840087Sbostic 			*pathend = EOS;
259*50050Sbostic 			if (g_stat(pathbuf, &sb))
26048357Sbostic 				return(0);
26148540Sbostic 
26248540Sbostic 			if (((pglob->gl_flags & GLOB_MARK) &&
263*50050Sbostic 			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
264*50050Sbostic 			    || (S_ISLNK(sb.st_mode) &&
265*50050Sbostic 			    (g_stat(pathbuf, &sb) == 0) &&
266*50050Sbostic 			    S_ISDIR(sb.st_mode)))) {
26740087Sbostic 				*pathend++ = SEP;
26840087Sbostic 				*pathend = EOS;
26940087Sbostic 			}
27047590Sbostic 			++pglob->gl_matchc;
27140087Sbostic 			return(globextend(pathbuf, pglob));
27240087Sbostic 		}
27340087Sbostic 
274*50050Sbostic 		/* Find end of next segment, copy tentatively to pathend. */
27540087Sbostic 		q = pathend;
27640087Sbostic 		p = pattern;
27740087Sbostic 		while (*p != EOS && *p != SEP) {
27840087Sbostic 			if (ismeta(*p))
27940087Sbostic 				anymeta = 1;
28040087Sbostic 			*q++ = *p++;
28140087Sbostic 		}
28240087Sbostic 
283*50050Sbostic 		if (!anymeta) {		/* No expansion, do next segment. */
28440087Sbostic 			pathend = q;
28540087Sbostic 			pattern = p;
28640087Sbostic 			while (*pattern == SEP)
28740087Sbostic 				*pathend++ = *pattern++;
288*50050Sbostic 		} else			/* Need expansion, recurse. */
28940087Sbostic 			return(glob3(pathbuf, pathend, pattern, p, pglob));
29040087Sbostic 	}
29140087Sbostic 	/* NOTREACHED */
29240087Sbostic }
29340087Sbostic 
29440087Sbostic static
29540087Sbostic glob3(pathbuf, pathend, pattern, restpattern, pglob)
296*50050Sbostic 	Char *pathbuf, *pathend, *pattern, *restpattern;
29740087Sbostic 	glob_t *pglob;
29840087Sbostic {
299*50050Sbostic 	register struct dirent *dp;
30040087Sbostic 	DIR *dirp;
30140087Sbostic 	int len, err;
30240087Sbostic 
30340087Sbostic 	*pathend = EOS;
30440087Sbostic 	errno = 0;
30548540Sbostic 
306*50050Sbostic 	if (!(dirp = g_opendir(pathbuf)))
307*50050Sbostic 		/* TODO: don't call for ENOENT or ENOTDIR? */
30840087Sbostic 		if (pglob->gl_errfunc &&
30940087Sbostic 		    (*pglob->gl_errfunc)(pathbuf, errno) ||
31040087Sbostic 		    (pglob->gl_flags & GLOB_ERR))
31140087Sbostic 			return(GLOB_ABEND);
31240087Sbostic 		else
31340087Sbostic 			return(0);
31440087Sbostic 
31540087Sbostic 	err = 0;
31640087Sbostic 
317*50050Sbostic 	/* Search directory for matching names. */
31840087Sbostic 	while ((dp = readdir(dirp))) {
31948540Sbostic 		register char *sc;
320*50050Sbostic 		register Char *dc;
321*50050Sbostic 
322*50050Sbostic 		/* Initial DOT must be matched literally. */
32340087Sbostic 		if (dp->d_name[0] == DOT && *pattern != DOT)
32440087Sbostic 			continue;
32548540Sbostic 		for (sc = dp->d_name, dc = pathend;
32648540Sbostic 		     *dc++ = (u_char)*sc++;);
32748540Sbostic 		if (!match(pathend, pattern, restpattern)) {
32848540Sbostic 			*pathend = EOS;
32940087Sbostic 			continue;
33048540Sbostic 		}
33148540Sbostic 		err = glob2(pathbuf, --dc, restpattern, pglob);
33240087Sbostic 		if (err)
33340087Sbostic 			break;
33440087Sbostic 	}
335*50050Sbostic 
336*50050Sbostic 	/* TODO: check error from readdir? */
33740087Sbostic 	(void)closedir(dirp);
33840087Sbostic 	return(err);
33940087Sbostic }
34040087Sbostic 
34140087Sbostic 
34240087Sbostic /*
34340087Sbostic  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
34440087Sbostic  * add the new item, and update gl_pathc.
34540087Sbostic  *
34640087Sbostic  * This assumes the BSD realloc, which only copies the block when its size
34740087Sbostic  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
34840087Sbostic  * behavior.
34940087Sbostic  *
35040087Sbostic  * Return 0 if new item added, error code if memory couldn't be allocated.
35140087Sbostic  *
35240087Sbostic  * Invariant of the glob_t structure:
35340087Sbostic  *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
354*50050Sbostic  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
35540087Sbostic  */
35648540Sbostic static int
35740087Sbostic globextend(path, pglob)
358*50050Sbostic 	Char *path;
35940087Sbostic 	glob_t *pglob;
36040087Sbostic {
36140087Sbostic 	register char **pathv;
36240087Sbostic 	register int i;
36348540Sbostic 	u_int newsize;
36440087Sbostic 	char *copy;
365*50050Sbostic 	Char *p;
36640087Sbostic 
36740087Sbostic 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
36848540Sbostic 	pathv = (char **)realloc((char *)pglob->gl_pathv, newsize);
36940087Sbostic 	if (pathv == NULL)
37040087Sbostic 		return(GLOB_NOSPACE);
37140087Sbostic 
37240087Sbostic 	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
37340087Sbostic 		/* first time around -- clear initial gl_offs items */
37440087Sbostic 		pathv += pglob->gl_offs;
37540087Sbostic 		for (i = pglob->gl_offs; --i >= 0; )
37640087Sbostic 			*--pathv = NULL;
37740087Sbostic 	}
37840087Sbostic 	pglob->gl_pathv = pathv;
37940087Sbostic 
38048540Sbostic 	for (p = path; *p++;);
38148540Sbostic 	if ((copy = malloc(p - path)) != NULL) {
382*50050Sbostic 		g_Ctoc(path, copy);
38340087Sbostic 		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
38440087Sbostic 	}
38540087Sbostic 	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
386*50050Sbostic 	return(copy == NULL ? GLOB_NOSPACE : 0);
38740087Sbostic }
38840087Sbostic 
38940087Sbostic 
39040087Sbostic /*
39140087Sbostic  * pattern matching function for filenames.  Each occurrence of the *
39240087Sbostic  * pattern causes a recursion level.
39340087Sbostic  */
39448540Sbostic static
39540087Sbostic match(name, pat, patend)
396*50050Sbostic 	register Char *name, *pat, *patend;
39740087Sbostic {
39848540Sbostic 	int ok, negate_range;
399*50050Sbostic 	Char c, k;
40040087Sbostic 
40140087Sbostic 	while (pat < patend) {
40240087Sbostic 		c = *pat++;
40348540Sbostic 		switch (c & M_MASK) {
40440087Sbostic 		case M_ALL:
40540087Sbostic 			if (pat == patend)
40640087Sbostic 				return(1);
407*50050Sbostic 			for (; *name != EOS; ++name)
40840087Sbostic 				if (match(name, pat, patend))
40940087Sbostic 					return(1);
41040087Sbostic 			return(0);
41140087Sbostic 		case M_ONE:
41240087Sbostic 			if (*name++ == EOS)
41340087Sbostic 				return(0);
41440087Sbostic 			break;
41540087Sbostic 		case M_SET:
41640087Sbostic 			ok = 0;
41740087Sbostic 			k = *name++;
41848540Sbostic 			if (negate_range = ((*pat & M_MASK) == M_NOT))
41940087Sbostic 				++pat;
420*50050Sbostic 			while (((c = *pat++) & M_MASK) != M_END)
42148540Sbostic 				if ((*pat & M_MASK) == M_RNG) {
42240087Sbostic 					if (c <= k && k <= pat[1])
42340087Sbostic 						ok = 1;
42440087Sbostic 					pat += 2;
425*50050Sbostic 				} else if (c == k)
42640087Sbostic 					ok = 1;
42740087Sbostic 			if (ok == negate_range)
42840087Sbostic 				return(0);
42940087Sbostic 			break;
43040087Sbostic 		default:
43140087Sbostic 			if (*name++ != c)
43240087Sbostic 				return(0);
43340087Sbostic 			break;
43440087Sbostic 		}
43540087Sbostic 	}
43640087Sbostic 	return(*name == EOS);
43740087Sbostic }
43840087Sbostic 
439*50050Sbostic /* Free allocated data belonging to a glob_t structure. */
44040087Sbostic void
44140087Sbostic globfree(pglob)
44240087Sbostic 	glob_t *pglob;
44340087Sbostic {
44440087Sbostic 	register int i;
44540087Sbostic 	register char **pp;
44640087Sbostic 
44740087Sbostic 	if (pglob->gl_pathv != NULL) {
44840087Sbostic 		pp = pglob->gl_pathv + pglob->gl_offs;
44940087Sbostic 		for (i = pglob->gl_pathc; i--; ++pp)
45040087Sbostic 			if (*pp)
451*50050Sbostic 				free(*pp);
45250049Sbostic 		free(pglob->gl_pathv);
45340087Sbostic 	}
45440087Sbostic }
455*50050Sbostic 
456*50050Sbostic static DIR *
457*50050Sbostic g_opendir(str)
458*50050Sbostic 	register Char *str;
459*50050Sbostic {
460*50050Sbostic 	char buf[MAXPATHLEN];
461*50050Sbostic 
462*50050Sbostic 	if (!*str)
463*50050Sbostic 		return(opendir("."));
464*50050Sbostic 	g_Ctoc(str, buf);
465*50050Sbostic 	return(opendir(buf));
466*50050Sbostic }
467*50050Sbostic 
468*50050Sbostic static int
469*50050Sbostic g_lstat(fn, sb)
470*50050Sbostic 	register Char *fn;
471*50050Sbostic 	struct stat *sb;
472*50050Sbostic {
473*50050Sbostic 	char buf[MAXPATHLEN];
474*50050Sbostic 
475*50050Sbostic 	g_Ctoc(fn, buf);
476*50050Sbostic 	return(lstat(buf, sb));
477*50050Sbostic }
478*50050Sbostic 
479*50050Sbostic static int
480*50050Sbostic g_stat(fn, sb)
481*50050Sbostic 	register Char *fn;
482*50050Sbostic 	struct stat *sb;
483*50050Sbostic {
484*50050Sbostic 	char buf[MAXPATHLEN];
485*50050Sbostic 
486*50050Sbostic 	g_Ctoc(fn, buf);
487*50050Sbostic 	return(stat(buf, sb));
488*50050Sbostic }
489*50050Sbostic 
490*50050Sbostic static Char *
491*50050Sbostic g_strchr(str, ch)
492*50050Sbostic 	Char *str;
493*50050Sbostic 	int ch;
494*50050Sbostic {
495*50050Sbostic 	do {
496*50050Sbostic 		if (*str == ch)
497*50050Sbostic 			return (str);
498*50050Sbostic 	} while (*str++);
499*50050Sbostic 	return (NULL);
500*50050Sbostic }
501*50050Sbostic 
502*50050Sbostic static void
503*50050Sbostic g_Ctoc(str, buf)
504*50050Sbostic 	register Char *str;
505*50050Sbostic 	char *buf;
506*50050Sbostic {
507*50050Sbostic 	register char *dc;
508*50050Sbostic 
509*50050Sbostic 	for (dc = buf; *dc++ = *str++;);
510*50050Sbostic }
511*50050Sbostic 
512*50050Sbostic #ifdef DEBUG
513*50050Sbostic static void
514*50050Sbostic qprintf(s)
515*50050Sbostic 	register Char *s;
516*50050Sbostic {
517*50050Sbostic 	register Char *p;
518*50050Sbostic 
519*50050Sbostic 	for (p = s; *p; p++)
520*50050Sbostic 		(void)printf("%c", *p & 0xff);
521*50050Sbostic 	(void)printf("\n");
522*50050Sbostic 	for (p = s; *p; p++)
523*50050Sbostic 		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
524*50050Sbostic 	(void)printf("\n");
525*50050Sbostic 	for (p = s; *p; p++)
526*50050Sbostic 		(void)printf("%c", *p & M_META ? '_' : ' ');
527*50050Sbostic 	(void)printf("\n");
528*50050Sbostic }
529*50050Sbostic #endif
530