/* cleanname -- print the shortest pathname equivalent to each specified NAME Copyright (C) 1990-1999 Free Software Foundation, Inc. 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, 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 #include #include #include #include "error.h" #include "system.h" #include "xalloc.h" #define AUTHORS "Leonard Stiles" #define PROGRAM_NAME "cleanname" #define DIRSEP '/' char *program_name; static struct option const longopts[] = { {"directory", 1, NULL, 'd'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} }; void usage (int status) { if (status) fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); else { printf (_("Usage: %s [ -d PREFIX ] NAME...\n"), program_name); printf (_("\ Print the shortest pathname equivalent to each specified NAME.\n\ \n\ -d, --directory=PREFIX prefix relative pathnames with `PREFIX/'\n\ --help print this help and exit\n\ --version output version information and exit\n")); puts (_("\nReport bugs to .")); } exit (status); } /* return shortest pathname equivalent to s, rewriting it in place. * s must be at least two bytes long, to hold "." */ static char * cleanname (char *s) { int *stk = malloc (sizeof *s / 2); /* stack of dir. name indices */ int iin = 0, iout = 0; /* input/output read/write indices */ int firstchar, top = 0; /* return input unchanged if we can't allocate memory for stack */ if (stk == NULL) return s; for (firstchar = 1; s[iin] != '\0'; firstchar = 0) { /* slash */ if (s[iin] == DIRSEP) { if (firstchar || (iout > 0 && s[iout - 1] != DIRSEP)) { s[iout++] = s[iin++]; } else iin++; continue; } /* dots */ if (s[iin] == '.' && (iout == 0 || s[iin - 1] == DIRSEP)) { /* single dot */ if (s[iin + 1] == DIRSEP || s[iin + 1] == '\0') { iin++; continue; } /* double dot */ if (s[iin + 1] == '.' && (s[iin + 2] == DIRSEP || s[iin + 2] == '\0')) { if (top > 0) { /* parent dir indices in stack */ iout = stk[--top]; iin += 2; } else /* copy literally */ while (s[iin] == '.') s[iout++] = s[iin++]; continue; } } /* non-special */ if (iout == 0 || s[iout - 1] == DIRSEP) stk[top++] = iout; while (s[iin] && s[iin] != DIRSEP) s[iout++] = s[iin++]; } if (iout == 0) s[iout++] = '.'; s[iout] = '\0'; /* delete trailing slashes */ if (iout > 1 && s[iout - 1] == DIRSEP) s[iout - 1] = '\0'; free (stk); return s; } int main (int argc, char **argv) { int i, optc; char *prefix = NULL; program_name = *argv; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); while ((optc = getopt_long (argc, argv, "d:", longopts, NULL)) != -1) switch (optc) { case 'd': prefix = optarg; break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: usage (1); } if (optind == argc) { error (0, 0, _("too few arguments")); usage (1); } for (i = optind; i < argc; i++) { char *instr; if (prefix != NULL && argv[i][0] != '/') { instr = xmalloc (strlen (prefix) + strlen (argv[i]) + 2); strcat (strcat (strcpy (instr, prefix), "/"), argv[i]); } else if (argv[i][0] == '\0') { instr = xmalloc (sizeof "."); *instr = '\0'; } else instr = argv[i]; puts (cleanname (instr)); if (instr != argv[i]) free (instr); } return 0; }