freebsd-dev/contrib/global/lib/find.c

446 lines
9.7 KiB
C

/*
* Copyright (c) 1996, 1997, 1998 Shigio Yamaguchi. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Shigio Yamaguchi.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* find.c 1-May-98
*
*/
/*
* USEFIND use find(1) to traverse directory tree.
* Otherwise, use dirent(3) library.
*/
#define USEFIND
#include <sys/param.h>
#include <assert.h>
#include <ctype.h>
#ifndef USEFIND
#include <dirent.h>
#ifndef BSD4_4
#include <sys/stat.h>
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <regex.h>
#include "conf.h"
#include "die.h"
#include "find.h"
#include "gparam.h"
#include "locatestring.h"
#include "makepath.h"
#include "strbuf.h"
/*
* usage of findxxx()
*
* findopen(db);
* while (path = findread(&length)) {
* ...
* }
* findclose();
*
*/
static regex_t skip_area;
static regex_t *skip = &skip_area;
static int opened;
static void trim __P((char *));
/*
* trim: remove blanks and '\'.
*/
static void
trim(s)
char *s;
{
char *p;
for (p = s; *s; s++) {
if (isspace(*s))
continue;
if (*s == '\\' && *(s + 1))
s++;
*p++ = *s;
}
*p = 0;
}
#ifdef USEFIND
/*----------------------------------------------------------------------*/
/* find command version */
/*----------------------------------------------------------------------*/
static FILE *ip;
void
findopen()
{
char *findcom, *p, *q;
STRBUF *sb;
char *sufflist = NULL;
char *skiplist = NULL;
assert(opened == 0);
opened = 1;
sb = stropen();
if (!getconfs("suffixes", sb))
die("cannot get suffixes data.");
sufflist = strdup(strvalue(sb));
if (!sufflist)
die("short of memory.");
trim(sufflist);
strstart(sb);
if (getconfs("skip", sb)) {
skiplist = strdup(strvalue(sb));
if (!skiplist)
die("short of memory.");
trim(skiplist);
}
strstart(sb);
strputs(sb, "find . \\( -type f -o -type l \\) \\(");
for (p = sufflist; p; ) {
char *suff = p;
if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
*p++ = 0;
strputs(sb, " -name '*.");
strputs(sb, suff);
strputs(sb, "'");
if (p)
strputs(sb, " -o");
}
strputs(sb, " \\) -print");
findcom = strvalue(sb);
if (skiplist) {
char *reg;
STRBUF *sbb = stropen();
/*
* construct regular expression.
*/
strputc(sbb, '('); /* ) */
for (p = skiplist; p; ) {
char *skipf = p;
if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
*p++ = 0;
strputc(sbb, '/');
for (q = skipf; *q; q++) {
if (*q == '.')
strputc(sbb, '\\');
strputc(sbb, *q);
}
if (*(q - 1) != '/')
strputc(sbb, '$');
if (p)
strputc(sbb, '|');
}
strputc(sbb, ')');
reg = strvalue(sbb);
/*
* compile regular expression.
*/
if (regcomp(skip, reg, REG_EXTENDED|REG_NEWLINE) != 0)
die("cannot compile regular expression.");
strclose(sbb);
} else {
skip = (regex_t *)0;
}
if (!(ip = popen(findcom, "r")))
die("cannot execute find.");
strclose(sb);
if (sufflist)
free(sufflist);
if (skiplist)
free(skiplist);
}
char *
findread(length)
int *length;
{
static char path[MAXPATHLEN+1];
char *p;
assert(opened == 1);
while (fgets(path, MAXPATHLEN, ip)) {
if (!skip || regexec(skip, path, 0, 0, 0) != 0) {
/*
* chop(path)
*/
p = path + strlen(path) - 1;
if (*p != '\n')
die("output of find(1) is wrong (findread).");
*p = 0;
if (length)
*length = p - path;
return path;
}
}
return NULL;
}
void
findclose(void)
{
assert(opened == 1);
pclose(ip);
opened = 0;
}
#else /* USEFIND */
/*----------------------------------------------------------------------*/
/* dirent version findxxx() */
/*----------------------------------------------------------------------*/
#define STACKSIZE 50
static char dir[MAXPATHLEN+1]; /* directory path */
static struct {
STRBUF *sb;
char *dirp, *start, *end, *p;
} stack[STACKSIZE], *topp, *curp; /* stack */
static regex_t suff_area;
static regex_t *suff = &suff_area;
static int
getdirs(dir, sb)
char *dir;
STRBUF *sb;
{
DIR *dirp;
struct dirent *dp;
#ifndef BSD4_4
struct stat st;
#endif
if ((dirp = opendir(dir)) == NULL)
return -1;
while ((dp = readdir(dirp)) != NULL) {
#ifdef BSD4_4
if (dp->d_namlen == 1 && dp->d_name[0] == '.')
continue;
if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
continue;
if (dp->d_type == DT_DIR)
strputc(sb, 'd');
else if (dp->d_type == DT_REG)
strputc(sb, 'f');
else if (dp->d_type == DT_LNK)
strputc(sb, 'l');
else
strputc(sb, ' ');
strnputs(sb, dp->d_name, (int)dp->d_namlen);
#else
if (stat(path, &st) < 0) {
fprintf(stderr, "cannot stat '%s'. (Ignored)\n", path);
continue;
}
if (S_ISDIR(st.st_mode))
strputc(sb, 'd');
else if (S_ISREG(st.st_mode))
strputc(sb, 'f');
else if (S_ISLNK(st.st_mode))
strputc(sb, 'l');
else
strputc(sb, ' ');
strputs(sb, dp->d_name);
#endif /* BSD4_4 */
strputc(sb, '\0');
}
(void)closedir(dirp);
return 0;
}
void
findopen()
{
STRBUF *sb = stropen();
char *sufflist = NULL;
char *skiplist = NULL;
assert(opened == 0);
opened = 1;
/*
* setup stack.
*/
curp = &stack[0];
topp = curp + STACKSIZE;
strcpy(dir, ".");
curp->dirp = dir + strlen(dir);
curp->sb = stropen();
if (getdirs(dir, curp->sb) < 0)
die("cannot open '.' directory.");
curp->start = curp->p = strvalue(curp->sb);
curp->end = curp->start + strbuflen(curp->sb);
/*
* preparing regular expression.
*/
strstart(sb);
if (!getconfs("suffixes", sb))
die("cannot get suffixes data.");
sufflist = strdup(strvalue(sb));
if (!sufflist)
die("short of memory.");
trim(sufflist);
strstart(sb);
if (getconfs("skip", sb)) {
skiplist = strdup(strvalue(sb));
if (!skiplist)
die("short of memory.");
trim(skiplist);
}
{
char *p;
strstart(sb);
strputc(sb, '('); /* ) */
for (p = sufflist; p; ) {
char *suffp = p;
if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
*p++ = 0;
strputs(sb, "\\.");
strputs(sb, suffp);
strputc(sb, '$');
if (p)
strputc(sb, '|');
}
strputc(sb, ')');
/*
* compile regular expression.
*/
if (regcomp(suff, strvalue(sb), REG_EXTENDED) != 0)
die("cannot compile regular expression.");
}
if (skiplist) {
char *p, *q;
/*
* construct regular expression.
*/
strstart(sb);
strputc(sb, '('); /* ) */
for (p = skiplist; p; ) {
char *skipf = p;
if ((p = locatestring(p, ",", MATCH_FIRST)) != NULL)
*p++ = 0;
strputc(sb, '/');
for (q = skipf; *q; q++) {
if (*q == '.')
strputc(sb, '\\');
strputc(sb, *q);
}
if (*(q - 1) != '/')
strputc(sb, '$');
if (p)
strputc(sb, '|');
}
strputc(sb, ')');
/*
* compile regular expression.
*/
if (regcomp(skip, strvalue(sb), REG_EXTENDED) != 0)
die("cannot compile regular expression.");
} else {
skip = (regex_t *)0;
}
strclose(sb);
if (sufflist)
free(sufflist);
if (skiplist)
free(skiplist);
}
char *
findread(length)
int *length;
{
static char val[MAXPATHLEN+1];
for (;;) {
while (curp->p < curp->end) {
char type = *(curp->p);
char *unit = curp->p + 1;
curp->p += strlen(curp->p) + 1;
if (type == 'f' || type == 'l') {
char *path = makepath(dir, unit);
if (regexec(suff, path, 0, 0, 0) != 0)
continue;
if (skip && regexec(skip, path, 0, 0, 0) == 0)
continue;
strcpy(val, path);
return val;
}
if (type == 'd') {
STRBUF *sb = stropen();
char *dirp = curp->dirp;
strcat(dirp, "/");
strcat(dirp, unit);
if (getdirs(dir, sb) < 0) {
fprintf(stderr, "cannot open directory '%s'. (Ignored)\n", dir);
strclose(sb);
*(curp->dirp) = 0;
continue;
}
/*
* Push stack.
*/
if (++curp >= topp)
die("directory stack over flow.");
curp->dirp = dirp + strlen(dirp);
curp->sb = sb;
curp->start = curp->p = strvalue(sb);
curp->end = curp->start + strbuflen(sb);
}
}
strclose(curp->sb);
curp->sb = NULL;
if (curp == &stack[0])
break;
/*
* Pop stack.
*/
curp--;
*(curp->dirp) = 0;
}
return NULL;
}
void
findclose(void)
{
assert(opened == 1);
for (curp = &stack[0]; curp < topp; curp++)
if (curp->sb != NULL)
strclose(curp->sb);
else
break;
opened = 0;
}
#endif /* !USEFIND */