themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / filename_absolute.cxx
blobb98d5eeb4a244ca32d360a70cca90c64ff4c0c75
1 //
2 // "$Id: filename_absolute.cxx 8146 2010-12-31 22:13:07Z matt $"
3 //
4 // Filename expansion routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 /* expand a file name by prepending current directory, deleting . and
29 .. (not really correct for symbolic links) between the prepended
30 current directory. Use $PWD if it exists.
31 Returns true if any changes were made.
34 #include <FL/filename.H>
35 #include <FL/fl_utf8.h>
36 #include <stdlib.h>
37 #include "flstring.h"
38 #include <ctype.h>
39 #if defined(WIN32) && !defined(__CYGWIN__)
40 # include <direct.h>
41 #else
42 # include <unistd.h>
43 #endif
45 #if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
46 inline int isdirsep(char c) {return c=='/' || c=='\\';}
47 #else
48 #define isdirsep(c) ((c)=='/')
49 #endif
51 /** Makes a filename absolute from a relative filename.
52 \code
53 #include <FL/filename.H>
54 [..]
55 chdir("/var/tmp");
56 fl_filename_absolute(out, sizeof(out), "foo.txt"); // out="/var/tmp/foo.txt"
57 fl_filename_absolute(out, sizeof(out), "./foo.txt"); // out="/var/tmp/foo.txt"
58 fl_filename_absolute(out, sizeof(out), "../log/messages"); // out="/var/log/messages"
59 \endcode
60 \param[out] to resulting absolute filename
61 \param[in] tolen size of the absolute filename buffer
62 \param[in] from relative filename
63 \return 0 if no change, non zero otherwise
65 int fl_filename_absolute(char *to, int tolen, const char *from) {
66 if (isdirsep(*from) || *from == '|'
67 #if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
68 || from[1]==':'
69 #endif
70 ) {
71 strlcpy(to, from, tolen);
72 return 0;
75 char *a;
76 char *temp = new char[tolen];
77 const char *start = from;
79 a = fl_getcwd(temp, tolen);
80 if (!a) {
81 strlcpy(to, from, tolen);
82 delete[] temp;
83 return 0;
85 #if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
86 for (a = temp; *a; a++) if (*a=='\\') *a = '/'; // ha ha
87 #else
88 a = temp+strlen(temp);
89 #endif
90 if (isdirsep(*(a-1))) a--;
91 /* remove intermediate . and .. names: */
92 while (*start == '.') {
93 if (start[1]=='.' && isdirsep(start[2])) {
94 char *b;
95 for (b = a-1; b >= temp && !isdirsep(*b); b--);
96 if (b < temp) break;
97 a = b;
98 start += 3;
99 } else if (isdirsep(start[1])) {
100 start += 2;
101 } else if (!start[1]) {
102 start ++; // Skip lone "."
103 break;
104 } else
105 break;
108 *a++ = '/';
109 strlcpy(a,start,tolen - (a - temp));
111 strlcpy(to, temp, tolen);
113 delete[] temp;
115 return 1;
118 /** Makes a filename relative to the current working directory.
119 \code
120 #include <FL/filename.H>
121 [..]
122 chdir("/var/tmp/somedir"); // set cwd to /var/tmp/somedir
123 [..]
124 char out[FL_PATH_MAX];
125 fl_filename_relative(out, sizeof(out), "/var/tmp/somedir/foo.txt"); // out="foo.txt", return=1
126 fl_filename_relative(out, sizeof(out), "/var/tmp/foo.txt"); // out="../foo.txt", return=1
127 fl_filename_relative(out, sizeof(out), "foo.txt"); // out="foo.txt", return=0 (no change)
128 fl_filename_relative(out, sizeof(out), "./foo.txt"); // out="./foo.txt", return=0 (no change)
129 fl_filename_relative(out, sizeof(out), "../foo.txt"); // out="../foo.txt", return=0 (no change)
130 \endcode
131 \param[out] to resulting relative filename
132 \param[in] tolen size of the relative filename buffer
133 \param[in] from absolute filename
134 \return 0 if no change, non zero otherwise
136 int // O - 0 if no change, 1 if changed
137 fl_filename_relative(char *to, // O - Relative filename
138 int tolen, // I - Size of "to" buffer
139 const char *from) // I - Absolute filename
141 char cwd_buf[FL_PATH_MAX]; // Current directory
142 // get the current directory and return if we can't
143 if (!fl_getcwd(cwd_buf, sizeof(cwd_buf))) {
144 strlcpy(to, from, tolen);
145 return 0;
147 return fl_filename_relative(to, tolen, from, cwd_buf);
151 /** Makes a filename relative to any other directory.
152 \param[out] to resulting relative filename
153 \param[in] tolen size of the relative filename buffer
154 \param[in] from absolute filename
155 \param[in] base relative to this absolute path
156 \return 0 if no change, non zero otherwise
158 int // O - 0 if no change, 1 if changed
159 fl_filename_relative(char *to, // O - Relative filename
160 int tolen, // I - Size of "to" buffer
161 const char *from, // I - Absolute filename
162 const char *base) { // I - Find path relative to this path
164 char *newslash; // Directory separator
165 const char *slash; // Directory separator
166 char *cwd = 0L, *cwd_buf = 0L;
167 if (base) cwd = cwd_buf = strdup(base);
169 // return if "from" is not an absolute path
170 #if defined(WIN32) || defined(__EMX__)
171 if (from[0] == '\0' ||
172 (!isdirsep(*from) && !isalpha(*from) && from[1] != ':' &&
173 !isdirsep(from[2]))) {
174 #else
175 if (from[0] == '\0' || !isdirsep(*from)) {
176 #endif // WIN32 || __EMX__
177 strlcpy(to, from, tolen);
178 if (cwd_buf) free(cwd_buf);
179 return 0;
182 // return if "cwd" is not an absolute path
183 #if defined(WIN32) || defined(__EMX__)
184 if (!cwd || cwd[0] == '\0' ||
185 (!isdirsep(*cwd) && !isalpha(*cwd) && cwd[1] != ':' &&
186 !isdirsep(cwd[2]))) {
187 #else
188 if (!cwd || cwd[0] == '\0' || !isdirsep(*cwd)) {
189 #endif // WIN32 || __EMX__
190 strlcpy(to, from, tolen);
191 if (cwd_buf) free(cwd_buf);
192 return 0;
195 #if defined(WIN32) || defined(__EMX__)
196 // convert all backslashes into forward slashes
197 for (newslash = strchr(cwd, '\\'); newslash; newslash = strchr(newslash + 1, '\\'))
198 *newslash = '/';
200 // test for the exact same string and return "." if so
201 if (!strcasecmp(from, cwd)) {
202 strlcpy(to, ".", tolen);
203 free(cwd_buf);
204 return (1);
207 // test for the same drive. Return the absolute path if not
208 if (tolower(*from & 255) != tolower(*cwd & 255)) {
209 // Not the same drive...
210 strlcpy(to, from, tolen);
211 free(cwd_buf);
212 return 0;
215 // compare the path name without the drive prefix
216 from += 2; cwd += 2;
217 #else
218 // test for the exact same string and return "." if so
219 if (!strcmp(from, cwd)) {
220 strlcpy(to, ".", tolen);
221 free(cwd_buf);
222 return (1);
224 #endif // WIN32 || __EMX__
226 // compare both path names until we find a difference
227 for (slash = from, newslash = cwd;
228 *slash != '\0' && *newslash != '\0';
229 slash ++, newslash ++)
230 if (isdirsep(*slash) && isdirsep(*newslash)) continue;
231 #if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
232 else if (tolower(*slash & 255) != tolower(*newslash & 255)) break;
233 #else
234 else if (*slash != *newslash) break;
235 #endif // WIN32 || __EMX__ || __APPLE__
237 // skip over trailing slashes
238 if ( *newslash == '\0' && *slash != '\0' && !isdirsep(*slash)
239 &&(newslash==cwd || !isdirsep(newslash[-1])) )
240 newslash--;
242 // now go back to the first character of the first differing paths segment
243 while (!isdirsep(*slash) && slash > from) slash --;
244 if (isdirsep(*slash)) slash ++;
246 // do the same for the current dir
247 if (isdirsep(*newslash)) newslash --;
248 if (*newslash != '\0')
249 while (!isdirsep(*newslash) && newslash > cwd) newslash --;
251 // prepare the destination buffer
252 to[0] = '\0';
253 to[tolen - 1] = '\0';
255 // now add a "previous dir" sequence for every following slash in the cwd
256 while (*newslash != '\0') {
257 if (isdirsep(*newslash)) strlcat(to, "../", tolen);
259 newslash ++;
262 // finally add the differing path from "from"
263 strlcat(to, slash, tolen);
265 free(cwd_buf);
266 return 1;
271 // End of "$Id: filename_absolute.cxx 8146 2010-12-31 22:13:07Z matt $".