- /* Construct file name. */
- ds_clear (&file);
- if (prefix != NULL && !fn_is_absolute (ds_c_str (&dir)))
- {
- ds_puts (&file, prefix);
- ds_putc (&file, '/');
- }
- ds_puts (&file, ds_c_str (&dir));
- if (ds_length (&dir) && ds_last (&file) != '/')
- ds_putc (&file, '/');
- ds_puts (&file, base_name);
-
- /* Check whether file exists. */
- if (fn_exists (ds_c_str (&file)))
- {
- verbose_msg (2, _("...found \"%s\""), ds_c_str (&file));
- ds_destroy (&path);
- ds_destroy (&dir);
- return ds_c_str (&file);
- }
- }
-
- /* Failure. */
- verbose_msg (2, _("...not found"));
- ds_destroy (&path);
- ds_destroy (&dir);
- ds_destroy (&file);
- return NULL;
-}
-
-/* fn_normalize(): This very OS-dependent routine canonicalizes
- filename FN1. The filename should not need to be the name of an
- existing file. Returns a malloc()'d copy of the canonical name.
- This function must always succeed; if it needs to bail out then it
- should return xstrdup(FN1). */
-#ifdef unix
-char *
-fn_normalize (const char *filename)
-{
- const char *src;
- char *fn1, *fn2, *dest;
- int maxlen;
-
- if (fn_is_special (filename))
- return xstrdup (filename);
-
- fn1 = fn_tilde_expand (filename);
-
- /* Follow symbolic links. */
- for (;;)
- {
- fn2 = fn1;
- fn1 = fn_readlink (fn1);
- if (!fn1)
- {
- fn1 = fn2;
- break;
- }
- free (fn2);
- }
-
- maxlen = strlen (fn1) * 2;
- if (maxlen < 31)
- maxlen = 31;
- dest = fn2 = xmalloc (maxlen + 1);
- src = fn1;
-
- if (*src == '/')
- *dest++ = *src++;
- else
- {
- errno = 0;
- while (getcwd (dest, maxlen - (dest - fn2)) == NULL && errno == ERANGE)
- {
- maxlen *= 2;
- dest = fn2 = xrealloc (fn2, maxlen + 1);
- errno = 0;
- }
- if (errno)
- {
- free (fn1);
- free (fn2);
- return NULL;
- }
- dest = strchr (fn2, '\0');
- if (dest - fn2 >= maxlen)
- {
- int ofs = dest - fn2;
- maxlen *= 2;
- fn2 = xrealloc (fn2, maxlen + 1);
- dest = fn2 + ofs;
- }
- if (dest[-1] != '/')
- *dest++ = '/';
- }
-
- for (;;)
- {
- int c, f;
-
- c = *src++;
-
- f = 0;
- if (c == '/' || c == 0)
- {
- /* remove `./', `../' from directory */
- if (dest[-1] == '.' && dest[-2] == '/')
- dest--;
- else if (dest[-1] == '.' && dest[-2] == '.' && dest[-3] == '/')
- {
- dest -= 3;
- if (dest == fn2)
- dest++;
- while (dest[-1] != '/')
- dest--;
- }
- else if (dest[-1] != '/') /* remove extra slashes */
- f = 1;
-
- if (c == 0)
- {
- if (dest[-1] == '/' && dest > fn2 + 1)
- dest--;
- *dest = 0;
- free (fn1);
-
- return xrealloc (fn2, strlen (fn2) + 1);
- }
- }