home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <sys/file.h>
- #include <sys/types.h>
- #include <sys/dir.h>
-
- #define MAXWILD 20
- #define MAXREP 40
-
- typedef struct rep{
- int ftorep;
- char *repname;
- struct rep *dofirst;
- int mustdel;
- int status;
- struct rep *nextrep;
- } REP;
-
- #define DO 0
- #define FORGET 1
- #define DONE 2
-
- #define ASKDEL 0
- #define QUIETDEL 1
- #define NODEL 2
- #define ABORTDEL 3
-
- extern int alphasort();
- extern int scandir();
- extern qsort();
-
- static procargs();
- static int procdir();
- static int checkpats();
- static int getreps();
- static int scan();
- static char *makerep();
- static checkcollisons();
- static int mycmp();
- static checkdeletes();
- static int bsearch();
- static char** breakcycles();
- static dorenames();
-
- static char tempprefix[] = "renTMP";
-
- main(argc, argv)
- int argc;
- char *(argv[]);
- {
- char *from_pat, *to_pat, *path;
- int verbose, delstyle;
- int nfils, nreps;
- struct direct **dot;
- REP *reps, **filrep;
- char **tempnames;
-
- procargs(argc, argv, &verbose, &delstyle, &from_pat, &to_pat, &path);
- checkpats(from_pat, to_pat);
- nfils = procdir(path, &dot, &filrep);
- nreps = getreps(dot, nfils, from_pat, to_pat, filrep, &reps);
- checkcollisons(reps, nreps);
- checkdeletes(reps, dot, filrep, nfils, delstyle);
- tempnames = breakcycles(reps, nreps, dot);
- dorenames(reps, dot, tempnames, verbose);
- return(0);
- }
-
-
- static procargs(argc, argv, pverbose, pdelstyle, pfrom_pat, pto_pat, ppath)
- int argc;
- char *(argv[]);
- int *pverbose, *pdelstyle;
- char **pfrom_pat, **pto_pat, **ppath;
- {
- char *p;
- int arg1;
-
- *pverbose = 0;
- *pdelstyle = ASKDEL;
- for (arg1 = 1; arg1 < argc && *(argv[arg1]) == '-'; arg1++)
- for (p = argv[arg1]+1; *p != '\0'; p++)
- if (*p == 'v')
- *pverbose = 1;
- else if (*p == 'd')
- *pdelstyle = QUIETDEL;
- else if (*p == 'k')
- *pdelstyle = NODEL;
- else if (*p == 'a')
- *pdelstyle = ABORTDEL;
- else {
- fputs("Illegal option -", stderr);
- fputc(*p, stderr);
- fputc('\n', stderr);
- exit(1);
- }
-
- if (argc - arg1 != 2) {
- fputs(
- "Usage: ren [-d|-k|-a] [-v] [path/]search_pattern replacement_pattern\n",
- stderr);
- fputs("\nSearch patterns containing wildcard(s) should be quoted.\n",
- stderr);
- fputs("Put #n into the replacement pattern to insert the string\n",
- stderr);
- fputs("matched by the n'th wildcard in the search pattern.\n", stderr);
- exit(1);
- }
-
- *ppath = argv[arg1];
- *pto_pat = argv[arg1 + 1];
- for (
- *pfrom_pat = *ppath + strlen(*ppath);
- **pfrom_pat != '/' && *pfrom_pat != *ppath;
- --(*pfrom_pat)
- ) {}
- if (**pfrom_pat == '/') {
- **pfrom_pat = '\0';
- if (*pfrom_pat == *ppath)
- *ppath = "/";
- (*pfrom_pat)++;
- }
- else
- *ppath = ".";
- }
-
-
- static checkpats(from_pat, to_pat)
- char *from_pat, *to_pat;
- {
- char *p;
- int nwilds;
-
- for (nwilds = 0, p = from_pat; *p != '\0'; p++) {
- if (*p == '\\') {
- p++;
- if (*p == '\0')
- break;
- }
- else if (*p == '*' || *p == '?')
- nwilds++;
- }
-
- for (p = to_pat; *p != '\0'; p++) {
- if (*p == '/') {
- fputs("The replacement pattern must not contain a path.\n",
- stderr);
- exit(1);
- }
- else if (*p == '*' || *p == '?') {
- fputs("No wildcards allowed in replacement pattern.\n", stderr);
- fputs("Use #n to insert the substring matched\n", stderr);
- fputs("by the n'th wildcard in the search pattern.\n", stderr);
- exit(1);
- }
- else if (*p == '#') {
- if (*(p+1) < '1' || *(p+1) > '9' || *(p+1) - '0' > nwilds) {
- fputc('#', stderr);
- fputc(*(p+1), stderr);
- fputs(": bad substring numer.\n", stderr);
- fputs("(Use '\\#' to get '#' in replacement string.)\n", stderr);
- exit(1);
- }
- p++;
- }
- else if (*p == '\\') {
- p++;
- if (*p == '\0')
- break;
- }
- }
- }
-
-
- static int procdir(path, pdot, pfilrep)
- char *path;
- struct direct ***pdot;
- REP ***pfilrep;
- {
- int nfils;
-
- if (access(path, R_OK | X_OK | W_OK) < 0) {
- fputs("Read/write access denied to ", stderr);
- fputs(path, stderr);
- fputc('\n', stderr);
- exit(1);
- }
- if (chdir(path) < 0) {
- fputs("Strange, can not change directory to ", stderr);
- fputs(path, stderr);
- fputc('\n', stderr);
- exit(1);
- }
- if ((nfils = scandir(".", pdot, NULL, alphasort)) < 0) {
- fputs("Strange, can not scan ", stderr);
- fputs(path, stderr);
- fputc('\n');
- exit(1);
- }
- *pfilrep = (REP **)malloc(nfils * sizeof(REP *));
- return(nfils);
- }
-
-
-
- static int getreps(dot, nfils, from_pat, to_pat, filrep, preps)
- struct direct *(dot[]);
- int nfils;
- char *from_pat, *to_pat;
- REP *(filrep[]);
- REP **preps;
- {
- char *(start[MAXWILD]);
- int len[MAXWILD];
- int nreps, i;
- REP *cur;
-
- for (*preps = NULL, nreps = 0, i = 0; i < nfils; i++) {
- if (
- (*(dot[i]->d_name) != '.' || *from_pat == '.') &&
- strcmp(dot[i]->d_name, ".") != 0 &&
- strcmp(dot[i]->d_name, "..") != 0 &&
- scan(from_pat, dot[i]->d_name, start, len)
- ) {
- cur = (REP *)malloc(sizeof(REP));
- filrep[i] = cur;
- cur->repname = makerep(to_pat, start, len);
- cur->ftorep = i;
- cur->mustdel = -1;
- cur->nextrep = *preps;
- cur->status = DO;
- *preps = cur;
- nreps++;
- if (*(cur->repname) == '\0') {
- fputc('\'', stderr);
- fputs(dot[i]->d_name, stderr);
- fputs("' would have to be renamed to empty string.\n",
- stderr);
- fputs("Aborting, no renames done.\n");
- exit(1);
- }
- }
- else
- filrep[i] = NULL;
- }
- if (nreps == 0) {
- fputs("No match.\n", stderr);
- exit(1);
- }
- return(nreps);
- }
-
-
- static int scan(pat, s, start1, len1)
- char *pat, *s, **start1;
- int *len1;
- {
- *start1 = 0;
- while (1) {
- if (*pat == '*') {
- pat++;
- *start1 = s;
- if (*pat == '\0') {
- *len1 = strlen(s);
- return(1);
- }
- else {
- for (*len1=0; !scan(pat, s, start1+1, len1+1); (*len1)++, s++)
- if (*s == '\0')
- return(0);
- return(1);
- }
- }
- else if (*pat == '\0')
- return(*s == '\0');
- else if (*pat == '?') {
- if (*s == '\0')
- return(0);
- *(start1++) = s;
- *(len1++) = 1;
- pat++;
- s++;
- }
- else {
- if (*pat == '\\') {
- pat++;
- if (*pat == '\0')
- return(*s == '\0');
- }
- if (*pat == *s) {
- pat++;
- s++;
- }
- else
- return(0);
- }
- }
- }
-
-
- static char *makerep(pat, start, len)
- char *pat, **start;
- int *len;
- {
- int i, k;
- char *q, *p, *res;
- char b[MAXNAMLEN];
-
- p = b;
- for ( ; *pat != '\0'; pat++) {
- if (*pat == '#') {
- pat++;
- k = *pat - '1';
- if (p - b + len[k] > MAXNAMLEN) {
- fputs("Replacement name too long.\n", stderr);
- exit(1);
- }
- for (i=0, q = start[k]; i < len[k]; i++)
- *(p++)= *(q++);
- }
- else {
- if (*pat == '\\') {
- pat++;
- if (*pat == '\0')
- break;
- }
- if (p - b + 1 > MAXNAMLEN) {
- fputs("Replacement name too long.\n", stderr);
- exit(1);
- }
- *(p++)= *pat;
- }
- }
- *(p++) = '\0';
- res = (char *)malloc((p - b) * sizeof(char));
- strcpy(res, b);
- return(res);
- }
-
-
- static checkcollisons(reps, nreps)
- REP *reps;
- int nreps;
- {
- char **repdict;
- REP *cur;
- int i;
-
- repdict = (char **)malloc(nreps * sizeof(char *));
- for (i = 0, cur = reps; cur != NULL; cur = cur->nextrep)
- repdict[i++] = cur->repname;
- qsort(repdict, nreps, sizeof(char *), mycmp);
- for (i = 0; i < nreps-1; i++)
- if (strcmp(repdict[i], repdict[i+1]) == 0) {
- fputs("Two or more files would have to be renamed to '",
- stderr);
- fputs(repdict[i], stderr);
- fputs("'.\n", stderr);
- fputs("Aborting, no renames done.\n", stderr);
- exit(1);
- }
- }
-
-
- static int mycmp(pps1, pps2)
- char **pps1, **pps2;
- {
- return(strcmp(*pps1, *pps2));
- }
-
-
- static checkdeletes(reps, dot, filrep, nfils, delstyle)
- REP *reps;
- struct direct *(dot[]);
- REP *(filrep[]);
- int nfils, delstyle;
- {
- int recheck, i;
- REP *cur;
- char doit, reply[MAXREP];
-
- do {
- recheck = 0;
- for (cur = reps; cur != NULL; cur = cur->nextrep) {
- if (cur->status == FORGET)
- continue;
- if ((i = bsearch(cur->repname, dot, nfils)) >= 0) {
- if (filrep[i] == NULL && cur->mustdel < 0) {
- cur->dofirst = NULL;
- if (delstyle == QUIETDEL)
- cur->mustdel = i;
- else if (delstyle == NODEL) {
- cur->status = FORGET;
- filrep[cur->ftorep] = NULL;
- recheck = 1;
- }
- else if (delstyle == ABORTDEL) {
- fputs(dot[i]->d_name, stderr);
- fputs(" would have to be removed.\n", stderr);
- fputs("Aborting, no renames done.\n", stderr);
- exit(1);
- }
- else {
- fputs(dot[cur->ftorep]->d_name, stderr);
- fputs(" -> ", stderr);
- fputs(cur->repname, stderr);
- fputs(" ; remove old ", stderr);
- fputs(dot[i]->d_name, stderr);
- fputs("? ", stderr);
- for (;;) {
- doit = *fgets(reply, MAXREP, stdin);
- if (doit == 'Y' || doit == 'y') {
- cur->mustdel = i;
- break;
- }
- else if (doit == 'N' || doit == 'n') {
- cur->status = FORGET;
- filrep[cur->ftorep] = NULL;
- recheck = 1;
- break;
- }
- else
- fputs("Yes or No? ", stderr);
- }
- }
- }
- else {
- cur->dofirst = filrep[i];
- cur->mustdel = -1;
- }
- }
- else {
- cur->dofirst = NULL;
- cur->mustdel = -1;
- }
- }
- } while (recheck);
- }
-
-
- static int bsearch(s, dlist, n)
- char *s;
- struct direct *(dlist[]);
- int n;
- {
- int first, k, last, res;
-
- for(first = 0, last = n - 1;;) {
- if (last < first)
- return(-1);
- k = (first + last) >> 1;
- if ((res = strcmp(s, dlist[k]->d_name)) == 0)
- return(k);
- if (res < 0)
- last = k - 1;
- else
- first = k + 1;
- }
- }
-
-
- static char** breakcycles(reps, nreps, dot)
- REP *reps;
- int nreps;
- struct direct *(dot[]);
- {
- char **tempnames;
- int tempno;
- REP *cur, *pred;
-
- tempnames = (char **)malloc(nreps * sizeof(char *) + 1);
- tempno = 0;
- for (cur = reps; cur != NULL; cur = cur->nextrep) {
- if (cur->status == FORGET)
- continue;
- for (pred = cur->dofirst;
- pred != NULL && pred != cur;
- pred = pred->dofirst)
- {
- if (pred->status != DO) {
- fputs("Strange error in cycle checking.\n", stderr);
- exit(1);
- }
- }
- if (pred == cur)
- if (cur->dofirst == cur)
- cur->status = FORGET;
- else {
- pred = (REP *)malloc(sizeof(REP));
- tempnames[++tempno] =
- (char *)malloc(sizeof(tempprefix) + strlen(cur->repname));
- strcpy(tempnames[tempno], tempprefix);
- strcat(tempnames[tempno], cur->repname);
- pred->repname = cur->repname;
- pred->ftorep = -tempno;
- pred->dofirst = cur->dofirst;
- pred->mustdel = -1;
- pred->status = DO;
- pred->nextrep = cur->nextrep;
- cur->repname = tempnames[tempno];
- cur->dofirst = NULL;
- cur->nextrep = pred;
- }
- }
- return(tempnames);
- }
-
-
- static dorenames(reps, dot, tempnames, verbose)
- REP *reps;
- struct direct *(dot[]);
- char *(tempnames[]);
- int verbose;
- {
- REP *cur;
- int skipped;
- char *fromname;
-
- do {
- skipped = 0;
- for (cur = reps; cur != NULL; cur = cur->nextrep) {
- if (cur->status == DO) {
- if (cur->dofirst != NULL && cur->dofirst->status != DONE)
- skipped = 1;
- else {
- fromname = (cur->ftorep < 0 ?
- tempnames[-(cur->ftorep)] :
- dot[cur->ftorep]->d_name);
- cur->status = DONE;
- if (rename(fromname, cur->repname)) {
- fputs("Strange. Can not rename '", stderr);
- fputs(fromname, stderr);
- fputs("' to '", stderr);
- fputs(cur->repname, stderr);
- fputs("'\n", stderr);
- }
- else if (verbose) {
- fputs(fromname, stdout);
- fputs(" -> ", stdout);
- fputs(cur->repname, stdout);
- if (cur->mustdel >= 0)
- fputs(" (*)", stderr);
- fputc('\n', stdout);
- }
- }
- }
- }
- } while (skipped);
- }
-