/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*
* these routines support two kinds of globs. first, the
* usual kind of filename globbing, like:
*
* *.c
* log[0-9]*file
*
* this is basically the same syntax that csh supports for globs and
* is provided by the routine glob_glob() which takes a filename and
* returns a list of filenames that match the glob.
*
* the second type is something called a "reglob" which is a pathname
* where the components are regular expressions as described in regex(3c).
* some examples:
*
* .*\.c
* log[0-9].*file
*
* the last example uses the ()$n form to assign a numeric extension
* on a filename to the "n" value kept by the fn routines with each
* filename (see fn_setn() in fn.c). logadm uses this mechanism to
* correctly sort lognames when templates containing $n are used.
*
* the routine glob_reglob() is used to expand reglobs. glob_glob()
* is implemented by expanding the curly braces, converting the globs
* to reglobs, and then passing the work to glob_reglob().
*
* finally, since expanding globs and reglobs requires doing a stat(2)
* on the files, we store the resulting stat information in the filename
* struct (see fn_setstat() in fn.c).
*
* the glob(3c) routines are not used here since they don't support
* braces, and don't support the more powerful reglobs required by logadm.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <libintl.h>
#include <stdlib.h>
#include <libgen.h>
#include <strings.h>
#include <dirent.h>
#include "err.h"
#include "fn.h"
#include "glob.h"
/* forward declarations for functions used internally by this module */
/* expand curly braces (like file{one,two,three}name) */
static struct fn_list *
{
char *left;
char *right;
char *comma;
/* start with an empty string in the list */
/* while braces remain... */
return (NULL);
} else {
/* stuff before "left" is finished */
/* stuff after "right" still need processing */
continue; /* just an empty {} */
/* stuff between "left" and "right" is comma-sep list */
left++;
/* stuff from left to comma is one variant */
}
/* what's left is the last item in the list */
}
/* anything remaining in "s" is finished */
return (ret);
}
/* return true if filename contains any "magic" characters (*,?,[) */
static boolean_t
{
for (; s != NULL && *s; s++)
if (*s == '*' ||
*s == '?' ||
*s == '[')
return (B_TRUE);
return (B_FALSE);
}
/*
* glob_glob -- given a filename glob, return the list of matching filenames
*
* fn_setn() and fn_setstat() are called to set the "n" and stat information
* for the resulting filenames.
*/
struct fn_list *
{
int magic = 0;
/* debracing produced NULL list? */
return (NULL);
/* see if anything in list contains magic characters */
if (glob_magic(nextfnp)) {
magic = 1;
break;
}
if (!magic)
return (tmplist); /* no globs to expand */
/* foreach name in the list, call glob_glob() to expand it */
}
return (ret);
}
/*
* glob_glob_list -- given a list of filename globs, return all matches
*/
struct fn_list *
{
return (ret);
}
/*
* glob_reglob -- given a filename reglob, return a list of matching filenames
*
* this routine does all the hard work in this module.
*/
struct fn_list *
{
char *slash;
int skipdotfiles;
char *re;
/* start with the initial directory in the list */
if (*sp == '/') {
while (*sp == '/')
sp++;
} else
/* while components remain... */
do {
*slash++ = '\0';
/* skip superfluous slashes */
while (*slash == '/')
slash++;
}
/* dot files are skipped unless a dot was specifically given */
skipdotfiles = 0;
else
skipdotfiles = 1;
/* compile the regex */
/* apply regex to every filename we've matched so far */
/* go through directory looking for matches */
continue;
continue;
*ret0 = '\0';
int n;
continue;
}
/* skip non-dirs if more components */
if (slash &&
S_IFDIR) {
continue;
}
/*
* component matched, fill in "n"
* value, stat information, and
* append component to directory
* name just searched.
*/
if (*ret0)
else
n = -1;
if (slash)
}
}
}
} while (slash);
return (ret);
}
/* reglob a list of filenames */
static struct fn_list *
{
return (ret);
}
/*
* glob_to_reglob -- convert a glob (*, ?, etc) to a reglob (.*, ., etc.)
*/
struct fn *
{
int c;
switch (c) {
case '.':
case '(':
case ')':
case '^':
case '+':
case '{':
case '}':
case '$':
/* magic characters need backslash */
break;
case '?':
/* change '?' to a single dot */
break;
case '*':
/* change '*' to ".*" */
break;
default:
}
return (ret);
}
#ifdef TESTMODULE
/*
* test main for glob module, usage: a.out [-r] [pattern...]
* -r means the patterns are reglobs instead of globs
*/
int
{
int i;
int reglobs = 0;
for (i = 1; i < argc; i++) {
reglobs = 1;
continue;
}
if (SETJMP) {
printf(" skipped due to errors\n");
continue;
} else {
if (reglobs)
else
}
}
}
err_done(0);
/* NOTREACHED */
return (0);
}
#endif /* TESTMODULE */