home *** CD-ROM | disk | FTP | other *** search
- /* 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;
- }
-