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