1 //
2 // "$Id: filename_absolute.cxx 6644 2009-01-23 10:47:53Z AlbrechtS $"
3 //
4 // Filename expansion routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2005 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.
12 //
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.
17 //
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 // http://www.fltk.org/str.php
26 //
27
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.
32 */
33
34 #include <FL/filename.H>
35 #include <stdlib.h>
36 #include "flstring.h"
37 #include <ctype.h>
38 #if defined(WIN32) && !defined(__CYGWIN__)
39 # include <direct.h>
40 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs
41 // on Windows, which is supposed to be POSIX compliant...
42 # define getcwd _getcwd
43 #else
44 # include <unistd.h>
45 # ifdef __EMX__
46 # define getcwd _getcwd2
47 # endif
48 #endif
49
50 #if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
isdirsep(char c)51 inline int isdirsep(char c) {return c=='/' || c=='\\';}
52 #else
53 #define isdirsep(c) ((c)=='/')
54 #endif
55
fl_filename_absolute(char * to,int tolen,const char * from)56 int fl_filename_absolute(char *to, int tolen, const char *from) {
57 if (isdirsep(*from) || *from == '|'
58 #if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
59 || from[1]==':'
60 #endif
61 ) {
62 strlcpy(to, from, tolen);
63 return 0;
64 }
65
66 char *a;
67 char *temp = new char[tolen];
68 const char *start = from;
69
70 a = getcwd(temp, tolen);
71 if (!a) {
72 strlcpy(to, from, tolen);
73 delete[] temp;
74 return 0;
75 }
76 #if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__)
77 for (a = temp; *a; a++) if (*a=='\\') *a = '/'; // ha ha
78 #else
79 a = temp+strlen(temp);
80 #endif
81 if (isdirsep(*(a-1))) a--;
82 /* remove intermediate . and .. names: */
83 while (*start == '.') {
84 if (start[1]=='.' && isdirsep(start[2])) {
85 char *b;
86 for (b = a-1; b >= temp && !isdirsep(*b); b--);
87 if (b < temp) break;
88 a = b;
89 start += 3;
90 } else if (isdirsep(start[1])) {
91 start += 2;
92 } else if (!start[1]) {
93 start ++; // Skip lone "."
94 break;
95 } else
96 break;
97 }
98
99 *a++ = '/';
100 strlcpy(a,start,tolen - (a - temp));
101
102 strlcpy(to, temp, tolen);
103
104 delete[] temp;
105
106 return 1;
107 }
108
109 /*
110 * 'fl_filename_relative()' - Make a filename relative to the current working directory.
111 */
112
113 int // O - 0 if no change, 1 if changed
fl_filename_relative(char * to,int tolen,const char * from)114 fl_filename_relative(char *to, // O - Relative filename
115 int tolen, // I - Size of "to" buffer
116 const char *from) {// I - Absolute filename
117 char *newslash; // Directory separator
118 const char *slash; // Directory separator
119 char cwd_buf[1024]; // Current directory
120 char *cwd = cwd_buf;
121
122
123 // return if "from" is not an absolute path
124 #if defined(WIN32) || defined(__EMX__)
125 if (from[0] == '\0' ||
126 (!isdirsep(*from) && !isalpha(*from) && from[1] != ':' &&
127 !isdirsep(from[2]))) {
128 #else
129 if (from[0] == '\0' || !isdirsep(*from)) {
130 #endif // WIN32 || __EMX__
131 strlcpy(to, from, tolen);
132 return 0;
133 }
134
135 // get the current directory and return if we can't
136 if (!getcwd(cwd_buf, sizeof(cwd_buf))) {
137 strlcpy(to, from, tolen);
138 return 0;
139 }
140
141 #if defined(WIN32) || defined(__EMX__)
142 // convert all backslashes into forward slashes
143 for (newslash = strchr(cwd, '\\'); newslash; newslash = strchr(newslash + 1, '\\'))
144 *newslash = '/';
145
146 // test for the exact same string and return "." if so
147 if (!strcasecmp(from, cwd)) {
148 strlcpy(to, ".", tolen);
149 return (1);
150 }
151
152 // test for the same drive. Return the absolute path if not
153 if (tolower(*from & 255) != tolower(*cwd & 255)) {
154 strlcpy(to, from, tolen);
155 return 0;
156 }
157
158 // compare the path name without the drive prefix
159 from += 2; cwd += 2;
160 #else
161 // test for the exact same string and return "." if so
162 if (!strcmp(from, cwd)) {
163 strlcpy(to, ".", tolen);
164 return (1);
165 }
166 #endif // WIN32 || __EMX__
167
168 // compare both path names until we find a difference
169 for (slash = from, newslash = cwd;
170 *slash != '\0' && *newslash != '\0';
171 slash ++, newslash ++)
172 if (isdirsep(*slash) && isdirsep(*newslash)) continue;
173 #if defined(WIN32) || defined(__EMX__) || defined(__APPLE__)
174 else if (tolower(*slash & 255) != tolower(*newslash & 255)) break;
175 #else
176 else if (*slash != *newslash) break;
177 #endif // WIN32 || __EMX__ || __APPLE__
178
179 // skip over trailing slashes
180 if ( *newslash == '\0' && *slash != '\0' && !isdirsep(*slash)
181 &&(newslash==cwd || !isdirsep(newslash[-1])) )
182 newslash--;
183
184 // now go back to the first character of the first differing paths segment
185 while (!isdirsep(*slash) && slash > from) slash --;
186 if (isdirsep(*slash)) slash ++;
187
188 // do the same for the current dir
189 if (*newslash != '\0')
190 while (!isdirsep(*newslash) && newslash > cwd) newslash --;
191
192 // prepare the destination buffer
193 to[0] = '\0';
194 to[tolen - 1] = '\0';
195
196 // now add a "previous dir" sequence for every following slash in the cwd
197 while (*newslash != '\0') {
198 if (isdirsep(*newslash)) strlcat(to, "../", tolen);
199
200 newslash ++;
201 }
202
203 // finally add the differing path from "from"
204 strlcat(to, slash, tolen);
205
206 return 1;
207 }
208
209
210 //
211 // End of "$Id: filename_absolute.cxx 6644 2009-01-23 10:47:53Z AlbrechtS $".
212 //
213