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