1 // This may look like C code, but it is really -*- C++ -*-
2
3 // ------------------------------------------------------------------
4 // The Goldware Library
5 // Copyright (C) 1990-1999 Odinn Sorensen
6 // Copyright (C) 1999-2000 Alexander S. Aganichev
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 program; if not, write to the Free
20 // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 // MA 02111-1307, USA
22 // ------------------------------------------------------------------
23 // $Id: gfilutl2.cpp,v 1.21 2011/02/19 20:14:58 stas_degteff Exp $
24 // ------------------------------------------------------------------
25 // File utility functions
26 // ------------------------------------------------------------------
27
28 #include <gfilutil.h>
29 #ifndef __HAVE_DRIVES__
30 #include <pwd.h>
31 #endif
32 #ifdef __WIN32__
33 #include <windows.h>
34 #endif
35 #include <stdlib.h>
36 #include <string.h>
37
38 // ------------------------------------------------------------------
39 // Adds the directory-delimiter character into end of string ('\\' in DOS-based, '/' in unix-based OS)
40 // Replace wrong directory-delimiter character with good.
41
AddBackslash(std::string & p)42 std::string& AddBackslash(std::string& p) {
43
44 for(size_t posn = 0; (posn=p.find(GOLD_WRONG_SLASH_CHR, posn)) != p.npos; posn++)
45 p[posn] = GOLD_SLASH_CHR;
46 if(p[p.length()-1] != GOLD_SLASH_CHR)
47 p += GOLD_SLASH_STR;
48
49 return p;
50 }
51
52 // ------------------------------------------------------------------
53 // Remove one trailing directory-delimiter character ('\\' in DOS-based, '/' in unix-based OS)
54
StripBackslash(std::string & p)55 std::string& StripBackslash(std::string& p) {
56
57 std::string::iterator pend = p.end();
58
59 if(isslash(*pend))
60 p.erase(pend);
61
62 return p;
63 }
64
65 // ------------------------------------------------------------------
66 // Get size of file. Return values:
67 // positive number or zero - size of file,
68 // negative number - error (and error code is stored in errno)
69
GetFilesize(const std::string & filename)70 long GetFilesize(const std::string& filename) {
71
72 if(filename.empty()) {
73 errno = EINVAL;
74 return -1;
75 }
76
77 struct stat info;
78 if(stat(filename.c_str(), &info) == 0)
79 return info.st_size;
80 return -1;
81 }
82
83 // ------------------------------------------------------------------
84 // Add path to filename, if no path is set. Don't chech size of 'path', be careful!
85
MakePathname(std::string & pathname,const std::string & path,const std::string & name)86 void MakePathname(std::string& pathname, const std::string& path, const std::string& name) {
87
88 Path pn;
89 MakePathname(pn, path.c_str(), name.c_str());
90 pathname = pn;
91 }
92
93
94 // ------------------------------------------------------------------
95 // Copy pathname with enviroment variables substitution and adds directory delimiter char.
96 // Copy not more sizeof(Path) characters (__dst should be type "Path" or equvalence, size is GMAXPATH)
97
PathCopy(std::string & dst,const char * src)98 void PathCopy(std::string& dst, const char* src) {
99
100 dst = src;
101 strschg_environ(dst);
102 AddBackslash(dst);
103 }
PathCopy(std::string & dst,const std::string & src)104 void PathCopy(std::string& dst, const std::string& src) {
105
106 dst = src;
107 strschg_environ(dst);
108 AddBackslash(dst);
109 }
110
111
112 // ------------------------------------------------------------------
113 // DOS-style enviroment variables substitution in string.
114 // In unix-like enviroment also tilde substitution in string.
115
strschg_environ(std::string & s)116 int strschg_environ(std::string& s) {
117
118 std::string fnd;
119 int replaced = 0;
120 size_t posn, posn1;
121
122 if (s.length() > 1) {
123 while(((posn=s.find('%')) != s.npos) and ((posn1=s.find('%', posn+1)) != s.npos)) {
124 fnd = s.substr(posn+1, posn1-1-posn);
125 const char* rep = getenv(fnd.c_str());
126 rep = rep ? rep : "";
127 s.replace(posn, posn1-posn+1, rep);
128 replaced++;
129 }
130 }
131
132 #ifndef __HAVE_DRIVES__
133 if( s[0] == '~' ) {
134 struct passwd *pe=NULL;
135 size_t slash = 1;
136
137 if( (s.length() > 1) and not isslash(s[1]) ) {
138 slash = s.find_first_of(GOLD_SLASH_STR GOLD_WRONG_SLASH_STR, 1);
139 fnd.assign(s,1,slash-1);
140 pe = getpwnam(fnd.c_str());
141 }else {
142 pe = getpwuid(getuid());
143 }
144 if(pe != NULL) {
145 fnd.assign(pe->pw_dir);
146 if ( slash != std::string::npos )
147 fnd += s.substr(slash);
148 s=fnd;
149 replaced++;
150 }
151 }
152 #endif
153
154 return replaced;
155 }
156
157
158 // ------------------------------------------------------------------
159 // Change dirname to real full pathname
160
maketruepath(std::string & dirname)161 bool maketruepath(std::string &dirname) {
162
163 bool ok = true;
164 std::string ndirname;
165 char cwd[GMAXPATH];
166 getcwd(cwd, GMAXPATH);
167 #ifdef __HAVE_DRIVES__
168 #ifdef __WIN32__
169 char expanded[GMAXPATH];
170 char *k;
171 if(GetFullPathName(dirname.c_str(), GMAXPATH, expanded, &k) == 0) {
172 dirname = cwd;
173 ok = false;
174 }
175 else {
176 if(access(expanded, R_OK) == 0)
177 dirname = expanded;
178 else {
179 dirname = cwd;
180 ok = false;
181 }
182 }
183 #elif defined __OS2__
184 char expanded[GMAXPATH];
185 if(_fullpath(expanded, dirname.c_str(), GMAXPATH) == 0) {
186 if(access(expanded, R_OK) == 0)
187 dirname = expanded;
188 else {
189 dirname = cwd;
190 ok = false;
191 }
192 }
193 else {
194 dirname = cwd;
195 ok = false;
196 }
197 #elif defined __DJGPP__
198 char expanded[GMAXPATH];
199 _fixpath(dirname.c_str(), expanded);
200 if(access(expanded, R_OK) == 0)
201 dirname = expanded;
202 else {
203 dirname = cwd;
204 ok = false;
205 }
206 #else
207 long inspos = -1;
208 if((dirname.length() == 2) and (dirname[1] == ':'))
209 inspos = 2;
210 else if((dirname.length() < 2) or (dirname[1] != ':') or isslash(dirname[0]))
211 inspos = 0;
212 else if(not isslash(dirname[2]))
213 inspos = 2;
214 if(inspos != -1) {
215 char chdrive[] = " :";
216 chdrive[0] = (inspos == 2) ? dirname[0] : cwd[0];
217 if(not chdir(chdrive)) {
218 char dwd[GMAXPATH];
219 getcwd(dwd, GMAXPATH);
220 if(isslash(dirname[0]))
221 ndirname = chdrive;
222 else {
223 ndirname = dwd;
224 ndirname += GOLD_SLASH_CHR;
225 }
226 ndirname += dirname.c_str() + inspos;
227 dirname = ndirname;
228 } else {
229 dirname = cwd;
230 ok = false;
231 }
232 chdir(cwd);
233 }
234 #endif
235 #else
236 if(not dirname.empty() and (dirname[0] == '~')) {
237 char* lname;
238 const char *p = dirname.c_str()+1;
239 if((dirname.length() != 1) and not isslash(*p)) {
240 while(*p and not isslash(*p))
241 ndirname += *p++; // get user name
242 } else {
243 if ((lname = getlogin()) == NULL)
244 lname = getenv("LOGNAME");
245 ndirname = lname; // get current user name
246 }
247 struct passwd *pe = getpwnam(ndirname.c_str()); // get home
248 if(pe != NULL) {
249 ndirname = pe->pw_dir;
250 ndirname += GOLD_SLASH_CHR;
251 if(isslash(*p))
252 ++p;
253 ndirname += p;
254 dirname = ndirname;
255 } else {
256 dirname = cwd;
257 ok = false;
258 }
259 } else if(not dirname.empty() and not isslash(dirname[0])) {
260 ndirname = cwd;
261 ndirname += GOLD_SLASH_CHR;
262 ndirname += dirname;
263 dirname = ndirname;
264 }
265 #endif
266 size_t posn;
267 for(posn = 0; (posn=dirname.find(GOLD_WRONG_SLASH_CHR, posn)) != dirname.npos; posn++)
268 dirname[posn] = GOLD_SLASH_CHR;
269 size_t skipfrom, skipto;
270 #ifdef __HAVE_DRIVES__ /* Prevent from destroying UNC names */
271 if(dirname.length() > 1) {
272 while((skipfrom=dirname.find("\\\\", 1)) != dirname.npos)
273 dirname.erase(skipfrom, 1);
274 }
275 #endif
276 size_t len = dirname.length();
277 #ifdef __HAVE_DRIVES__
278 while((len > 3) and isslash(dirname[--len]))
279 #else
280 while((len > 1) and isslash(dirname[--len]))
281 #endif
282 dirname.erase(len, 1);
283 if(access(dirname.c_str(), R_OK)) {
284 dirname = cwd;
285 ok = false;
286 }
287 #ifdef __HAVE_DRIVES__
288 if((dirname.length() > 2) and (dirname[0] == '\\') and (dirname[1] == '\\'))
289 posn = 2;
290 else
291 #endif
292 posn = 0;
293 for(; (posn=dirname.find('\\', posn)) != dirname.npos; posn++)
294 dirname[posn] = '/';
295 while((skipto=dirname.find("/../")) != dirname.npos) {
296 skipfrom = (skipto == 0) ? 0 : dirname.rfind('/', skipto-1);
297 skipto += 2;
298 dirname.erase(skipfrom, skipto-skipfrom+1);
299 }
300 while((skipfrom=dirname.find("/./")) != dirname.npos)
301 dirname.erase(skipfrom, 2);
302 len = dirname.length();
303 if(len > 2 and not strcmp(&(dirname.c_str()[len-2]), "/."))
304 dirname.erase(len-2, 2);
305 len = dirname.length();
306 #ifdef __HAVE_DRIVES__
307 if((len > 3) and isslash(dirname[--len]))
308 #else
309 if((len > 1) and isslash(dirname[--len]))
310 #endif
311 dirname.erase(len, 1);
312 return ok;
313 }
314
315
316 // ------------------------------------------------------------------
317