/* libnul * * Copyright (C) 2006-2007 Red Hat, Inc. * Copyright (C) 2009 Soren Sandmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * */ #include #include "libnul.h" /* nul_canonicalize_filename cutted and pasted from GIO * * Author: Alexander Larsson */ char * nul_canonicalize_filename (const char *filename) { char *canon, *start, *p, *q; char *cwd; int i; g_return_val_if_fail (filename != NULL, NULL); if (!g_path_is_absolute (filename)) { cwd = g_get_current_dir (); canon = g_build_filename (cwd, filename, NULL); g_free (cwd); } else canon = g_strdup (filename); start = (char *)g_path_skip_root (canon); /* POSIX allows double slashes at the start to * mean something special (as does windows too). * So, "//" != "/", but more than two slashes * is treated as "/". */ i = 0; for (p = start - 1; (p >= canon) && G_IS_DIR_SEPARATOR (*p); p--) i++; if (i > 2) { i -= 1; start -= i; memmove (start, start+i, strlen (start+i)+1); } p = start; while (*p != 0) { if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) { memmove (p, p+1, strlen (p+1)+1); } else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) { q = p + 2; /* Skip previous separator */ p = p - 2; if (p < start) p = start; while (p > start && !G_IS_DIR_SEPARATOR (*p)) p--; if (G_IS_DIR_SEPARATOR (*p)) *p++ = G_DIR_SEPARATOR; memmove (p, q, strlen (q)+1); } else { /* Skip until next separator */ while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) p++; if (*p != 0) { /* Canonicalize one separator */ *p++ = G_DIR_SEPARATOR; } } /* Remove additional separators */ q = p; while (*q && G_IS_DIR_SEPARATOR (*q)) q++; if (p != q) memmove (p, q, strlen (q)+1); } /* Remove trailing slashes */ if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) *(p-1) = 0; return canon; }