00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009 #include "vul_expand_path.h"
00010 #include <vcl_vector.h>
00011
00012 #if defined(VCL_WIN32) || defined(como4301)
00013
00014
00015
00016 vcl_string vul_expand_path_internal(vcl_string path)
00017 {
00018 if (path == "/")
00019 return path;
00020
00021 {
00022 vcl_vector<vcl_string> bits;
00023
00024
00025
00026 for (unsigned int i=0; i<path.size(); ) {
00027 if (path[i] == '/') {
00028 bits.push_back("/");
00029 ++i;
00030 }
00031 else {
00032 unsigned int j=i;
00033 while (j<path.size() && path[j]!='/')
00034 ++j;
00035 bits.push_back(vcl_string(path.c_str()+i, path.c_str()+j));
00036 i = j;
00037 }
00038 }
00039
00040
00041 while (true)
00042 {
00043 bool again = false;
00044 for (unsigned int i=0; i<bits.size(); ++i)
00045 {
00046
00047 if (i+1<bits.size() && bits[i] == "/" && bits[i+1] == "/") {
00048 bits.erase(bits.begin() + i);
00049 again = true;
00050 }
00051
00052
00053 if (i+1 == bits.size() && bits[i] == "/") {
00054 bits.pop_back();
00055 again = true;
00056 }
00057
00058
00059 if (i+2<bits.size() && !(bits[i]=="/") && bits[i+1]=="/" && bits[i+2]=="..") {
00060 bits.erase(bits.begin() + i+2);
00061 bits.erase(bits.begin() + i);
00062 again = true;
00063 }
00064
00065
00066 if (i+1<bits.size() && bits[i]=="/" && bits[i+1]==".") {
00067 bits.erase(bits.begin() + i+1);
00068 bits.erase(bits.begin() + i);
00069 again = true;
00070 }
00071 }
00072 if (!again)
00073 break;
00074 }
00075
00076
00077 path = "";
00078 for (unsigned int i=0; i<bits.size(); ++i)
00079 path += bits[i];
00080 #ifdef DEBUG
00081 vcl_cerr << "recomposed : " << path << '\n';
00082 #endif
00083 }
00084
00085
00086 return path;
00087 }
00088
00089
00090
00091 vcl_string vul_expand_path(vcl_string path)
00092 {
00093 return vul_expand_path_internal(path);
00094 }
00095
00096 #else // #if defined(VCL_WIN32) || defined(como4301)
00097
00098 #include <vcl_functional.h>
00099 #include <vcl_map.h>
00100 #include <vcl_cstdlib.h>
00101 #include <sys/types.h>
00102 #include <sys/stat.h>
00103 #include <dirent.h>
00104 #include <unistd.h>
00105
00106 static
00107 vcl_string vul_expand_path_internal(vcl_string path)
00108 {
00109 if (path == "/")
00110 return path;
00111
00112
00113 if ((path.size()>=2 && path[0] == '~' && path[1] == '/') || path == "~") {
00114 char const *HOME = vcl_getenv("HOME");
00115 if (! HOME) {
00116
00117 HOME = "/HOME";
00118 }
00119 path = vcl_string(HOME) + vcl_string(path.c_str() + 1);
00120 }
00121
00122
00123
00124 if (path.size()>=1 && path[0] != '/')
00125 path = vcl_string("./") + path;
00126
00127
00128 if ((path.size()>=2 && path[0] == '.' && path[1] == '/') || path == ".") {
00129 char cwd[4096];
00130 getcwd(cwd, sizeof cwd);
00131 path = vcl_string(cwd) + vcl_string(path.c_str() + 1);
00132 }
00133
00134 {
00135 vcl_vector<vcl_string> bits;
00136
00137
00138
00139 for (unsigned int i=0; i<path.size(); ) {
00140 if (path[i] == '/') {
00141 bits.push_back("/");
00142 ++i;
00143 }
00144 else {
00145 unsigned int j=i;
00146 while (j<path.size() && path[j]!='/')
00147 ++j;
00148 bits.push_back(vcl_string(path.c_str()+i, path.c_str()+j));
00149 i = j;
00150 }
00151 }
00152
00153
00154 while (true)
00155 {
00156 bool again = false;
00157 for (unsigned int i=0; i<bits.size(); ++i)
00158 {
00159
00160 if (i+1<bits.size() && bits[i] == "/" && bits[i+1] == "/") {
00161 bits.erase(bits.begin() + i);
00162 again = true;
00163 }
00164
00165
00166 if (i+1 == bits.size() && bits[i] == "/") {
00167 bits.pop_back();
00168 again = true;
00169 }
00170
00171
00172 if (i+2<bits.size() && !(bits[i]=="/") && bits[i+1]=="/" && bits[i+2]=="..") {
00173 bits.erase(bits.begin() + i+2);
00174 bits.erase(bits.begin() + i);
00175 again = true;
00176 }
00177
00178
00179 if (i+1<bits.size() && bits[i]=="/" && bits[i+1]==".") {
00180 bits.erase(bits.begin() + i+1);
00181 bits.erase(bits.begin() + i);
00182 again = true;
00183 }
00184 }
00185 if (!again)
00186 break;
00187 }
00188
00189
00190 path = "";
00191 for (unsigned int i=0; i<bits.size(); ++i)
00192 path += bits[i];
00193 #ifdef DEBUG
00194 vcl_cerr << "recomposed : " << path << '\n';
00195 #endif
00196 }
00197
00198
00199 for (unsigned int i=1; i<=path.size(); ++i)
00200 {
00201 if (i==path.size() || path[i] == '/')
00202 {
00203 vcl_string sub(path.c_str(), path.c_str() + i);
00204 char buf[4096];
00205 int len = readlink(sub.c_str(), buf, sizeof buf);
00206 if (len != -1)
00207 {
00208
00209 #ifdef DEBUG
00210 vcl_cerr << "before expansion : " << path << '\n';
00211 #endif
00212 if (buf[0] == '/') {
00213
00214
00215 path = vcl_string(buf, buf+len) + vcl_string(path.c_str() + i);
00216 }
00217 else
00218 {
00219
00220 int j=i-1;
00221 while (j>=0 && path[j] != '/')
00222 --j;
00223 if (j>=0) {
00224
00225 vcl_string a = vcl_string(path.c_str(), path.c_str()+j+1);
00226 vcl_string b = vcl_string(buf, buf+len);
00227 vcl_string c = vcl_string(path.c_str() + i, path.c_str() + path.size());
00228 #ifdef DEBUG
00229 vcl_cerr << "a = " << a << "\nb = " << b << "\nc = " << c << '\n';
00230 #endif
00231 path = a + b + c;
00232 }
00233 else {
00234
00235 path = vcl_string(buf, buf+len) + vcl_string(path.c_str() + i);
00236 }
00237 }
00238
00239 #ifdef DEBUG
00240 vcl_cerr << "after expansion : " << path << '\n';
00241 #endif
00242 return vul_expand_path_internal(path);
00243 }
00244 }
00245 }
00246
00247
00248 return path;
00249 }
00250
00251 typedef vcl_map<vcl_string, vcl_string, vcl_less<vcl_string> > map_t;
00252
00253 vcl_string vul_expand_path(vcl_string path)
00254 {
00255
00256 static map_t the_map;
00257
00258
00259 map_t::iterator i = the_map.find(path);
00260
00261 if (i == the_map.end()) {
00262
00263 vcl_string mapped = vul_expand_path_internal(path);
00264
00265 i = the_map.insert(map_t::value_type(path, mapped)).first;
00266 }
00267
00268
00269 return (*i).second;
00270 }
00271
00272 vcl_string vul_expand_path_uncached(vcl_string path)
00273 {
00274 return vul_expand_path_internal(path);
00275 }
00276
00277 #endif // VCL_WIN32