Mercurial > hg > octave-nkf
annotate liboctave/file-ops.cc @ 10172:96ed9db3345c
provide wrappers for mkdir and mkfifo
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 21 Jan 2010 04:02:29 -0500 |
parents | 1dffc8b2fca7 |
children | 2b1f3f156aaf |
rev | line source |
---|---|
1765 | 1 /* |
2 | |
7017 | 3 Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
8920 | 4 2007, 2008 John W. Eaton |
1765 | 5 |
6 This file is part of Octave. | |
7 | |
8 Octave is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
7016 | 10 Free Software Foundation; either version 3 of the License, or (at your |
11 option) any later version. | |
1765 | 12 |
13 Octave is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
7016 | 19 along with Octave; see the file COPYING. If not, see |
20 <http://www.gnu.org/licenses/>. | |
1765 | 21 |
22 */ | |
23 | |
24 #ifdef HAVE_CONFIG_H | |
25 #include <config.h> | |
26 #endif | |
27 | |
28 #include <cerrno> | |
1802 | 29 #include <cstdio> |
30 #include <cstdlib> | |
1765 | 31 #include <cstring> |
32 | |
3503 | 33 #include <iostream> |
4726 | 34 #include <vector> |
3040 | 35 |
2443 | 36 #ifdef HAVE_SYS_TYPES_H |
1765 | 37 #include <sys/types.h> |
2443 | 38 #endif |
2926 | 39 |
40 #ifdef HAVE_UNISTD_H | |
1765 | 41 #include <unistd.h> |
42 #endif | |
43 | |
5476 | 44 #include "dir-ops.h" |
1765 | 45 #include "file-ops.h" |
5476 | 46 #include "file-stat.h" |
2926 | 47 #include "oct-env.h" |
2934 | 48 #include "oct-passwd.h" |
3710 | 49 #include "pathlen.h" |
5476 | 50 #include "quit.h" |
1775 | 51 #include "statdefs.h" |
2926 | 52 #include "str-vec.h" |
8377
25bc2d31e1bf
improve OCTAVE_LOCAL_BUFFER
Jaroslav Hajek <highegg@gmail.com>
parents:
8327
diff
changeset
|
53 #include "oct-locbuf.h" |
1765 | 54 |
8009
d936b21b3a6b
file_ops: use singleton class for static data members
John W. Eaton <jwe@octave.org>
parents:
8007
diff
changeset
|
55 file_ops::static_members *file_ops::static_members::instance = 0; |
d936b21b3a6b
file_ops: use singleton class for static data members
John W. Eaton <jwe@octave.org>
parents:
8007
diff
changeset
|
56 |
d936b21b3a6b
file_ops: use singleton class for static data members
John W. Eaton <jwe@octave.org>
parents:
8007
diff
changeset
|
57 file_ops::static_members::static_members (void) |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
58 : |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
59 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)) |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
60 xdir_sep_char ('\\'), |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
61 xdir_sep_str ("\\"), |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
62 #else |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
63 xdir_sep_char ('/'), |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
64 xdir_sep_str ("/"), |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
65 #endif |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
66 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
67 xdir_sep_chars ("/\\") |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
68 #else |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
69 xdir_sep_chars (xdir_sep_str) |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
70 #endif |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
71 { } |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
72 |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
73 bool |
8009
d936b21b3a6b
file_ops: use singleton class for static data members
John W. Eaton <jwe@octave.org>
parents:
8007
diff
changeset
|
74 file_ops::static_members::instance_ok (void) |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
75 { |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
76 bool retval = true; |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
77 |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
78 if (! instance) |
8009
d936b21b3a6b
file_ops: use singleton class for static data members
John W. Eaton <jwe@octave.org>
parents:
8007
diff
changeset
|
79 instance = new static_members (); |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
80 |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
81 if (! instance) |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
82 { |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
83 (*current_liboctave_error_handler) |
8009
d936b21b3a6b
file_ops: use singleton class for static data members
John W. Eaton <jwe@octave.org>
parents:
8007
diff
changeset
|
84 ("unable to create file_ops::static_members object!"); |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
85 |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
86 retval = false; |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
87 } |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
88 |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
89 return retval; |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
90 } |
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
91 |
2937 | 92 #define NOT_SUPPORTED(nm) \ |
4062 | 93 nm ": not supported on this system" |
2937 | 94 |
2433 | 95 // We provide a replacement for mkdir(). |
96 | |
1765 | 97 int |
10172
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
98 file_ops::mkdir (const std::string& nm, mode_t md) |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
99 { |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
100 std::string msg; |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
101 return mkdir (nm, md, msg); |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
102 } |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
103 |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
104 int |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
105 file_ops::mkdir (const std::string& name, mode_t mode, std::string& msg) |
2668 | 106 { |
3504 | 107 msg = std::string (); |
2668 | 108 |
2937 | 109 int status = -1; |
110 | |
10172
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
111 status = octave_mkdir (name.c_str (), mode); |
2668 | 112 |
113 if (status < 0) | |
3504 | 114 { |
115 using namespace std; | |
116 msg = ::strerror (errno); | |
117 } | |
2668 | 118 |
119 return status; | |
120 } | |
121 | |
2433 | 122 // I don't know how to emulate this on systems that don't provide it. |
123 | |
1765 | 124 int |
10172
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
125 file_ops::mkfifo (const std::string& nm, mode_t md) |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
126 { |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
127 std::string msg; |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
128 return mkfifo (nm, md, msg); |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
129 } |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
130 |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
131 int |
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
132 file_ops::mkfifo (const std::string& name, mode_t mode, std::string& msg) |
2668 | 133 { |
3504 | 134 msg = std::string (); |
2668 | 135 |
2937 | 136 int status = -1; |
137 | |
10028
52a248732bb6
use mkfifo module from gnulib
John W. Eaton <jwe@octave.org>
parents:
10027
diff
changeset
|
138 // With gnulib we will always have mkfifo, but some systems like MinGW |
52a248732bb6
use mkfifo module from gnulib
John W. Eaton <jwe@octave.org>
parents:
10027
diff
changeset
|
139 // don't have working mkfifo functions. On those systems, mkfifo will |
52a248732bb6
use mkfifo module from gnulib
John W. Eaton <jwe@octave.org>
parents:
10027
diff
changeset
|
140 // always return -1 and set errno. |
52a248732bb6
use mkfifo module from gnulib
John W. Eaton <jwe@octave.org>
parents:
10027
diff
changeset
|
141 |
10172
96ed9db3345c
provide wrappers for mkdir and mkfifo
John W. Eaton <jwe@octave.org>
parents:
10170
diff
changeset
|
142 status = octave_mkfifo (name.c_str (), mode); |
2668 | 143 |
144 if (status < 0) | |
3504 | 145 { |
146 using namespace std; | |
147 msg = ::strerror (errno); | |
148 } | |
2668 | 149 |
150 return status; | |
151 } | |
152 | |
3710 | 153 // I don't know how to emulate this on systems that don't provide it. |
154 | |
155 int | |
156 file_ops::link (const std::string& old_name, const std::string& new_name) | |
157 { | |
158 std::string msg; | |
159 return link (old_name, new_name, msg); | |
160 } | |
161 | |
162 int | |
163 file_ops::link (const std::string& old_name, | |
164 const std::string& new_name, std::string& msg) | |
165 { | |
166 msg = std::string (); | |
167 | |
168 int status = -1; | |
169 | |
170 #if defined (HAVE_LINK) | |
171 status = ::link (old_name.c_str (), new_name.c_str ()); | |
172 | |
173 if (status < 0) | |
174 { | |
175 using namespace std; | |
176 msg = ::strerror (errno); | |
177 } | |
178 #else | |
179 msg = NOT_SUPPORTED ("link"); | |
180 #endif | |
181 | |
182 return status; | |
183 } | |
184 | |
185 // I don't know how to emulate this on systems that don't provide it. | |
186 | |
187 int | |
188 file_ops::symlink (const std::string& old_name, const std::string& new_name) | |
189 { | |
190 std::string msg; | |
191 return symlink (old_name, new_name, msg); | |
192 } | |
193 | |
194 int | |
195 file_ops::symlink (const std::string& old_name, | |
196 const std::string& new_name, std::string& msg) | |
197 { | |
198 msg = std::string (); | |
199 | |
200 int status = -1; | |
201 | |
202 #if defined (HAVE_SYMLINK) | |
4577 | 203 |
9430
bfc7b000a229
file-ops.cc (file_ops::symlink, file_ops::readlink): avoid incorrectly sized buffer
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
204 status = ::symlink (old_name.c_str (), new_name.c_str ()); |
3710 | 205 |
206 if (status < 0) | |
207 { | |
208 using namespace std; | |
209 msg = ::strerror (errno); | |
210 } | |
211 #else | |
212 msg = NOT_SUPPORTED ("symlink"); | |
213 #endif | |
214 | |
215 return status; | |
216 } | |
217 | |
218 // We provide a replacement for rename(). | |
219 | |
220 int | |
221 file_ops::readlink (const std::string& path, std::string& result) | |
222 { | |
223 std::string msg; | |
224 return readlink (path, result, msg); | |
225 } | |
226 | |
227 int | |
228 file_ops::readlink (const std::string& path, std::string& result, | |
229 std::string& msg) | |
230 { | |
231 int status = -1; | |
232 | |
233 msg = std::string (); | |
234 | |
4066 | 235 #if defined (HAVE_READLINK) |
3710 | 236 char buf[MAXPATHLEN+1]; |
237 | |
9430
bfc7b000a229
file-ops.cc (file_ops::symlink, file_ops::readlink): avoid incorrectly sized buffer
John W. Eaton <jwe@octave.org>
parents:
8920
diff
changeset
|
238 status = ::readlink (path.c_str (), buf, MAXPATHLEN); |
3710 | 239 |
240 if (status < 0) | |
241 { | |
242 using namespace std; | |
243 msg = ::strerror (errno); | |
244 } | |
245 else | |
246 { | |
247 buf[status] = '\0'; | |
3769 | 248 result = std::string (buf); |
3710 | 249 status = 0; |
250 } | |
251 #else | |
252 msg = NOT_SUPPORTED ("rename"); | |
253 #endif | |
254 | |
255 return status; | |
256 } | |
257 | |
2433 | 258 // We provide a replacement for rename(). |
259 | |
1765 | 260 int |
3504 | 261 file_ops::rename (const std::string& from, const std::string& to) |
1765 | 262 { |
3504 | 263 std::string msg; |
2937 | 264 return rename (from, to, msg); |
1765 | 265 } |
266 | |
2668 | 267 int |
3504 | 268 file_ops::rename (const std::string& from, const std::string& to, |
269 std::string& msg) | |
2668 | 270 { |
2937 | 271 int status = -1; |
272 | |
3504 | 273 msg = std::string (); |
2668 | 274 |
10170
1dffc8b2fca7
use rename module from gnulib
John W. Eaton <jwe@octave.org>
parents:
10169
diff
changeset
|
275 status = octave_rename (from.c_str (), to.c_str ()); |
2668 | 276 |
277 if (status < 0) | |
3504 | 278 { |
279 using namespace std; | |
280 msg = ::strerror (errno); | |
281 } | |
2668 | 282 |
283 return status; | |
284 } | |
285 | |
2433 | 286 // We provide a replacement for rmdir(). |
287 | |
1765 | 288 int |
3504 | 289 file_ops::rmdir (const std::string& name) |
1765 | 290 { |
3504 | 291 std::string msg; |
2937 | 292 return rmdir (name, msg); |
1765 | 293 } |
294 | |
2668 | 295 int |
3504 | 296 file_ops::rmdir (const std::string& name, std::string& msg) |
2668 | 297 { |
3504 | 298 msg = std::string (); |
2668 | 299 |
2937 | 300 int status = -1; |
301 | |
10169
06bd6e57f889
use rmdir module from gnulib
John W. Eaton <jwe@octave.org>
parents:
10158
diff
changeset
|
302 status = octave_rmdir (name.c_str ()); |
2668 | 303 |
304 if (status < 0) | |
3504 | 305 { |
306 using namespace std; | |
307 msg = ::strerror (errno); | |
308 } | |
2668 | 309 |
310 return status; | |
311 } | |
312 | |
5476 | 313 // And a version that works recursively. |
314 | |
315 int | |
316 file_ops::recursive_rmdir (const std::string& name) | |
317 { | |
318 std::string msg; | |
319 return recursive_rmdir (name, msg); | |
320 } | |
321 | |
322 int | |
323 file_ops::recursive_rmdir (const std::string& name, std::string& msg) | |
324 { | |
325 msg = std::string (); | |
326 | |
327 int status = 0; | |
328 | |
329 dir_entry dir (name); | |
330 | |
331 if (dir) | |
332 { | |
333 string_vector dirlist = dir.read (); | |
334 | |
335 for (octave_idx_type i = 0; i < dirlist.length (); i++) | |
336 { | |
10142
829e69ec3110
make OCTAVE_QUIT a function
Jaroslav Hajek <highegg@gmail.com>
parents:
10038
diff
changeset
|
337 octave_quit (); |
5476 | 338 |
339 std::string nm = dirlist[i]; | |
340 | |
341 // Skip current directory and parent. | |
342 if (nm == "." || nm == "..") | |
343 continue; | |
344 | |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
345 std::string fullnm = name + file_ops::dir_sep_str () + nm; |
5476 | 346 |
347 // Get info about the file. Don't follow links. | |
348 file_stat fs (fullnm, false); | |
349 | |
350 if (fs) | |
351 { | |
352 if (fs.is_dir ()) | |
353 { | |
354 status = recursive_rmdir (fullnm, msg); | |
355 | |
356 if (status < 0) | |
357 break; | |
358 } | |
359 else | |
360 { | |
361 status = unlink (fullnm, msg); | |
362 | |
363 if (status < 0) | |
364 break; | |
365 } | |
366 } | |
367 else | |
368 { | |
369 msg = fs.error (); | |
370 break; | |
371 } | |
372 } | |
373 | |
374 if (status >= 0) | |
6363 | 375 { |
376 dir.close (); | |
377 status = file_ops::rmdir (name, msg); | |
378 } | |
5476 | 379 } |
380 else | |
381 { | |
382 status = -1; | |
383 | |
384 msg = dir.error (); | |
385 } | |
386 | |
387 return status; | |
388 } | |
389 | |
5138 | 390 std::string |
391 file_ops::canonicalize_file_name (const std::string& name) | |
392 { | |
393 std::string msg; | |
394 return canonicalize_file_name (name, msg); | |
395 } | |
396 | |
397 std::string | |
398 file_ops::canonicalize_file_name (const std::string& name, std::string& msg) | |
399 { | |
400 msg = std::string (); | |
401 | |
402 std::string retval; | |
403 | |
404 #if defined (HAVE_CANONICALIZE_FILE_NAME) | |
405 | |
406 char *tmp = ::canonicalize_file_name (name.c_str ()); | |
407 | |
408 if (tmp) | |
409 { | |
410 retval = tmp; | |
411 ::free (tmp); | |
412 } | |
413 | |
414 #elif defined (HAVE_RESOLVEPATH) | |
415 | |
416 #if !defined (errno) | |
417 extern int errno; | |
418 #endif | |
419 | |
420 #if !defined (__set_errno) | |
421 # define __set_errno(Val) errno = (Val) | |
422 #endif | |
423 | |
424 if (name.empty ()) | |
425 { | |
426 __set_errno (ENOENT); | |
427 return retval; | |
428 } | |
429 | |
430 // All known hosts with resolvepath (e.g. Solaris 7) don't turn | |
431 // relative names into absolute ones, so prepend the working | |
432 // directory if the path is not absolute. | |
433 | |
5149 | 434 std::string absolute_name |
435 = octave_env::make_absolute (name, octave_env::getcwd ()); | |
5138 | 436 |
5149 | 437 size_t resolved_size = absolute_name.length (); |
5138 | 438 |
6208 | 439 while (true) |
5138 | 440 { |
441 resolved_size = 2 * resolved_size + 1; | |
442 | |
443 OCTAVE_LOCAL_BUFFER (char, resolved, resolved_size); | |
444 | |
5149 | 445 int resolved_len |
446 = ::resolvepath (absolute_name.c_str (), resolved, resolved_size); | |
5138 | 447 |
448 if (resolved_len < 0) | |
449 break; | |
450 | |
451 if (resolved_len < resolved_size) | |
452 { | |
453 retval = resolved; | |
454 break; | |
455 } | |
456 } | |
457 | |
6208 | 458 #elif defined (__WIN32__) |
459 | |
460 int n = 1024; | |
461 | |
462 std::string win_path (n, '\0'); | |
463 | |
464 while (true) | |
465 { | |
7520 | 466 int status = GetFullPathName (name.c_str (), n, &win_path[0], 0); |
6208 | 467 |
468 if (status == 0) | |
469 break; | |
470 else if (status < n) | |
471 { | |
472 win_path.resize (status); | |
473 retval = win_path; | |
474 break; | |
475 } | |
476 else | |
477 { | |
478 n *= 2; | |
479 win_path.resize (n); | |
480 } | |
481 } | |
482 | |
6271 | 483 #elif defined (HAVE_REALPATH) |
484 | |
485 #if !defined (__set_errno) | |
486 # define __set_errno(Val) errno = (Val) | |
487 #endif | |
488 | |
489 if (name.empty ()) | |
490 { | |
491 __set_errno (ENOENT); | |
492 return retval; | |
493 } | |
494 | |
495 OCTAVE_LOCAL_BUFFER (char, buf, PATH_MAX); | |
496 | |
6273 | 497 if (::realpath (name.c_str (), buf)) |
498 retval = buf; | |
6271 | 499 |
5138 | 500 #else |
501 | |
5775 | 502 // FIXME -- provide replacement here... |
5138 | 503 retval = name; |
504 | |
505 #endif | |
506 | |
507 if (retval.empty ()) | |
508 { | |
509 using namespace std; | |
510 msg = ::strerror (errno); | |
511 } | |
512 | |
513 return retval; | |
514 } | |
515 | |
2433 | 516 // We provide a replacement for tempnam(). |
517 | |
3504 | 518 std::string |
519 file_ops::tempnam (const std::string& dir, const std::string& pfx) | |
1802 | 520 { |
3504 | 521 std::string msg; |
2937 | 522 return tempnam (dir, pfx, msg); |
523 } | |
524 | |
3504 | 525 std::string |
526 file_ops::tempnam (const std::string& dir, const std::string& pfx, | |
527 std::string& msg) | |
2937 | 528 { |
3504 | 529 msg = std::string (); |
2937 | 530 |
3504 | 531 std::string retval; |
2937 | 532 |
533 const char *pdir = dir.empty () ? 0 : dir.c_str (); | |
1802 | 534 |
2937 | 535 const char *ppfx = pfx.empty () ? 0 : pfx.c_str (); |
536 | |
537 char *tmp = ::tempnam (pdir, ppfx); | |
1802 | 538 |
539 if (tmp) | |
540 { | |
541 retval = tmp; | |
542 | |
2937 | 543 ::free (tmp); |
1802 | 544 } |
545 else | |
3504 | 546 { |
547 using namespace std; | |
548 msg = ::strerror (errno); | |
549 } | |
1802 | 550 |
551 return retval; | |
552 } | |
553 | |
3040 | 554 // The following tilde-expansion code was stolen and adapted from |
555 // readline. | |
2926 | 556 |
3040 | 557 // The default value of tilde_additional_prefixes. This is set to |
558 // whitespace preceding a tilde so that simple programs which do not | |
559 // perform any word separation get desired behaviour. | |
560 static const char *default_prefixes[] = { " ~", "\t~", ":~", 0 }; | |
561 | |
562 // The default value of tilde_additional_suffixes. This is set to | |
563 // whitespace or newline so that simple programs which do not perform | |
564 // any word separation get desired behaviour. | |
565 static const char *default_suffixes[] = { " ", "\n", ":", 0 }; | |
566 | |
567 // If non-null, this contains the address of a function that the | |
568 // application wants called before trying the standard tilde | |
569 // expansions. The function is called with the text sans tilde, and | |
570 // returns a malloc()'ed string which is the expansion, or a NULL | |
571 // pointer if the expansion fails. | |
572 file_ops::tilde_expansion_hook file_ops::tilde_expansion_preexpansion_hook = 0; | |
573 | |
574 // If non-null, this contains the address of a function to call if the | |
575 // standard meaning for expanding a tilde fails. The function is | |
576 // called with the text (sans tilde, as in "foo"), and returns a | |
577 // malloc()'ed string which is the expansion, or a NULL pointer if | |
578 // there is no expansion. | |
579 file_ops::tilde_expansion_hook file_ops::tilde_expansion_failure_hook = 0; | |
580 | |
581 // When non-null, this is a NULL terminated array of strings which are | |
582 // duplicates for a tilde prefix. Bash uses this to expand `=~' and | |
583 // `:~'. | |
584 string_vector file_ops::tilde_additional_prefixes = default_prefixes; | |
585 | |
586 // When non-null, this is a NULL terminated array of strings which | |
587 // match the end of a username, instead of just "/". Bash sets this | |
588 // to `:' and `=~'. | |
589 string_vector file_ops::tilde_additional_suffixes = default_suffixes; | |
590 | |
591 // Find the start of a tilde expansion in S, and return the index | |
592 // of the tilde which starts the expansion. Place the length of the | |
593 // text which identified this tilde starter in LEN, excluding the | |
594 // tilde itself. | |
595 | |
596 static size_t | |
3504 | 597 tilde_find_prefix (const std::string& s, size_t& len) |
3040 | 598 { |
599 len = 0; | |
600 | |
601 size_t s_len = s.length (); | |
602 | |
603 if (s_len == 0 || s[0] == '~') | |
604 return 0; | |
605 | |
606 string_vector prefixes = file_ops::tilde_additional_prefixes; | |
607 | |
608 if (! prefixes.empty ()) | |
609 { | |
610 for (size_t i = 0; i < s_len; i++) | |
611 { | |
612 for (int j = 0; j < prefixes.length (); j++) | |
613 { | |
614 size_t pfx_len = prefixes[j].length (); | |
615 | |
616 if (prefixes[j].compare (s.substr (i, pfx_len)) == 0) | |
617 { | |
618 len = pfx_len - 1; | |
619 return i + len; | |
620 } | |
621 } | |
622 } | |
623 } | |
624 | |
625 return s_len; | |
626 } | |
627 | |
628 // Find the end of a tilde expansion in S, and return the index | |
629 // of the character which ends the tilde definition. | |
630 | |
631 static size_t | |
3504 | 632 tilde_find_suffix (const std::string& s) |
3040 | 633 { |
634 size_t s_len = s.length (); | |
635 | |
636 string_vector suffixes = file_ops::tilde_additional_suffixes; | |
637 | |
638 size_t i = 0; | |
639 | |
640 for ( ; i < s_len; i++) | |
641 { | |
6694 | 642 if (file_ops::is_dir_sep (s[i])) |
3040 | 643 break; |
644 | |
645 if (! suffixes.empty ()) | |
646 { | |
647 for (int j = 0; j < suffixes.length (); j++) | |
648 { | |
649 size_t sfx_len = suffixes[j].length (); | |
650 | |
651 if (suffixes[j].compare (s.substr (i, sfx_len)) == 0) | |
652 return i; | |
653 } | |
654 } | |
655 } | |
656 | |
657 return i; | |
658 } | |
659 | |
660 // Take FNAME and return the tilde prefix we want expanded. | |
661 | |
3504 | 662 static std::string |
663 isolate_tilde_prefix (const std::string& fname) | |
3040 | 664 { |
665 size_t f_len = fname.length (); | |
666 | |
667 size_t len = 1; | |
668 | |
6694 | 669 while (len < f_len && ! file_ops::is_dir_sep (fname[len])) |
3040 | 670 len++; |
671 | |
672 return fname.substr (1, len); | |
673 } | |
674 | |
675 // Do the work of tilde expansion on FILENAME. FILENAME starts with a | |
676 // tilde. | |
677 | |
3504 | 678 static std::string |
679 tilde_expand_word (const std::string& filename) | |
3040 | 680 { |
681 size_t f_len = filename.length (); | |
682 | |
683 if (f_len == 0 || filename[0] != '~') | |
684 return filename; | |
685 | |
686 // A leading `~/' or a bare `~' is *always* translated to the value | |
687 // of $HOME or the home directory of the current user, regardless of | |
688 // any preexpansion hook. | |
689 | |
6694 | 690 if (f_len == 1 || file_ops::is_dir_sep (filename[1])) |
3040 | 691 return octave_env::get_home_directory () + filename.substr (1); |
692 | |
3504 | 693 std::string username = isolate_tilde_prefix (filename); |
3040 | 694 |
695 size_t user_len = username.length (); | |
696 | |
3504 | 697 std::string dirname; |
3040 | 698 |
699 if (file_ops::tilde_expansion_preexpansion_hook) | |
700 { | |
3504 | 701 std::string expansion |
3040 | 702 = file_ops::tilde_expansion_preexpansion_hook (username); |
703 | |
704 if (! expansion.empty ()) | |
3074 | 705 return expansion + filename.substr (user_len+1); |
3040 | 706 } |
707 | |
708 // No preexpansion hook, or the preexpansion hook failed. Look in the | |
709 // password database. | |
710 | |
711 octave_passwd pw = octave_passwd::getpwnam (username); | |
712 | |
713 if (! pw) | |
714 { | |
715 // If the calling program has a special syntax for expanding tildes, | |
716 // and we couldn't find a standard expansion, then let them try. | |
717 | |
718 if (file_ops::tilde_expansion_failure_hook) | |
719 { | |
3504 | 720 std::string expansion |
3040 | 721 = file_ops::tilde_expansion_failure_hook (username); |
722 | |
723 if (! expansion.empty ()) | |
3074 | 724 dirname = expansion + filename.substr (user_len+1); |
3040 | 725 } |
726 | |
727 // If we don't have a failure hook, or if the failure hook did not | |
728 // expand the tilde, return a copy of what we were passed. | |
729 | |
730 if (dirname.length () == 0) | |
731 dirname = filename; | |
732 } | |
733 else | |
3074 | 734 dirname = pw.dir () + filename.substr (user_len+1); |
3040 | 735 |
736 return dirname; | |
737 } | |
738 | |
739 // If NAME has a leading ~ or ~user, Unix-style, expand it to the | |
740 // user's home directory. If no ~, or no <pwd.h>, just return NAME. | |
741 | |
3504 | 742 std::string |
743 file_ops::tilde_expand (const std::string& name) | |
2926 | 744 { |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
745 if (name.find ('~') == std::string::npos) |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
746 return name; |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
747 else |
3040 | 748 { |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
749 std::string result; |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
750 |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
751 size_t name_len = name.length (); |
2926 | 752 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
753 // Scan through S expanding tildes as we come to them. |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
754 |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
755 size_t pos = 0; |
3040 | 756 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
757 while (1) |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
758 { |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
759 if (pos > name_len) |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
760 break; |
3040 | 761 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
762 size_t len; |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
763 |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
764 // Make START point to the tilde which starts the expansion. |
2926 | 765 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
766 size_t start = tilde_find_prefix (name.substr (pos), len); |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
767 |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
768 result.append (name.substr (pos, start)); |
3040 | 769 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
770 // Advance STRING to the starting tilde. |
2926 | 771 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
772 pos += start; |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
773 |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
774 // Make FINI be the index of one after the last character of the |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
775 // username. |
2926 | 776 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
777 size_t fini = tilde_find_suffix (name.substr (pos)); |
2926 | 778 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
779 // If both START and FINI are zero, we are all done. |
2926 | 780 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
781 if (! (start || fini)) |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
782 break; |
2926 | 783 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
784 // Expand the entire tilde word, and copy it into RESULT. |
2947 | 785 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
786 std::string tilde_word = name.substr (pos, fini); |
3040 | 787 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
788 pos += fini; |
2926 | 789 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
790 std::string expansion = tilde_expand_word (tilde_word); |
3040 | 791 |
8327
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
792 result.append (expansion); |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
793 } |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
794 |
4a7a943581d0
Fast return case for file_ops::tilde_expand
David Bateman <dbateman@free.fr>
parents:
8009
diff
changeset
|
795 return result; |
2926 | 796 } |
797 } | |
798 | |
799 // A vector version of the above. | |
800 | |
801 string_vector | |
802 file_ops::tilde_expand (const string_vector& names) | |
803 { | |
804 string_vector retval; | |
805 | |
806 int n = names.length (); | |
807 | |
808 retval.resize (n); | |
809 | |
810 for (int i = 0; i < n; i++) | |
811 retval[i] = file_ops::tilde_expand (names[i]); | |
812 | |
813 return retval; | |
814 } | |
1802 | 815 |
1765 | 816 int |
2926 | 817 file_ops::umask (mode_t mode) |
1765 | 818 { |
819 #if defined (HAVE_UMASK) | |
2926 | 820 return ::umask (mode); |
1765 | 821 #else |
822 return 0; | |
823 #endif | |
824 } | |
825 | |
1773 | 826 int |
3504 | 827 file_ops::unlink (const std::string& name) |
1773 | 828 { |
3504 | 829 std::string msg; |
2937 | 830 return unlink (name, msg); |
1773 | 831 } |
832 | |
2668 | 833 int |
3504 | 834 file_ops::unlink (const std::string& name, std::string& msg) |
2668 | 835 { |
3504 | 836 msg = std::string (); |
2668 | 837 |
2937 | 838 int status = -1; |
839 | |
840 #if defined (HAVE_UNLINK) | |
841 status = ::unlink (name.c_str ()); | |
2668 | 842 |
843 if (status < 0) | |
3504 | 844 { |
845 using namespace std; | |
846 msg = ::strerror (errno); | |
847 } | |
2937 | 848 #else |
849 msg = NOT_SUPPORTED ("unlink"); | |
850 #endif | |
2668 | 851 |
852 return status; | |
853 } | |
854 | |
7272 | 855 std::string |
856 file_ops::concat (const std::string& dir, const std::string& file) | |
857 { | |
858 return dir.empty () | |
859 ? file | |
860 : (is_dir_sep (dir[dir.length()-1]) | |
861 ? dir + file | |
8007
a2ab20ba78f7
make file_ops a proper singleton class
John W. Eaton <jwe@octave.org>
parents:
7520
diff
changeset
|
862 : dir + file_ops::dir_sep_char () + file); |
7272 | 863 } |