]> git.street.me.uk Git - andy/viking.git/blob - src/fileutils.c
Embed GtkHTML 4.10.0 URI functions
[andy/viking.git] / src / fileutils.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21 /*
22  * Code that is independent of any other Viking specific types
23  * Otherwise see file.c
24  */
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28
29 #include "fileutils.h"
30
31 #ifdef WINDOWS
32 #include <windef.h>
33 #define realpath(X,Y) _fullpath(Y,X,MAX_PATH)
34 #define FILE_SEP '\\'
35 #else
36 #define FILE_SEP '/'
37 #endif
38
39 const gchar *a_file_basename ( const gchar *filename )
40 {
41   const gchar *t = filename + strlen(filename) - 1;
42   while ( --t > filename )
43     if ( *(t-1) == FILE_SEP )
44       break;
45   if ( t >= filename )
46     return t;
47   return filename;
48 }
49
50 /**
51  * Just a wrapper around realpath, which itself is platform dependent
52  */
53 char *file_realpath ( const char *path, char *real )
54 {
55   return realpath ( path, real );
56 }
57
58 #ifndef MAXPATHLEN
59 #define MAXPATHLEN 1024
60 #endif
61 /**
62  * Always return the canonical filename in a newly allocated string
63  */
64 char *file_realpath_dup ( const char *path )
65 {
66         char real[MAXPATHLEN];
67
68         g_return_val_if_fail(path != NULL, NULL);
69
70         if (file_realpath(path, real))
71                 return g_strdup(real);
72
73         return g_strdup(path);
74 }
75
76 /**
77  * Permission granted to use this code after personal correspondance
78  * Slightly reworked for better cross platform use, glibisms, function rename and a compacter format
79  *
80  * FROM http://www.codeguru.com/cpp/misc/misc/fileanddirectorynaming/article.php/c263
81  */
82
83 // GetRelativeFilename(), by Rob Fisher.
84 // rfisher@iee.org
85 // http://come.to/robfisher
86
87 // The number of characters at the start of an absolute filename.  e.g. in DOS,
88 // absolute filenames start with "X:\" so this value should be 3, in UNIX they start
89 // with "\" so this value should be 1.
90 #ifdef WINDOWS
91 #define ABSOLUTE_NAME_START 3
92 #else
93 #define ABSOLUTE_NAME_START 1
94 #endif
95
96 // Given the absolute current directory and an absolute file name, returns a relative file name.
97 // For example, if the current directory is C:\foo\bar and the filename C:\foo\whee\text.txt is given,
98 // GetRelativeFilename will return ..\whee\text.txt.
99
100 const gchar *file_GetRelativeFilename ( gchar *currentDirectory, gchar *absoluteFilename )
101 {
102   gint afMarker = 0, rfMarker = 0;
103   gint cdLen = 0, afLen = 0;
104   gint i = 0;
105   gint levels = 0;
106   static gchar relativeFilename[MAXPATHLEN+1];
107
108   cdLen = strlen(currentDirectory);
109   afLen = strlen(absoluteFilename);
110
111   // make sure the names are not too long or too short
112   if (cdLen > MAXPATHLEN || cdLen < ABSOLUTE_NAME_START+1 ||
113       afLen > MAXPATHLEN || afLen < ABSOLUTE_NAME_START+1) {
114     return NULL;
115   }
116
117   // Handle DOS names that are on different drives:
118   if (currentDirectory[0] != absoluteFilename[0]) {
119     // not on the same drive, so only absolute filename will do
120     g_strlcpy(relativeFilename, absoluteFilename, MAXPATHLEN+1);
121     return relativeFilename;
122   }
123
124   // they are on the same drive, find out how much of the current directory
125   // is in the absolute filename
126   i = ABSOLUTE_NAME_START;
127   while (i < afLen && i < cdLen && currentDirectory[i] == absoluteFilename[i]) {
128     i++;
129   }
130
131   if (i == cdLen && (absoluteFilename[i] == G_DIR_SEPARATOR || absoluteFilename[i-1] == G_DIR_SEPARATOR)) {
132     // the whole current directory name is in the file name,
133     // so we just trim off the current directory name to get the
134     // current file name.
135     if (absoluteFilename[i] == G_DIR_SEPARATOR) {
136       // a directory name might have a trailing slash but a relative
137       // file name should not have a leading one...
138       i++;
139     }
140
141     g_strlcpy(relativeFilename, &absoluteFilename[i], MAXPATHLEN+1);
142     return relativeFilename;
143   }
144
145   // The file is not in a child directory of the current directory, so we
146   // need to step back the appropriate number of parent directories by
147   // using "..\"s.  First find out how many levels deeper we are than the
148   // common directory
149   afMarker = i;
150   levels = 1;
151
152   // count the number of directory levels we have to go up to get to the
153   // common directory
154   while (i < cdLen) {
155     i++;
156     if (currentDirectory[i] == G_DIR_SEPARATOR) {
157       // make sure it's not a trailing slash
158       i++;
159       if (currentDirectory[i] != '\0') {
160         levels++;
161       }
162     }
163   }
164
165   // move the absolute filename marker back to the start of the directory name
166   // that it has stopped in.
167   while (afMarker > 0 && absoluteFilename[afMarker-1] != G_DIR_SEPARATOR) {
168     afMarker--;
169   }
170
171   // check that the result will not be too long
172   if (levels * 3 + afLen - afMarker > MAXPATHLEN) {
173     return NULL;
174   }
175
176   // add the appropriate number of "..\"s.
177   rfMarker = 0;
178   for (i = 0; i < levels; i++) {
179     relativeFilename[rfMarker++] = '.';
180     relativeFilename[rfMarker++] = '.';
181     relativeFilename[rfMarker++] = G_DIR_SEPARATOR;
182   }
183
184   // copy the rest of the filename into the result string
185   strcpy(&relativeFilename[rfMarker], &absoluteFilename[afMarker]);
186
187   return relativeFilename;
188 }
189 /* END http://www.codeguru.com/cpp/misc/misc/fileanddirectorynaming/article.php/c263 */