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