summaryrefslogtreecommitdiffstats
path: root/lib/filenames.c
diff options
context:
space:
mode:
authorGreg McGary <greg@mcgary.org>1997-04-18 06:42:59 +0000
committerGreg McGary <greg@mcgary.org>1997-04-18 06:42:59 +0000
commit40b4b4e4990e67028efb79345fba5fa9e760b522 (patch)
tree34e9ba556c821f7c7f94b99c0cbcbf0cc321b5af /lib/filenames.c
parent8c13e09279f361e18173f9e237c454af0ab33299 (diff)
downloadidutils-40b4b4e4990e67028efb79345fba5fa9e760b522.tar.gz
idutils-40b4b4e4990e67028efb79345fba5fa9e760b522.tar.bz2
idutils-40b4b4e4990e67028efb79345fba5fa9e760b522.zip
Initial revision
Diffstat (limited to 'lib/filenames.c')
-rw-r--r--lib/filenames.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/lib/filenames.c b/lib/filenames.c
new file mode 100644
index 0000000..fc154a7
--- /dev/null
+++ b/lib/filenames.c
@@ -0,0 +1,375 @@
+/* filenames.c -- file & directory name manipulations
+ Copyright (C) 1986, 1995, 1996 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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <config.h>
+#include "system.h"
+#include "strxtra.h"
+#include "filenames.h"
+#include "misc.h"
+#include "error.h"
+
+extern char *xgetcwd __P((void));
+
+/* root_name returns the base name of the file with any leading
+ * directory information or trailing suffix stripped off. Examples:
+ *
+ * /usr/include/stdio.h -> stdio
+ * fred -> fred
+ * barney.c -> barney
+ * bill/bob -> bob
+ * / -> < null string >
+ */
+char const *
+root_name (char const *path)
+{
+ static char file_name_buffer[BUFSIZ];
+ char const *root;
+ char const *dot;
+
+ root = strrchr (path, '/');
+ if (root == NULL)
+ root = path;
+ else
+ root++;
+
+ dot = strrchr (root, '.');
+ if (dot == NULL)
+ strcpy (file_name_buffer, root);
+ else
+ {
+ strncpy (file_name_buffer, root, dot - root);
+ file_name_buffer[dot - root] = '\0';
+ }
+ return file_name_buffer;
+}
+
+/* suff_name returns the suffix (including the dot) or a null string
+ * if there is no suffix. Examples:
+ *
+ * /usr/include/stdio.h -> .h
+ * fred -> < null string >
+ * barney.c -> .c
+ * bill/bob -> < null string >
+ * / -> < null string >
+ */
+char const *
+suff_name (char const *path)
+{
+ char const *dot;
+
+ dot = strrchr (path, '.');
+ if (dot == NULL)
+ return "";
+ return dot;
+}
+
+int
+can_crunch (char const *path1, char const *path2)
+{
+ char const *slash1;
+ char const *slash2;
+
+ slash1 = strrchr (path1, '/');
+ slash2 = strrchr (path2, '/');
+
+ if (slash1 == NULL && slash2 == NULL)
+ return strequ (suff_name (path1), suff_name (path2));
+ if ((slash1 - path1) != (slash2 - path2))
+ return 0;
+ if (!strnequ (path1, path2, slash1 - path1))
+ return 0;
+ return strequ (suff_name (slash1), suff_name (slash2));
+}
+
+/* look_up adds ../s to the beginning of a file name until it finds
+ * the one that really exists. Returns NULL if it gets all the way
+ * to / and never finds it.
+ *
+ * If the file name starts with /, just return it as is.
+ *
+ * This routine is used to locate the ID database file.
+ */
+char const *
+look_up (char const *arg)
+{
+ static char file_name_buffer[BUFSIZ];
+ char *buf = file_name_buffer;
+ char *id_path = 0;
+ struct stat rootb;
+ struct stat statb;
+
+ if (arg == 0)
+ {
+ id_path = getenv ("IDPATH");
+ if (id_path)
+ {
+ id_path = strdup (id_path);
+ arg = strtok (id_path, ":");
+ /* FIXME: handle multiple ID file names */
+ }
+ }
+ if (arg == 0)
+ arg = ID_FILE_NAME;
+
+ /* if we got absolute name, just use it. */
+ if (arg[0] == '/')
+ return arg;
+ /* if the name we were give exists, don't bother searching */
+ if (stat (arg, &statb) == 0)
+ return arg;
+ /* search up the tree until we find a directory where this
+ * relative file name is visible.
+ * (or we run out of tree to search by hitting root).
+ */
+
+ if (stat ("/", &rootb) != 0)
+ return NULL;
+ do
+ {
+ strcpy (buf, "../");
+ buf += 3;
+ strcpy (buf, arg);
+ if (stat (file_name_buffer, &statb) == 0)
+ return file_name_buffer;
+ *buf = '\0';
+ if (stat (file_name_buffer, &statb) != 0)
+ return NULL;
+ }
+ while (!((statb.st_ino == rootb.st_ino) ||
+ (statb.st_dev == rootb.st_dev)));
+ return NULL;
+}
+
+/* define special name components */
+
+static char slash[] = "/";
+static char dot[] = ".";
+static char dotdot[] = "..";
+
+/* nextc points to the next character to look at in the string or is
+ * null if the end of string was reached.
+ *
+ * namep points to buffer that holds the components.
+ */
+static char const *nextc = NULL;
+static char *namep;
+
+/* lexname - Return next name component. Uses global variables initialized
+ * by canonize_file_name to figure out what it is scanning.
+ */
+static char const *
+lexname (void)
+{
+ char c;
+ char const *d;
+
+ if (nextc)
+ {
+ c = *nextc++;
+ if (c == '\0')
+ {
+ nextc = NULL;
+ return NULL;
+ }
+ if (c == '/')
+ {
+ return &slash[0];
+ }
+ if (c == '.')
+ {
+ if ((*nextc == '/') || (*nextc == '\0'))
+ return &dot[0];
+ if (*nextc == '.' && (*(nextc + 1) == '/' || *(nextc + 1) == '\0'))
+ {
+ ++nextc;
+ return &dotdot[0];
+ }
+ }
+ d = namep;
+ *namep++ = c;
+ while ((c = *nextc) != '/')
+ {
+ *namep++ = c;
+ if (c == '\0')
+ {
+ nextc = NULL;
+ return d;
+ }
+ ++nextc;
+ }
+ *namep++ = '\0';
+ return d;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/* canonize_file_name - Put a file name in cannonical form. Looks for all the
+ * whacky wonderful things a demented *ni* programmer might put
+ * in a file name and reduces the name to cannonical form.
+ */
+void
+canonize_file_name (char *n)
+{
+ char const *components[1024];
+ char const **cap = &components[0];
+ char const **cad;
+ char const *cp;
+ char namebuf[2048];
+ char const *s;
+
+ /* initialize scanner */
+ nextc = n;
+ namep = &namebuf[0];
+
+ /* break the file name into individual components */
+ while ((cp = lexname ()))
+ {
+ *cap++ = cp;
+ }
+
+ /* If name is empty, leave it that way */
+ if (cap == &components[0])
+ return;
+
+ /* flag end of component list */
+ *cap = NULL;
+
+ /* remove all trailing slashes and dots */
+ while ((--cap != &components[0]) &&
+ ((*cap == &slash[0]) || (*cap == &dot[0])))
+ *cap = NULL;
+
+ /* squeeze out all . / component sequences */
+ cap = &components[0];
+ cad = cap;
+ while (*cap)
+ {
+ if ((*cap == &dot[0]) && (*(cap + 1) == &slash[0]))
+ {
+ cap += 2;
+ }
+ else
+ {
+ *cad++ = *cap++;
+ }
+ }
+ *cad++ = NULL;
+
+ /* find multiple // and use last slash as root, except on apollo which
+ * apparently actually uses // in real file names (don't ask me why).
+ */
+#ifndef apollo
+ s = NULL;
+ cap = &components[0];
+ cad = cap;
+ while (*cap)
+ {
+ if ((s == &slash[0]) && (*cap == &slash[0]))
+ {
+ cad = &components[0];
+ }
+ s = *cap++;
+ *cad++ = s;
+ }
+ *cad = NULL;
+#endif
+
+ /* if this is absolute name get rid of any /.. at beginning */
+ if ((components[0] == &slash[0]) && (components[1] == &dotdot[0]))
+ {
+ cap = &components[1];
+ cad = cap;
+ while (*cap == &dotdot[0])
+ {
+ ++cap;
+ if (*cap == NULL)
+ break;
+ if (*cap == &slash[0])
+ ++cap;
+ }
+ while (*cap)
+ *cad++ = *cap++;
+ *cad = NULL;
+ }
+
+ /* squeeze out any name/.. sequences (but leave leading ../..) */
+ cap = &components[0];
+ cad = cap;
+ while (*cap)
+ {
+ if ((*cap == &dotdot[0]) &&
+ ((cad - 2) >= &components[0]) &&
+ ((*(cad - 2)) != &dotdot[0]))
+ {
+ cad -= 2;
+ ++cap;
+ if (*cap)
+ ++cap;
+ }
+ else
+ {
+ *cad++ = *cap++;
+ }
+ }
+ /* squeezing out a trailing /.. can leave unsightly trailing /s */
+ if ((cad >= &components[2]) && ((*(cad - 1)) == &slash[0]))
+ --cad;
+ *cad = NULL;
+ /* if it was just name/.. it now becomes . */
+ if (components[0] == NULL)
+ {
+ components[0] = &dot[0];
+ components[1] = NULL;
+ }
+
+ /* re-assemble components */
+ cap = &components[0];
+ while ((s = *cap++))
+ {
+ while (*s)
+ *n++ = *s++;
+ }
+ *n++ = '\0';
+}
+
+FILE *
+open_source_FILE (char *file_name)
+{
+ FILE *source_FILE;
+
+ source_FILE = fopen (file_name, "r");
+ if (source_FILE == NULL)
+ error (0, errno, _("can't open `%s'"), file_name);
+ return source_FILE;
+}
+
+void
+close_source_FILE (FILE *fp)
+{
+ fclose (fp);
+}