]> git.street.me.uk Git - andy/viking.git/blame - src/fileutils.c
[DOC] Switch from ordered list to a itemitized list.
[andy/viking.git] / src / fileutils.c
CommitLineData
a660c6aa
RN
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
724504e0
RN
32#include <windef.h>
33#define realpath(X,Y) _fullpath(Y,X,MAX_PATH)
a660c6aa
RN
34#define FILE_SEP '\\'
35#else
36#define FILE_SEP '/'
37#endif
38
39const 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}
724504e0
RN
49
50/**
51 * Just a wrapper around realpath, which itself is platform dependent
52 */
53char *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 */
64char *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
100const 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 */