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