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