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