/* X X U -- UNIX filename converter */ /* Lowercases filenames and strips spurious pathnames from them. Handy for use after UNZIPs or FTP MGETs or magnetic tape operations that leave your UNIX directory full of uppercase filenames, possibly with foreign paths included. Path stripping handles UNIX, DOS, VMS, and TOPS-20/TENEX formats. Usage: xxu file(s) Action: Renames argument files as follows: strips DOS or DEC device:, node:: names from front (up to rightmost ':') strips DOS path name from front (up to rightmost '\') if present strips VMS [directory] or DEC-20 name if present strips UNIX path name from front (up to rightmost '/') if present strips VMS version number from end (everything after ';') if present strips DEC-20 attributes from end (everything after ';') if present lowercases any uppercase letters converts spaces to underscores honors Ctrl-V quote for special characters discards unquoted unprintable characters if result is null, file is renamed to xxfile-n, where n is a number. if result would write over an existing file, file also renamed to xxfile-n. Typical usage: make a new directory, cd to it, then FTP files from DOS, Windows, VMS, etc, or Unzip them from an archive, then "xxu *" to fix the names. Files that already have lowercase names (and no path part included) are not touched. Author: F. da Cruz, The Kermit Project, Columbia University Email: fdc@columbia.edu Please send any changes back to the author. Revised: Jul 1985: First version Sep 1998: Provide for no rename(), handle spaces. Jul 1999: Add support for DOS pathname stripping. Copyright (C) 1999 Trustees of Columbia University in the City of New York This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #ifdef SYSV #include #else #ifdef M_XENIX #include #endif /* M_XENIX */ #endif /* SYSV */ #include #include /* For access() */ /* Define NO_RENAME on cc command line if rename() missing */ #ifdef NO_RENAME /* Use rename() if available since rename() is atomic and this isn't. */ int rename(oldname, newname) char *oldname, *newname; { if (link(oldname,newname) < 0) { perror("link"); return(-1); } else if (unlink(oldname) < 0) { perror("unlink"); return(-1); } else return(0); } #endif /* NO_RENAME */ char name[1024]; /* File name buffer */ char *pp, *cp, *xp; /* Character pointers */ char delim; /* Directory Delimiter */ int dc = 0, n = 0; /* Counters */ int quote = 0, indir = 0, done = 0; /* Flags */ main(argc,argv) int argc; char **argv; { if (argc < 2) { /* Give message if no args */ fprintf(stderr,"Usage: xxu file(s)\n"); exit(1); } n = 0; /* Unfixable filename counter */ while (--argc > 0) { /* For all files on command line... */ argv++; xp = *argv; /* Copy pointer for simplicity */ printf("%s ",*argv); /* Echo name of this file */ pp = name; /* Point to translation buffer */ *name = '\0'; /* Initialize buffer */ dc = 0; /* Filename dot counter */ done = 0; /* Flag for early completion */ for (cp = xp; (*cp != '\0') && !done; cp++) { /* Loop thru chars... */ if (quote) { /* If this char quoted, */ *pp++ = *cp; /* include it literally. */ quote = 0; } else if (indir) { /* If in directory name, */ if (*cp == delim) indir = 0; /* look for end delimiter. */ } else switch (*cp) { case '<': /* Discard DEC-20 directory name */ indir = 1; delim = '>'; break; case '[': /* Discard VMS directory name */ indir = 1; delim = ']'; break; case '/': /* Discard Unix path name */ case '\\': /* or DOS path name */ case ':': /* or DOS/DEC dev: or node:: name */ pp = name; break; #ifdef COMMENT /* We don't have too many DEC-20s any more, but we do have *.tar.gz's */ case '.': /* DEC -20 generation number */ if (++dc == 1) /* Keep first dot */ *pp++ = *cp; else /* Discard everything starting */ done = 1; /* with second dot. */ break; #endif /* COMMENT */ case ';': /* VMS version or DEC-20 attribute */ done = 1; /* Discard everything starting with */ break; /* semicolon */ case '\026': /* Control-V quote for special chars */ quote = 1; /* Set flag for next time. */ break; default: if (isupper(*cp)) /* Uppercase letter to lowercase */ *pp++ = tolower(*cp); else if (*cp == ' ') /* change blanks to underscore */ *pp++ = '_'; else if (isprint(*cp)) /* Other printable, just keep */ *pp++ = *cp; } } *pp = '\0'; /* Done with name, terminate it */ if (strcmp(name,xp) == 0) { /* If no renaming necessary, */ printf("(ok)\n"); /* just give message. */ continue; } while (*name == '\0' || access(name,0) == 0) { /* Find unique name */ sprintf(name,"xxfile-%d",n++); } printf("=> %s ",name); /* Tell what new name will be */ if (rename(xp,name) == 0) /* Try to rename it */ printf("(ok)\n"); /* Say what happened */ #ifndef NO_RENAME else perror("failed"); #endif /* NO_RENAME */ } exit(0); /* Done. */ }