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