home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
0
/
0988
/
tclGlob.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-28
|
12KB
|
436 lines
/* TclGlob.c -
*
* This file contains routines to glob filenames. It calls
* glob routines from GNU.
*
*/
#ifndef lint
static char rcsid[] = "$Header: /sprite/src/lib/tcl/RCS/tclGlob.c,v 1.2 89/06/12 17:00:39 shirriff Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <string.h>
#include <list.h>
#include <pwd.h>
#include <tcl.h>
/*
* Library imports.
*/
extern int errno;
extern char *sys_errlist[];
extern char *ckalloc(), *sprintf(), *getlogin();
extern char **glob_filename();
/*
* Structure to hold a list of strings.
*/
typedef struct {
List_Links links;
char *str;
} stringList;
/*
* Free the linked list. This macro requires stringElt to be defined.
*/
#define FREE(list) \
while (!List_IsEmpty((list))) { \
stringElt=(stringList *)List_First((list)); \
List_Remove((List_Links *)stringElt); \
if (stringElt->str != NULL) { \
ckfree(stringElt->str); \
} \
ckfree((char *)stringElt); \
} \
ckfree((char *)(list))
/*
* ----------------------------------------------------------------------------
*
* BraceExpand --
*
* Expands a filename containing {} braces.
* If inBrace==0, this routine matches expression E, where
* E = string
* or E = [E]{E,...,E}[E]
* otherwise this routine matches a similar expression E1, where
* E1 = string (stopping at comma or closing brace)
* or E1 = [E1]{E,...,E}[E1]
* That is, commas and closing braces will stop the parsing.
*
* Results:
*
* The position of the next character in the input is returned.
* This position will point to '\0', or possibly ',' if inBrace is true.
* The resulting list of strings is returned in strList.
* In case of an error, NULL will be returned and the error
* message will be returned in the list of strings.
*
* Side effects:
* Allocates memory for the list of strings.
*
* ----------------------------------------------------------------------------
*/
static char*
BraceExpand(str,inBrace,strList)
char *str; /* String to expand. */
int inBrace; /* True if inside a brace. */
List_Links **strList; /* List of strings. */
{
List_Links *headerPtr; /* Header of string list. */
stringList *stringElt; /* Element of string list. */
List_Links *leftHdr; /* Left part of expanded name. */
List_Links *rightHdr; /* Right part of expanded name. */
char *strPtr; /* Pointer into the string. */
char *next; /* Next position in string. */
int len; /* String length. */
List_Links *leftPtr; /* Pointer to left string element. */
char *left; /* Left string. */
int leftLen; /* Length of left string. */
List_Links *rightPtr; /* Pointer to right string element. */
char *right; /* Right string. */
headerPtr = (List_Links *)ckalloc(sizeof(List_Links));
List_Init(headerPtr);
if (inBrace) {
strPtr = strpbrk(str,"{,}");
} else {
strPtr = strchr(str,'{');
}
if (strPtr==NULL || *strPtr=='}' || *strPtr==',') {
/*
* Return a single element.
*/
if (strPtr==NULL) {
len = strlen(str);
strPtr = str+len;
}
else {
len = strPtr-str;
}
stringElt = (stringList *)ckalloc(sizeof(stringList));
List_InitElement((List_Links *)stringElt);
stringElt->str = (char *)ckalloc((unsigned)len+1);
(void) strncpy(stringElt->str,str,len);
stringElt->str[len] = '\0';
List_Insert((List_Links *)stringElt,
LIST_ATFRONT(headerPtr));
*strList = headerPtr;
return strPtr;
}
len = strPtr-str;
leftHdr = (List_Links *)ckalloc(sizeof(List_Links));
List_Init(leftHdr);
/*
* The idea is to grab a unit (string or thing in braces) from
* the left, and put this in leftHdr. Then recursively expand
* the remainder, and put this in rightHdr. Finally merge the
* two lists
*/
if (*str=='{') {
next = strPtr;
while (1) {
/*
* Expand the part in the braces.
*/
next = BraceExpand(++next,1,&rightHdr);
if (next==NULL) {
/*
* Error in BraceExpand.
*/
*strList = rightHdr;
return NULL;
} else if (*next=='\0') {
/*
* Unexpected end of string.
*/
FREE(leftHdr);
FREE(rightHdr);
stringElt = (stringList *)ckalloc(sizeof(stringList));
List_InitElement((List_Links *)stringElt);
stringElt->str = "Missing }.";
List_Insert((List_Links *)stringElt,
LIST_ATREAR(headerPtr));
*strList = headerPtr;
return NULL;
}
else {
/*
* Add the new list obtained from BraceExpand to the list.
*/
List_ListInsert(rightHdr, LIST_ATREAR(leftHdr));
ckfree((char *)rightHdr);
if (*next=='}') {
strPtr = next+1;
break;
}
}
}
} else {
/*
* leftHdr is the part before the braces.
*/
stringElt = (stringList *)ckalloc(sizeof(stringList));
List_InitElement((List_Links *)stringElt);
stringElt->str = (char *)ckalloc((unsigned)len+1);
(void) strncpy(stringElt->str,str,len);
stringElt->str[len] = '\0';
List_Insert((List_Links *)stringElt,
LIST_ATFRONT(leftHdr));
}
/*
* Now expand the rest of the pattern and put this in rightHdr.
*/
if (*strPtr=='\0' || (*strPtr==',' && inBrace)) {
/*
* We can leave early.
*/
*strList = leftHdr;
ckfree((char *)headerPtr);
return strPtr;
}
next = BraceExpand(strPtr,inBrace,&rightHdr);
if (next==NULL) {
ckfree((char *)leftHdr);
ckfree((char *)headerPtr);
*strList = rightHdr;
return NULL;
}
/*
* Merge the left and right lists of strings.
*/
LIST_FORALL(leftHdr,leftPtr) {
left = ((stringList *)leftPtr)->str;
leftLen = strlen(left);
LIST_FORALL(rightHdr,rightPtr) {
right = ((stringList *)rightPtr)->str;
stringElt = (stringList *)ckalloc(sizeof(stringList));
List_InitElement((List_Links *)stringElt);
stringElt->str = (char *)ckalloc((unsigned)strlen(left)+
strlen(right)+1);
(void)strcpy(stringElt->str,left);
(void)strcpy(stringElt->str+leftLen,right);
List_Insert((List_Links *)stringElt,
LIST_ATREAR(headerPtr));
}
}
FREE(leftHdr);
FREE(rightHdr);
*strList = headerPtr;
return next;
}
#define VALID "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\
0123456789-"
/*
* ----------------------------------------------------------------------------
*
* Tilde --
*
* Expands a string starting with a tilde.
* It is assumed that the pattern starts with a tilde.
* It is also assumed that we may temporarily modify pattern.
*
* Results:
*
* If successful, TCL_OK is returned, and result points to the string
* containing the expanded filenames.
* Otherwise, TCL_ERROR is returned, and interp contains the error.
*
* Side effects:
* Allocates the result string if successful.
*
* ----------------------------------------------------------------------------
*/
static int
Tilde(pattern,interp,result)
char *pattern; /* Pattern to expand. */
Tcl_Interp *interp; /* Current interpreter. */
char **result; /* Result of expansion. */
{
int len; /* Length of tilde name. */
struct passwd *pwPtr; /* Password file entry. */
char *strPtr; /* String pointer. */
int ret;
pattern++;
len = strspn(pattern,VALID);
if (len==0) {
/*
* Get home directory.
*/
strPtr = (char *)getlogin();
if (strPtr==NULL) {
interp->result = "no home directory";
return TCL_ERROR;
}
}
else {
strPtr = (char *)ckalloc((unsigned)len+1);
strncpy(strPtr,pattern,len);
strPtr[len] = '\0';
}
pwPtr = getpwnam(strPtr);
if (pwPtr==NULL) {
sprintf(interp->result,"Unknown user: %s.",strPtr);
ret = TCL_ERROR;
}
else {
*result = (char *)ckalloc((unsigned)strlen(pattern+len)+
strlen(pwPtr->pw_dir)+1);
(void) strcpy(*result,pwPtr->pw_dir);
(void) strcpy(*result+strlen(pwPtr->pw_dir),pattern+len);
ret = TCL_OK;
}
if (len>0) {
ckfree(strPtr);
}
return ret;
}
/*
* ----------------------------------------------------------------------------
*
* Tcl_Glob --
*
* Expands a pattern in a directory using csh rules.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
* ----------------------------------------------------------------------------
*/
int
Tcl_Glob(interp, argc, argv)
Tcl_Interp *interp; /* Current interpreter. */
int argc;
char *argv[];
{
List_Links *stringHdr; /* Element of string list. */
stringList *stringElt; /* Element of string list. */
List_Links *resultList; /* Results of expansion. */
List_Links *linkPtr; /* Pointer to linked list element. */
int length = 0; /* Length of result. */
char *strPtr; /* String pointer. */
char *str2Ptr; /* String pointer. */
char **fileList; /* List of globbed filenames */
char **fileList1; /* List of globbed filenames */
int i;
resultList = (List_Links *) ckalloc(sizeof(List_Links));
List_Init(resultList);
for (i=1;i<argc;i++) {
/*
* Expand the braces in each argument and add to resultList.
*/
if (!strcmp(argv[i],"{") || !strcmp(argv[i],"{}")) {
/*
* Patterns "{" and "{}" are special cases.
*/
stringElt = (stringList *)ckalloc(sizeof(stringList));
List_InitElement((List_Links *)stringElt);
stringElt->str = (char *)ckalloc((unsigned)strlen(argv[i])+1);
(void)strcpy(stringElt->str,argv[i]);
List_Insert((List_Links *)stringElt,
LIST_ATREAR(resultList));
} else if (BraceExpand(argv[i],0,&stringHdr)==NULL) {
strcpy(interp->result,
((stringList *)List_First(stringHdr))->str);
FREE(resultList);
FREE(stringHdr);
return TCL_ERROR;
} else {
List_ListInsert(stringHdr,LIST_ATREAR(resultList));
ckfree((char *)stringHdr);
}
}
stringHdr = (List_Links *)ckalloc(sizeof(List_Links));
List_Init(stringHdr);
LIST_FORALL(resultList,linkPtr) {
strPtr = ((stringList *)linkPtr)->str;
if (*strPtr == '~') {
/*
* Expand tildes.
*/
if (Tilde(strPtr,interp,&str2Ptr) != TCL_OK) {
FREE(resultList);
FREE(stringHdr);
return TCL_ERROR;
} else {
ckfree(strPtr);
((stringList *)linkPtr)->str = str2Ptr;
strPtr = str2Ptr;
}
}
if (glob_pattern_p(strPtr)) {
fileList = (char **)glob_filename(strPtr);
if ((int)fileList==-1) {
strcpy(interp->result,sys_errlist[errno]);
FREE(resultList);
FREE(stringHdr);
return TCL_ERROR;
} else {
for (fileList1=fileList; *fileList1!='\0'; fileList1++) {
length += strlen(*fileList1)+1;
stringElt = (stringList *)ckalloc(sizeof(stringList));
List_InitElement((List_Links *)stringElt);
stringElt->str =
(char *)ckalloc((unsigned)strlen(*fileList1)+1);
strcpy(stringElt->str,*fileList1);
List_Insert((List_Links *)stringElt,
LIST_ATREAR(stringHdr));
ckfree(*fileList1);
}
ckfree((char *)fileList);
}
} else {
length += strlen(strPtr)+1;
stringElt = (stringList *)ckalloc(sizeof(stringList));
List_InitElement((List_Links *)stringElt);
stringElt->str = strPtr;
((stringList *)linkPtr)->str = NULL;
List_Insert((List_Links *)stringElt,LIST_ATREAR(stringHdr));
}
}
FREE(resultList);
if (List_IsEmpty(stringHdr)) {
FREE(stringHdr);
sprintf(interp->result,"%.50s couldn't find file that matches pattern",
argv[0]);
return TCL_ERROR;
}
strPtr = (char *)ckalloc((unsigned) length);
interp->result = strPtr;
interp->dynamic = 1;
LIST_FORALL(stringHdr,linkPtr) {
strcpy(strPtr,((stringList *)linkPtr)->str);
strPtr += strlen(strPtr)+1;
strPtr[-1] = ' ';
}
strPtr[-1] = '\0';
FREE(stringHdr);
return TCL_OK;
}