/* mren.c - mass rename using posix regex */ /* PUBLIC DOMAIN - April 7, 2008 - Jon Mayo */ /* examples: * * pretends to rename all your .c files to .cc : * mren -p -e '\(.*\)\.c$' -s '\1.cc' *.c * * Actually renames all .c files to .cc : * mren -v -e '\(.*\)\.c$' -s '\1.cc' *.c */ #include #include #include #include #include #include #define NR(x) (sizeof(x)/sizeof*(x)) static const char *argv0; static char *subst(const char *match_str, size_t nmatch, regmatch_t *pmatch, const char *substitute_str) { char *ret, *p; unsigned n, tmplen; /* TODO: calculate length for output */ ret=malloc(1024); p=ret; for(;*substitute_str;substitute_str++) { if(*substitute_str=='\\') { substitute_str++; if(isdigit(*substitute_str)) { n=*substitute_str-'0'; /* TODO: append pmatch[n] */ if(n=0) { tmplen=pmatch[n].rm_eo-pmatch[n].rm_so; memcpy(p, match_str+pmatch[n].rm_so, tmplen); p+=tmplen; } else { fprintf(stderr, "WARNING: substitution has invalid field %u.\n", n); free(ret); return 0; } } else { /* \escape invalid, insert the next character as literal */ *p++=*substitute_str; } } else { /* literal character */ *p++=*substitute_str; } } *p=0; return ret; } static void usage(void) { fprintf(stderr, "%s [-ipv] [-a action] [-e regex] [-s subst] ...\n", argv0); fprintf(stderr, "-a action\n" "-e regex pattern\n" "-i case insensitive matches\n" "-p pretend, do not actually perform action\n" "-s substitution string\n" ); exit(EXIT_FAILURE); } int main(int argc, char **argv) { int ch, i; int icase_fl=0, pretend_fl=0, verbose_fl=0, regex_fl=0; const char *subst_str=NULL; regex_t re; regmatch_t pmatch[10]; const char *action="move"; if(!(argv0=strrchr(argv[0], '/'))) argv0=argv[0]; else argv0++; while((ch=getopt(argc, argv, "e:hips:v"))>0) { switch(ch) { case 'i': icase_fl=0; break; case 'e': if(regex_fl) { /* TODO: support multiple matches and use the first match */ fprintf(stderr, "regex parameter may only be specified once\n"); return EXIT_FAILURE; } if(!regcomp(&re, optarg, REG_EXTENDED | icase_fl?REG_ICASE:0)) { regex_fl=1; } else { fprintf(stderr, "error:could not parse regex: %s\n", optarg); return EXIT_FAILURE; } break; case 'p': pretend_fl++; break; case 's': if(subst_str) { fprintf(stderr, "error:subst string option may only be specified once.\n"); return EXIT_FAILURE; } subst_str=optarg; break; case 'v': verbose_fl++; break; default: fprintf(stderr, "error:unknown option!\n"); case 'h': usage(); } } if(optind>=argc) usage(); for(i=optind;i %s\n", action, argv[i], out); } if(!pretend_fl) { if(!strcmp(action, "move")) { /* TODO: support cross-filesystem moves */ if(rename(argv[i], out)) { perror(argv[i]); return EXIT_FAILURE; } } else { fprintf(stderr, "error:action %s unsupported\n", action); return EXIT_FAILURE; } } free(out); } return EXIT_SUCCESS; }