Fix compile errors on 64-bit systems
[libs/core.git] / source / utils.cpp
1 /* $Id$
2
3 This file is part of libmspfs
4 Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <cerrno>
9 #include <msp/core/except.h>
10 #ifndef WIN32
11 #include <fnmatch.h>
12 #else
13 #include <msp/strings/glob.h>
14 #endif
15 #include <msp/strings/utils.h>
16 #include "dir.h"
17 #include "path.h"
18 #include "stat.h"
19 #include "utils.h"
20
21 using namespace std;
22
23 namespace Msp {
24 namespace FS {
25
26 string basename(const Path &p)
27 {
28         return p[-1];
29 }
30
31 Path dirname(const Path &p)
32 {
33         if(p.size()==1)
34         {
35                 if(p.is_absolute())
36                         return p;
37                 return ".";
38         }
39         return p.subpath(0, p.size()-1);
40 }
41
42 string basepart(const string &fn)
43 {
44         unsigned dot=fn.rfind('.');
45         return fn.substr(0, dot);
46 }
47
48 string extpart(const string &fn)
49 {
50         string::size_type dot=fn.rfind('.');
51         if(dot==string::npos)
52                 return string();
53         return fn.substr(dot);
54 }
55
56 Path fix_case(const Path &path)
57 {
58         bool found=true;
59         Path result;
60         for(Path::Iterator i=path.begin(); i!=path.end(); ++i)
61         {
62                 if(!found || *i=="/")
63                         result/=*i;
64                 else
65                 {
66                         list<string> files;
67                         if(result.size())
68                                 files=list_files(result);
69                         else
70                                 files=list_files(".");
71
72                         found=false;
73                         for(list<string>::iterator j=files.begin(); (j!=files.end() && !found); ++j)
74                                 if(!strcasecmp(*j,*i))
75                                 {
76                                         result/=*j;
77                                         found=true;
78                                 }
79
80                         if(!found)
81                                 result/=*i;
82                 }
83         }
84
85         return result;
86 }
87
88 Path readlink(const Path &link)
89 {
90 #ifdef WIN32
91         (void)link;
92         throw Exception("No symbolic links on win32");
93 #else
94         char buf[4096];
95         int len=::readlink(link.str().c_str(), buf, sizeof(buf));
96         if(len==-1)
97                 throw SystemError("readlink failed", errno);
98         return string(buf, len);
99 #endif
100 }
101
102 Path realpath(const Path &path)
103 {
104 #ifdef WIN32
105         if(path.is_absolute())
106                 return path;
107         else
108                 return getcwd()/path;
109 #else
110         list<string> queue(path.begin(), path.end());
111         if(!path.is_absolute())
112         {
113                 Path cwd=getcwd();
114                 queue.insert(queue.begin(), cwd.begin(), cwd.end());
115         }
116
117         Path real;
118         unsigned n_links=0;
119         while(!queue.empty())
120         {
121                 Path next=real/queue.front();
122                 queue.pop_front();
123
124                 struct stat st=lstat(next);
125                 if(S_ISLNK(st.st_mode))
126                 {
127                         if(++n_links>64)
128                                 throw Exception("Ludicrous amount of symlinks detected in realpath, giving up");
129                         Path link=readlink(next);
130                         queue.insert(queue.begin(), link.begin(), link.end());
131                 }
132                 else
133                         real=next;
134         }
135
136         return real;
137 #endif
138 }
139
140 void unlink(const Path &path)
141 {
142         if(::unlink(path.str().c_str())==-1)
143                 throw SystemError("unlink failed", errno);
144 }
145
146 Path relative(const Path &path, const Path &base)
147 {
148         Path::Iterator i=path.begin();
149         Path::Iterator j=base.begin();
150         for(; (i!=path.end() && j!=base.end() && *i==*j); ++i, ++j) ;
151
152         Path result;
153         for(; j!=base.end(); ++j)
154                 result/="..";
155         for(; i!=path.end(); ++i)
156                 result/=*i;
157
158         return result;
159 }
160
161 } // namespace FS
162 } // namespace Msp