/* * viking -- GPS Data and Topo Analyzer, Explorer, and Manager * * Copyright (C) 2003-2005, Evan Battaglia * * 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 * */ /* * Code that is independent of any other Viking specific types * Otherwise see file.c */ #include #include #include #include #include "fileutils.h" #ifdef WINDOWS #include #define realpath(X,Y) _fullpath(Y,X,MAX_PATH) #define FILE_SEP '\\' #else #define FILE_SEP '/' #endif const gchar *a_file_basename ( const gchar *filename ) { const gchar *t = filename + strlen(filename) - 1; while ( --t > filename ) if ( *(t-1) == FILE_SEP ) break; if ( t >= filename ) return t; return filename; } /** * Just a wrapper around realpath, which itself is platform dependent */ char *file_realpath ( const char *path, char *real ) { return realpath ( path, real ); } #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif /** * Always return the canonical filename in a newly allocated string */ char *file_realpath_dup ( const char *path ) { g_return_val_if_fail (path != NULL, NULL); #ifdef PATH_MAX // Posix 2008, realpath() will handle memory allocation return file_realpath ( path, NULL ); #else char real[MAXPATHLEN]; if ( file_realpath ( path, real ) ) return g_strdup ( real ); return NULL; #endif } /** * Permission granted to use this code after personal correspondance * Slightly reworked for better cross platform use, glibisms, function rename and a compacter format * * FROM http://www.codeguru.com/cpp/misc/misc/fileanddirectorynaming/article.php/c263 */ // GetRelativeFilename(), by Rob Fisher. // rfisher@iee.org // http://come.to/robfisher // The number of characters at the start of an absolute filename. e.g. in DOS, // absolute filenames start with "X:\" so this value should be 3, in UNIX they start // with "\" so this value should be 1. #ifdef WINDOWS #define ABSOLUTE_NAME_START 3 #else #define ABSOLUTE_NAME_START 1 #endif // Given the absolute current directory and an absolute file name, returns a relative file name. // For example, if the current directory is C:\foo\bar and the filename C:\foo\whee\text.txt is given, // GetRelativeFilename will return ..\whee\text.txt. const gchar *file_GetRelativeFilename ( gchar *currentDirectory, gchar *absoluteFilename ) { gint afMarker = 0, rfMarker = 0; gint cdLen = 0, afLen = 0; gint i = 0; gint levels = 0; static gchar relativeFilename[MAXPATHLEN+1]; cdLen = strlen(currentDirectory); afLen = strlen(absoluteFilename); // make sure the names are not too long or too short if (cdLen > MAXPATHLEN || cdLen < ABSOLUTE_NAME_START+1 || afLen > MAXPATHLEN || afLen < ABSOLUTE_NAME_START+1) { return NULL; } // Handle DOS names that are on different drives: if (currentDirectory[0] != absoluteFilename[0]) { // not on the same drive, so only absolute filename will do g_strlcpy(relativeFilename, absoluteFilename, MAXPATHLEN+1); return relativeFilename; } // they are on the same drive, find out how much of the current directory // is in the absolute filename i = ABSOLUTE_NAME_START; while (i < afLen && i < cdLen && currentDirectory[i] == absoluteFilename[i]) { i++; } if (i == cdLen && (absoluteFilename[i] == G_DIR_SEPARATOR || absoluteFilename[i-1] == G_DIR_SEPARATOR)) { // the whole current directory name is in the file name, // so we just trim off the current directory name to get the // current file name. if (absoluteFilename[i] == G_DIR_SEPARATOR) { // a directory name might have a trailing slash but a relative // file name should not have a leading one... i++; } g_strlcpy(relativeFilename, &absoluteFilename[i], MAXPATHLEN+1); return relativeFilename; } // The file is not in a child directory of the current directory, so we // need to step back the appropriate number of parent directories by // using "..\"s. First find out how many levels deeper we are than the // common directory afMarker = i; levels = 1; // count the number of directory levels we have to go up to get to the // common directory while (i < cdLen) { i++; if (currentDirectory[i] == G_DIR_SEPARATOR) { // make sure it's not a trailing slash i++; if (currentDirectory[i] != '\0') { levels++; } } } // move the absolute filename marker back to the start of the directory name // that it has stopped in. while (afMarker > 0 && absoluteFilename[afMarker-1] != G_DIR_SEPARATOR) { afMarker--; } // check that the result will not be too long if (levels * 3 + afLen - afMarker > MAXPATHLEN) { return NULL; } // add the appropriate number of "..\"s. rfMarker = 0; for (i = 0; i < levels; i++) { relativeFilename[rfMarker++] = '.'; relativeFilename[rfMarker++] = '.'; relativeFilename[rfMarker++] = G_DIR_SEPARATOR; } // copy the rest of the filename into the result string strcpy(&relativeFilename[rfMarker], &absoluteFilename[afMarker]); return relativeFilename; } /* END http://www.codeguru.com/cpp/misc/misc/fileanddirectorynaming/article.php/c263 */