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