#ifdef CWRU /* CWRU specific extention(hack :-) * Examine each argument given to main, * If it is a directory, then expand it * to all its component files, recursively * till you bottom out. * If it is not a directory, then just pass it on. * * Inputs: argc, argv * Outputs: nargc, nargv (calls MAIN(nargc, nargv)) * To test: compile with -DCASE -DTEST * run with a directory as an arg * Hacker: JRB * Requirements: BSD 4.2/3 specific routines used * only tested on Vax BSD 4.3 * * Added -P name prune option at the suggestion of dietz@zhmti * Multiple -P's may be given on the command line. * -P name may be given anywhere on the command line. -P name * will prune the subdirectories named as arguement to -P. * ie: when the program is decending the file hierarchy it * will not visit the pruned branches. * NOTE that the option is -P and not -p * (-p is a valid sz option). * NOTE that the arguement given to -P can be the name * of a file or a directory. In case it is a file, * that file is skipped. * */ /* * Expand argc, so that the called MAIN(nargc,nargv) receives only * filenames, in nargv[][] * * WARNING: Contains BSD specific code, tested on BSD4.3 ONLY. * * Jwahar Bammi * usenet: {decvax,cbatt,cbosgd,sun}!cwruecmp!bammi * csnet: bammi@case * arpa: bammi%case@csnet-relay * compuServe: 71515,155 * */ #include #define OK 0 #define FALSE 0 #define Realloc realloc typedef struct _prunelist { char *name; /* name of subdirectory to prune */ struct _prunelist *next; /* ptr to next */ } PRUNELIST; static char *ProgName; static PRUNELIST *PruneList = (PRUNELIST *)NULL; /* Head of PruneList */ main(argc, argv) int argc; char **argv; { register int status; int nargc = 0; char **nargv = (char **)NULL; extern int MAIN(); extern char **CopyToNargv(); extern PRUNELIST *AddPrune(); ProgName = *argv; /* copy argv[0] blindly */ if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL) return(~OK); nargc++; while((--argc) > 0) { argv++; if(**argv == '-') { /* copy any options except -P */ if( (*argv)[1] == 'P') { if((--argc) <= 0) { fprintf(stderr,"no argument given to -P\n"); return(~OK); } if((PruneList = AddPrune(PruneList,*++argv)) == (PRUNELIST *)NULL) return(~OK); } else { if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL) return(~OK); else nargc++; } } else { /* If its not on the PruneList then */ if(!OnPruneList(PruneList, *argv)) { /* if it is a directory, push it */ if(isdir(*argv)) { if((status = PushDir(*argv)) != OK) { return(status); } } else { /* it is NOT a directory, copy to nargv */ if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL) return(~OK); else nargc++; } } } } /* while */ /* process pushed directories if any */ if((status = ProcessDirs(&nargc, &nargv)) != OK) return(status); /* else Free the Stack and call MAIN */ FreeStack(); return (MAIN(nargc, nargv)); } #include #include /* * is name a directory ? * */ int isdir(name) char *name; { struct stat st; if(stat(name, &st) != 0) return (FALSE); /* assume its not a directory */ /* NOTE: the expression below eliminates Sockets. (st.st_mode & S_IFMT)& S_IFDIR does not! */ return( ( (st.st_mode & S_IFMT) == S_IFDIR) ); } /* * Expand nargv by an element and copy a String into the new element * */ char **CopyToNargv(string, nargc, nargv) char *string; int nargc; char **nargv; { extern char *malloc(), *Realloc(), *strcpy(); extern int strlen(); /* expand nargv by 1 element */ if(nargv == (char **)NULL) /* do it with malloc for the first one */ nargv = (char **)malloc(sizeof(char **)); else /* do it with Realloc for others */ nargv = (char **)Realloc(nargv, (nargc+1)*sizeof(char **)); if(nargv == (char **)NULL) { /* failed to get memory */ perror(ProgName); return ((char **)NULL); } /* Get mem for string */ if(( nargv[nargc] = malloc(strlen(string)+1)) == (char *)NULL) { /* failed to get memory */ perror(ProgName); return ((char **)NULL); } /* copy string into nargv[nargc] */ (void)strcpy( nargv[nargc], string); return(nargv); } static char **Stack = (char **)NULL; /* directory stack */ static char StackSize = 0; /* Size of current Stack */ static int Top = -1; #define STACK_EMPTY (Top < 0) #define CHUNKSIZE 16 /* * Grow the Stack by one chunk of CHUNKSIZE elements * */ char **ExpandStack(Stack) char **Stack; { extern char *malloc(), *Realloc(); /* Grow Stack */ if(Stack == (char **)NULL) /* with malloc */ Stack = (char **)malloc(CHUNKSIZE * sizeof(char **)); else /* with Realloc */ Stack = (char **)Realloc(Stack, (StackSize+CHUNKSIZE) * sizeof(char **)); if(Stack == (char **)NULL) { /* outa mem */ perror(ProgName); return((char **)NULL); } StackSize += CHUNKSIZE; return(Stack); } /* * Free the Stack * */ FreeStack() { if(StackSize > 0) (void)free(Stack); } /* * Push a directory name on Stack * */ int PushDir(name) char *name; { register int status; extern char *malloc(), *strcpy(); extern int strlen(); extern char **ExpandStack(); ++Top; if(Top >= StackSize) { if((Stack = ExpandStack(Stack)) == (char **)NULL) return(~OK); } if((Stack[Top] = malloc(strlen(name)+1)) == (char *)NULL) { /* outa mem */ perror(ProgName); return(~OK); } (void)strcpy(Stack[Top], name); return(OK); } /* * Pop a directory name from the stack * */ char *PopDir() { register char *r; extern char **ShrinkStack(); if(STACK_EMPTY) return ((char *)NULL); r = Stack[Top]; Top--; return(r); } static int BadStatus = FALSE; #define BADSTATUS (BadStatus != FALSE) #include /* * Process directories on the Stack, by adding all the * files in a directory to nargv. */ int ProcessDirs(nargc, nargv) int *nargc; char ***nargv; { register char *name; register DIR *dirp; register struct direct *dp; register int status; char path[MAXNAMLEN+1]; extern DIR *opendir(); extern struct direct *readdir(); extern char **CopyToNargv(); extern char *PopDir(); if(BADSTATUS) return(~OK); if(STACK_EMPTY) /* Nothing more to do */ return(OK); /* Pop a directory from Stack and process */ if((name = PopDir()) == (char *)NULL) { /* Oh Oh */ fprintf(stderr,"Internal Error (BUG), PopDir returns NULL\n"); BadStatus = (~FALSE); return(~OK); } /* Open the directory */ if((dirp = opendir(name)) == (DIR *)NULL) { /* trouble opening directory */ perror(name); /* set BADSTATUS and return */ BadStatus = (~FALSE); return(~OK); } /* for each entry in the directory, if it is a file add to nargv. If it is a directory, Push it onto the directory stack. */ for (dp = readdir(dirp); dp != (struct direct *)NULL; dp = readdir(dirp)) { if( (!((strcmp(dp->d_name,".") == 0) || (strcmp(dp->d_name,"..") == 0))) && (dp->d_ino != 0 )) /* not a free entry */ { strcpy(path, name); strcat(path,"/"); strcat(path,dp->d_name); /* If this path is on the PruneList skip */ if(OnPruneList(PruneList, path)) continue; if(!isdir(path)) { /* not a dir -- add this to nargv */ if((*nargv = CopyToNargv(path, *nargc, *nargv)) == (char **)NULL) { closedir(dirp); BadStatus = (~FALSE); return(~OK); } else { *nargc += 1; } } else { /* Note: At this point we could have simply recursed on ProcessDirs() totally eliminating the directory Stack. This was not done as it is possible to run out of dirp's on deep file hierarchies. Yet another (ir)rational design decision. */ /* Push This directory */ if((status = PushDir(path)) != OK) { closedir(dirp); BadStatus = (~FALSE); return(status); } } } } /* for */ closedir(dirp); free(name); /* done with this directory */ /* go do the rest */ return (ProcessDirs(nargc, nargv)); } /* * Add a name to PruneList * */ PRUNELIST *AddPrune(list, name) PRUNELIST *list; char *name; { extern char *malloc(); register PRUNELIST *new; if((new = (PRUNELIST *)malloc(sizeof(PRUNELIST))) == (PRUNELIST *)NULL) { /* outa mem */ perror(ProgName); return(new); } new->name = name; new->next = list; return(new); } /* * Search for name on PruneList * */ int OnPruneList(list, name) register PRUNELIST *list; register char *name; { for(; list != (PRUNELIST *)NULL; list = list->next) { if(strcmp(list->name, name) == 0) return(~FALSE); } return(FALSE); } #ifdef TEST /* to test: cc -o name name.c -DTEST -DCASE; name ~ */ int MAIN(argc, argv) int argc; char **argv; { register int i; for(i = 0; i < argc; i++) printf("%d:\t%s\n", i, argv[i]); return(0); } #endif /* TEST */ #endif /* CWRU */