Name | Executed | Routines | % | Executed | Lines | % | Unexecuted |
/home/matt/eu/rds/include/std/filesys.e | 30 | 35 | 85.71% | 514 | 635 | 80.94% | 121 |
Routine | Executed | Lines | Unexecuted | |
disk_metrics() | 0 | 22 | 0.00% | 22 |
locate_file() | 39 | 51 | 76.47% | 12 |
clear_directory() | 22 | 31 | 70.97% | 9 |
temp_file() | 23 | 32 | 71.88% | 9 |
walk_dir() | 27 | 36 | 75.00% | 9 |
count_files() | 22 | 30 | 73.33% | 8 |
move_file() | 43 | 51 | 84.31% | 8 |
pathinfo() | 27 | 34 | 79.41% | 7 |
disk_size() | 29 | 34 | 85.29% | 5 |
file_length() | 0 | 5 | 0.00% | 5 |
copy_file() | 20 | 24 | 83.33% | 4 |
file_timestamp() | 0 | 4 | 0.00% | 4 |
remove_directory() | 27 | 31 | 87.10% | 4 |
canonical_path() | 39 | 42 | 92.86% | 3 |
driveid() | 0 | 3 | 0.00% | 3 |
defaultext() | 12 | 14 | 85.71% | 2 |
dir() | 18 | 20 | 90.00% | 2 |
init_curdir() | 0 | 2 | 0.00% | 2 |
rename_file() | 18 | 20 | 90.00% | 2 |
default_dir() | 4 | 5 | 80.00% | 1 |
absolute_path() | 7 | 7 | 100.00% | 0 |
chdir() | 2 | 2 | 100.00% | 0 |
create_directory() | 13 | 13 | 100.00% | 0 |
create_file() | 4 | 4 | 100.00% | 0 |
curdir() | 7 | 7 | 100.00% | 0 |
current_dir() | 2 | 2 | 100.00% | 0 |
delete_file() | 7 | 7 | 100.00% | 0 |
dir_size() | 7 | 7 | 100.00% | 0 |
dirname() | 6 | 6 | 100.00% | 0 |
file_exists() | 8 | 8 | 100.00% | 0 |
file_type() | 9 | 9 | 100.00% | 0 |
filebase() | 3 | 3 | 100.00% | 0 |
fileext() | 3 | 3 | 100.00% | 0 |
filename() | 3 | 3 | 100.00% | 0 |
xstat() | 2 | 2 | 100.00% | 0 |
# | Executed | |
1 | -- (c) Copyright - See License.txt | |
2 | -- | |
3 | --**** | |
4 | -- == File System | |
5 | -- | |
6 | -- Cross platform file operations for Euphoria | |
7 | -- | |
8 | -- < | |
9 | namespace filesys | |
10 | ||
11 | include std/dll.e | |
12 | ||
13 | include std/machine.e | |
14 | include std/wildcard.e | |
15 | include std/sort.e | |
16 | include std/search.e | |
17 | include std/machine.e | |
18 | include std/sequence.e | |
19 | include std/types.e | |
20 | include std/text.e | |
21 | include std/io.e | |
22 | include std/datetime.e as dt | |
23 | ||
24 | 101 | ifdef UNIX then |
25 | include std/get.e -- for disk_size() | |
26 | end ifdef | |
27 | ||
28 | constant | |
29 | 101 | M_DIR = 22, |
30 | 101 | M_CURRENT_DIR = 23, |
31 | 101 | M_CHDIR = 63 |
32 | ||
33 | 101 | ifdef WIN32 then |
34 | constant lib = open_dll("kernel32") | |
35 | constant xCopyFile = define_c_func(lib, "CopyFileA", {C_POINTER, C_POINTER, C_BOOL}, | |
36 | C_BOOL) | |
37 | constant xMoveFile = define_c_func(lib, "MoveFileA", {C_POINTER, C_POINTER}, C_BOOL) | |
38 | constant xDeleteFile = define_c_func(lib, "DeleteFileA", {C_POINTER}, C_BOOL) | |
39 | constant xCreateDirectory = define_c_func(lib, "CreateDirectoryA", | |
40 | {C_POINTER, C_POINTER}, C_BOOL) | |
41 | constant xRemoveDirectory = define_c_func(lib, "RemoveDirectoryA", {C_POINTER}, C_BOOL) | |
42 | constant xGetFileAttributes= define_c_func(lib, "GetFileAttributesA", {C_POINTER}, C_INT) -- N.B DWORD return fails this. | |
43 | constant xGetDiskFreeSpace = define_c_func(lib, "GetDiskFreeSpaceA", | |
44 | {C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_POINTER}, C_BOOL) | |
45 | ||
46 | elsifdef LINUX then | |
47 | 101 | constant lib = open_dll("") |
48 | ||
49 | elsifdef FREEBSD or SUNOS or OPENBSD then | |
50 | constant lib = open_dll("libc.so") | |
51 | ||
52 | elsifdef OSX then | |
53 | constant lib = open_dll("libc.dylib") | |
54 | ||
55 | elsedef | |
56 | constant xCopyFile = -1 | |
57 | constant xMoveFile = -1 | |
58 | constant xDeleteFile = -1 | |
59 | constant xCreateDirectory = -1 | |
60 | constant xRemoveDirectory = -1 | |
61 | constant xGetFileAttributes = -1 | |
62 | ||
63 | end ifdef | |
64 | ||
65 | 101 | ifdef LINUX then |
66 | 101 | constant xStatFile = define_c_func(lib, "__xstat", {C_INT, C_POINTER, C_POINTER}, C_INT) |
67 | elsifdef UNIX then | |
68 | constant xStatFile = define_c_func(lib, "stat", {C_POINTER, C_POINTER}, C_INT) | |
69 | end ifdef | |
70 | ||
71 | 101 | ifdef UNIX then |
72 | 101 | constant xMoveFile = define_c_func(lib, "rename", {C_POINTER, C_POINTER}, C_INT) |
73 | --constant xDeleteFile = define_c_func(lib, "remove", {C_POINTER}, C_LONG) | |
74 | 101 | constant xDeleteFile = define_c_func(lib, "unlink", {C_POINTER}, C_INT) |
75 | 101 | constant xCreateDirectory = define_c_func(lib, "mkdir", {C_POINTER, C_INT}, C_INT) |
76 | 101 | constant xRemoveDirectory = define_c_func(lib, "rmdir", {C_POINTER}, C_INT) |
77 | 101 | constant xGetFileAttributes = define_c_func(lib, "access", {C_POINTER, C_INT}, C_INT) |
78 | end ifdef | |
79 | ||
80 | ||
81 | --**** | |
82 | -- === Constants | |
83 | ||
84 | --**** | |
85 | -- Signature: | |
86 | -- public constant SLASH | |
87 | -- | |
88 | -- Description: | |
89 | -- Current platform's path separator character | |
90 | -- | |
91 | -- Comments: | |
92 | -- When on //Windows//, '~\\'. When on //Unix//, '/'. | |
93 | -- | |
94 | ||
95 | --**** | |
96 | -- Signature: | |
97 | -- public constant SLASHES | |
98 | -- | |
99 | -- Description: | |
100 | -- Current platform's possible path separators. This is slightly different | |
101 | -- in that on //Windows// the path separators variable contains | |
102 | -- ##~\~\## as well as ##~:## and ##/## as newer //Windows// versions support | |
103 | -- ##/## as a path separator. On //Unix// systems, it only contains ##/##. | |
104 | ||
105 | --**** | |
106 | -- Signature: | |
107 | -- public constant SLASHES | |
108 | -- | |
109 | -- Description: | |
110 | -- Current platform's possible path separators. This is slightly different | |
111 | -- in that on //Windows// the path separators variable contains | |
112 | -- ##~\~\## as well as ##~:## and ##/## as newer //Windows// versions support | |
113 | -- ##/## as a path separator. On //Unix// systems, it only contains ##/##. | |
114 | ||
115 | --**** | |
116 | -- Signature: | |
117 | -- public constant EOLSEP | |
118 | -- | |
119 | -- Description: | |
120 | -- Current platform's newline string: ##"\n"## on //Unix//, else ##"\r\n"##. | |
121 | ||
122 | --**** | |
123 | -- Signature: | |
124 | -- public constant EOL | |
125 | -- | |
126 | -- Description: | |
127 | -- All platform's newline character: ##'\n'##. When text lines are read the native | |
128 | -- platform's EOLSEP string is replaced by a single character EOL. | |
129 | ||
130 | --**** | |
131 | -- Signature: | |
132 | -- public constant PATHSEP | |
133 | -- | |
134 | -- Description: | |
135 | -- Current platform's path separator character: ##:## on //Unix//, else ##;##. | |
136 | ||
137 | --**** | |
138 | -- Signature: | |
139 | -- public constant NULLDEVICE | |
140 | -- | |
141 | -- Description: | |
142 | -- Current platform's null device path: ##/dev/null## on //Unix//, else ##NUL:##. | |
143 | ||
144 | --**** | |
145 | -- Signature: | |
146 | -- public constant SHARED_LIB_EXT | |
147 | -- | |
148 | -- Description: | |
149 | -- Current platform's shared library extension. For instance it can be ##dll##, | |
150 | -- ##so## or ##dylib## depending on the platform. | |
151 | ||
152 | 101 | ifdef UNIX then |
153 | 101 | public constant SLASH='/' |
154 | 101 | public constant SLASHES = "/" |
155 | 101 | public constant EOLSEP = "\n" |
156 | 101 | public constant PATHSEP = ':' |
157 | 101 | public constant NULLDEVICE = "/dev/null" |
158 | 101 | ifdef OSX then |
159 | public constant SHARED_LIB_EXT = "dylib" | |
160 | elsedef | |
161 | 101 | public constant SHARED_LIB_EXT = "so" |
162 | end ifdef | |
163 | ||
164 | elsifdef WINDOWS then | |
165 | ||
166 | public constant SLASH='\\' | |
167 | public constant SLASHES = "\\/:" | |
168 | public constant EOLSEP = "\r\n" | |
169 | public constant PATHSEP = ';' | |
170 | public constant NULLDEVICE = "NUL:" | |
171 | public constant SHARED_LIB_EXT = "dll" | |
172 | end ifdef | |
173 | ||
174 | 101 | public constant EOL = '\n' |
175 | ||
176 | --**** | |
177 | -- === Directory Handling | |
178 | ||
179 | public enum | |
180 | 101 | D_NAME, |
181 | 101 | D_ATTRIBUTES, |
182 | 101 | D_SIZE, |
183 | 101 | D_YEAR, |
184 | 101 | D_MONTH, |
185 | 101 | D_DAY, |
186 | 101 | D_HOUR, |
187 | 101 | D_MINUTE, |
188 | 101 | D_SECOND |
189 | ||
190 | --** | |
191 | -- Bad path error code. See [[:walk_dir]] | |
192 | ||
193 | 101 | public constant W_BAD_PATH = -1 -- error code |
194 | ||
195 | ||
196 | --** | |
197 | -- Return directory information for the specified file or directory. | |
198 | -- | |
199 | -- Parameters: | |
200 | -- # ##name## : a sequence, the name to be looked up in the file system. | |
201 | -- | |
202 | -- Returns: | |
203 | -- An **object**, -1 if no match found, else a sequence of sequence entries | |
204 | -- | |
205 | -- Errors: | |
206 | -- The length of ##name## should not exceed 1,024 characters. | |
207 | -- | |
208 | -- Comments: | |
209 | -- ##name## can also contain * and ? wildcards to select multiple files. | |
210 | -- | |
211 | -- The returned information is similar to what you would get from the DIR command. A sequence | |
212 | -- is returned where each element is a sequence that describes one file or subdirectory. | |
213 | -- | |
214 | -- If ##name## refers to a **directory** you may have entries for "." and "..", just as with the | |
215 | -- DIR command. If it refers to an existing **file**, and has no wildcards, then the returned | |
216 | -- sequence will have just one entry, i.e. its length will be 1. If ##name## contains wildcards | |
217 | -- you may have multiple entries. | |
218 | -- | |
219 | -- Each entry contains the name, attributes and file size as well as | |
220 | -- the year, month, day, hour, minute and second of the last modification. | |
221 | -- You can refer to the elements of an entry with the following constants: | |
222 | -- | |
223 | -- | |
224 | -- public constant | |
225 | -- -- File Attributes | |
226 | -- D_NAME = 1, | |
227 | -- D_ATTRIBUTES = 2, | |
228 | -- D_SIZE = 3, | |
229 | -- D_YEAR = 4, | |
230 | -- D_MONTH = 5, | |
231 | -- D_DAY = 6, | |
232 | -- D_HOUR = 7, | |
233 | -- D_MINUTE = 8, | |
234 | -- D_SECOND = 9 | |
235 | -- | |
236 | -- | |
237 | -- The attributes element is a string sequence containing characters chosen from: | |
238 | -- | |
239 | -- || Attribute || Description || | |
240 | -- | 'd' | directory | |
241 | -- | 'r' | read only file | |
242 | -- | 'h' | hidden file | |
243 | -- | 's' | system file | |
244 | -- | 'v' | volume-id entry | |
245 | -- | 'a' | archive file | |
246 | -- | |
247 | -- A normal file without special attributes would just have an empty string, "", in this field. | |
248 | -- | |
249 | -- The top level directory, e.g. c:\ does not have "." or ".." entries. | |
250 | -- | |
251 | -- This function is often used just to test if a file or directory exists. | |
252 | -- | |
253 | -- Under //WIN32//, st can have a long file or directory name anywhere in | |
254 | -- the path. | |
255 | -- | |
256 | -- Under //Unix//, the only attribute currently available is 'd'. | |
257 | -- | |
258 | -- //WIN32//: The file name returned in D_NAME will be a long file name. | |
259 | -- | |
260 | -- Example 1: | |
261 | -- | |
262 | -- d = dir(current_dir()) | |
263 | -- | |
264 | -- -- d might have: | |
265 | -- -- { | |
266 | -- -- {".", "d", 0 1994, 1, 18, 9, 30, 02}, | |
267 | -- -- {"..", "d", 0 1994, 1, 18, 9, 20, 14}, | |
268 | -- -- {"fred", "ra", 2350, 1994, 1, 22, 17, 22, 40}, | |
269 | -- -- {"sub", "d" , 0, 1993, 9, 20, 8, 50, 12} | |
270 | -- -- } | |
271 | -- | |
272 | -- d[3][D_NAME] would be "fred" | |
273 | -- | |
274 | -- | |
275 | -- See Also: | |
276 | -- [[:walk_dir]] | |
277 | -- | |
278 | ||
279 | 23 | |
280 | object dir_data, data, the_name, the_dir | |
281 | integer idx | |
282 | ||
283 | -- Did the user give a wildcard? If not, just return the standard dir. | |
284 | 23 | if eu:find('*', name) > 0 or eu:find('?', name) > 0 then |
285 | -- Empty if so that we can short circuit if * is found, otherwise | |
286 | -- we would have to run a search for * and ? even if * is found. | |
287 | else | |
288 | 21 | return machine_func(M_DIR, name) |
289 | end if | |
290 | ||
291 | -- Is there a path involved? | |
292 | 2 | if eu:find(SLASH, name) = 0 then |
293 | 1 | the_dir = "." |
294 | 1 | the_name = name |
295 | else | |
296 | -- Find a SLASH character and break the name there resulting in | |
297 | -- a directory and file name. | |
298 | 1 | idx = rfind(SLASH, name) |
299 | 1 | the_dir = name[1 .. idx] |
300 | 1 | the_name = name[idx+1 .. $] |
301 | end if | |
302 | ||
303 | -- Get directory contents | |
304 | 2 | dir_data = machine_func(M_DIR, the_dir) |
305 | ||
306 | -- Did an error occur? | |
307 | 2 | if atom(dir_data) then |
308 | 0 | return dir_data |
309 | end if | |
310 | ||
311 | 2 | data = {} |
312 | -- Filter the directory contents returning only those items | |
313 | -- matching name. | |
314 | 2 | for i = 1 to length(dir_data) do |
315 | 252 | if wildcard_file(the_name, dir_data[i][1]) then |
316 | 242 | data = append(data, dir_data[i]) |
317 | end if | |
318 | 252 | end for |
319 | ||
320 | 2 | if not length(data) then |
321 | -- no matches found, act like it doesn't exist | |
322 | 0 | return -1 |
323 | end if | |
324 | 2 | return data |
325 | end function | |
326 | ||
327 | --** | |
328 | -- Return the name of the current working directory. | |
329 | -- | |
330 | -- Returns: | |
331 | -- A **sequence**, the name of the current working directory | |
332 | -- | |
333 | -- Comments: | |
334 | -- There will be no slash or backslash on the end of the current directory, except under | |
335 | -- //Windows//, at the top-level of a drive, e.g. C:\ | |
336 | -- | |
337 | -- Example 1: | |
338 | -- | |
339 | -- sequence s | |
340 | -- s = current_dir() | |
341 | -- -- s would have "C:\EUPHORIA\DOC" if you were in that directory | |
342 | -- | |
343 | -- | |
344 | -- See Also: | |
345 | -- [[:dir]], [[:chdir]] | |
346 | ||
347 | 122 | |
348 | -- returns name of current working directory | |
349 | 122 | return machine_func(M_CURRENT_DIR, 0) |
350 | end function | |
351 | ||
352 | --** | |
353 | -- Set a new value for the current directory | |
354 | -- | |
355 | -- Parameters: | |
356 | -- ##newdir## : a sequence, the name for the new working directory. | |
357 | -- | |
358 | -- Returns: | |
359 | -- An **integer**, 0 on failure, 1 on success. | |
360 | -- | |
361 | -- Comments: | |
362 | -- By setting the current directory, you can refer to files in that directory using just | |
363 | -- the file name. | |
364 | -- | |
365 | -- The [[:current_dir]]() function will return the name of the current directory. | |
366 | -- | |
367 | -- On //WIN32// the current directory is a public property shared | |
368 | -- by all the processes running under one shell. On //Unix// a subprocess | |
369 | -- can change the current directory for itself, but this won't | |
370 | -- affect the current directory of its parent process. | |
371 | -- | |
372 | -- Example 1: | |
373 | -- | |
374 | -- if chdir("c:\\euphoria") then | |
375 | -- f = open("readme.doc", "r") | |
376 | -- else | |
377 | -- puts(STDERR, "Error: No euphoria directory?\n") | |
378 | -- end if | |
379 | -- | |
380 | -- | |
381 | -- See Also: | |
382 | -- [[:current_dir]], [[:dir]] | |
383 | ||
384 | 7 | |
385 | 7 | return machine_func(M_CHDIR, newdir) |
386 | end function | |
387 | ||
388 | -- Generalized recursive directory walker | |
389 | ||
390 | 4 | |
391 | -- Default directory sorting function for walk_dir(). | |
392 | -- * sorts by name * | |
393 | object d | |
394 | ||
395 | 4 | d = dir(path) |
396 | 4 | if atom(d) then |
397 | 0 | return d |
398 | else | |
399 | -- sort by name | |
400 | 4 | return sort(d) |
401 | end if | |
402 | end function | |
403 | ||
404 | -- override the dir sorting function with your own routine id | |
405 | 101 | constant DEFAULT_DIR_SOURCE = -2 |
406 | ||
407 | -- it's better not to use routine_id() here, | |
408 | -- or else users will have to bind with clear routine names | |
409 | ||
410 | --** | |
411 | -- **Deprecated**, so therefore not documented. | |
412 | 101 | public integer my_dir = DEFAULT_DIR_SOURCE |
413 | ||
414 | --** | |
415 | -- Generalized Directory Walker | |
416 | -- | |
417 | -- Parameters: | |
418 | -- # ##path_name## : a sequence, the name of the directory to walk through | |
419 | -- # ##your_function## : the routine id of a function that will receive each path | |
420 | -- returned from the result of ##dir_source##, one at a time. | |
421 | -- # ##scan_subdirs## : an optional integer, 1 to also walk though subfolders, 0 (the default) to skip them all. | |
422 | -- # ##dir_source## : an optional integer. A routine_id of a user-defined routine that | |
423 | -- returns the list of paths to pass to ##your_function##. If omitted, | |
424 | -- the [[:dir]]() function is used. | |
425 | -- | |
426 | -- Returns: | |
427 | -- An **object**, | |
428 | -- * 0 on success | |
429 | -- * W_BAD_PATH: an error occurred | |
430 | -- * anything else: the custom function returned something to stop [[:walk_dir]](). | |
431 | -- | |
432 | -- Comments: | |
433 | -- This routine will "walk" through a directory named ##path_name##. For each entry in the | |
434 | -- directory, it will call a function, whose routine_id is ##your_function##. | |
435 | -- If ##scan_subdirs## is non-zero (TRUE), then the subdirectories in | |
436 | -- ##path_name## will be walked through recursively in the very same way. | |
437 | -- | |
438 | -- The routine that you supply should accept two sequences, the path name and dir() entry for | |
439 | -- each file and subdirectory. It should return 0 to keep going, or non-zero to stop | |
440 | -- ##walk_dir##(). Returning ##W_BAD_PATH## is taken as denoting some error. | |
441 | -- | |
442 | -- This mechanism allows you to write a simple function that handles one file at a time, | |
443 | -- while ##walk_dir##() handles the process of walking through all the files and subdirectories. | |
444 | -- | |
445 | -- By default, the files and subdirectories will be visited in alphabetical order. To use | |
446 | -- a different order, use the ##dir_source## to pass the routine_id of your own modified | |
447 | -- [[:dir]] function that sorts the directory entries differently. | |
448 | -- | |
449 | -- The path that you supply to ##walk_dir()## must not contain wildcards (* or ?). Only a | |
450 | -- single directory (and its subdirectories) can be searched at one time. | |
451 | -- | |
452 | -- For non-unix systems, any '/' characters in ##path_name## are replaced with '\'. | |
453 | -- | |
454 | -- All trailing slash and whitespace characters are removed from ##path_name##. | |
455 | -- | |
456 | -- Example 1: | |
457 | -- | |
458 | -- function look_at(sequence path_name, sequence item) | |
459 | -- -- this function accepts two sequences as arguments | |
460 | -- -- it displays all C/C++ source files and their sizes | |
461 | -- if find('d', item[D_ATTRIBUTES]) then | |
462 | -- return 0 -- Ignore directories | |
463 | -- end if | |
464 | -- if not find(fileext(item[D_NAME]), {"c,h,cpp,hpp,cp"}) then | |
465 | -- return 0 -- ignore non-C/C++ files | |
466 | -- end if | |
467 | -- printf(STDOUT, "%s%s%s: %d\n", | |
468 | -- {path_name, SLASH, item[D_NAME], item[D_SIZE]}) | |
469 | -- return 0 -- keep going | |
470 | -- end function | |
471 | -- | |
472 | -- function mysort(sequence path) | |
473 | -- object d | |
474 | -- | |
475 | -- d = dir(path) | |
476 | -- if atom(d) then | |
477 | -- return d | |
478 | -- end if | |
479 | -- -- Sort in descending file size. | |
480 | -- return sort_columns(d, {-D_SIZE}) | |
481 | -- end function | |
482 | -- | |
483 | -- exit_code = walk_dir("C:\\MYFILES\\", routine_id("look_at"), TRUE, routine_id("mysort")) | |
484 | -- | |
485 | -- | |
486 | -- See Also: | |
487 | -- [[:dir]], [[:sort]], [[:sort_columns]] | |
488 | ||
489 | 4 | |
490 | object d, abort_now | |
491 | object orig_func | |
492 | 4 | sequence user_data = {path_name, 0} |
493 | object source_orig_func | |
494 | object source_user_data | |
495 | ||
496 | 4 | orig_func = your_function |
497 | 4 | if sequence(your_function) then |
498 | 1 | user_data = append(user_data, your_function[2]) |
499 | 1 | your_function = your_function[1] |
500 | end if | |
501 | ||
502 | 4 | source_orig_func = dir_source |
503 | 4 | if sequence(dir_source) then |
504 | 0 | source_user_data = dir_source[2] |
505 | 0 | dir_source = dir_source[1] |
506 | end if | |
507 | ||
508 | -- get the full directory information | |
509 | 4 | if not equal(dir_source, NO_ROUTINE_ID) then |
510 | 0 | if atom(source_orig_func) then |
511 | 0 | d = call_func(dir_source, {path_name}) |
512 | else | |
513 | 0 | d = call_func(dir_source, {path_name, source_user_data}) |
514 | end if | |
515 | ||
516 | 4 | elsif my_dir = DEFAULT_DIR_SOURCE then |
517 | 4 | d = default_dir(path_name) |
518 | else | |
519 | 0 | d = call_func(my_dir, {path_name}) |
520 | end if | |
521 | 4 | if atom(d) then |
522 | 0 | return W_BAD_PATH |
523 | end if | |
524 | ||
525 | -- trim any trailing blanks or '\' '/' characters from the path | |
526 | 4 | ifdef not UNIX then |
527 | path_name = replace_all(path_name, '/', '\\') | |
528 | end ifdef | |
529 | 4 | path_name = trim_tail(path_name, {' ', SLASH, '\n'}) |
530 | 4 | user_data[1] = path_name |
531 | ||
532 | 4 | for i = 1 to length(d) do |
533 | 18 | if eu:find(d[i][D_NAME], {".", ".."}) then |
534 | 8 | continue |
535 | end if | |
536 | ||
537 | 10 | user_data[2] = d[i] |
538 | 10 | abort_now = call_func(your_function, user_data) |
539 | 10 | if not equal(abort_now, 0) then |
540 | 0 | return abort_now |
541 | end if | |
542 | ||
543 | 10 | if eu:find('d', d[i][D_ATTRIBUTES]) then |
544 | -- a directory | |
545 | 4 | if scan_subdirs then |
546 | 2 | abort_now = walk_dir(path_name & SLASH & d[i][D_NAME], |
547 | orig_func, scan_subdirs, source_orig_func) | |
548 | ||
549 | 2 | if not equal(abort_now, 0) and |
550 | not equal(abort_now, W_BAD_PATH) then | |
551 | -- allow BAD PATH, user might delete a file or directory | |
552 | 0 | return abort_now |
553 | end if | |
554 | end if | |
555 | end if | |
556 | 10 | end for |
557 | 4 | return 0 |
558 | end function | |
559 | ||
560 | ||
561 | --** | |
562 | -- Create a new directory. | |
563 | -- | |
564 | -- Parameters: | |
565 | -- # ##name## : a sequence, the name of the new directory to create | |
566 | -- # ##mode## : on //Unix// systems, permissions for the new directory. Default is | |
567 | -- 448 (all rights for owner, none for others). | |
568 | -- # ##mkparent## : If true (default) the parent directories are also created | |
569 | -- if needed. | |
570 | -- | |
571 | -- Returns: | |
572 | -- An **integer**, 0 on failure, 1 on success. | |
573 | -- | |
574 | -- Comments: | |
575 | -- ##mode## is ignored on non-Unix platforms. | |
576 | -- | |
577 | -- Example 1: | |
578 | -- | |
579 | -- if not create_directory("the_new_folder") then | |
580 | -- crash("Filesystem problem - could not create the new folder") | |
581 | -- end if | |
582 | -- | |
583 | -- -- This example will also create "myapp/" and "myapp/interface/" if they don't exist. | |
584 | -- if not create_directory("myapp/interface/letters") then | |
585 | -- crash("Filesystem problem - could not create the new folder") | |
586 | -- end if | |
587 | -- | |
588 | -- -- This example will NOT create "myapp/" and "myapp/interface/" if they don't exist. | |
589 | -- if not create_directory("myapp/interface/letters",,0) then | |
590 | -- crash("Filesystem problem - could not create the new folder") | |
591 | -- end if | |
592 | -- | |
593 | -- | |
594 | -- See Also: | |
595 | -- [[:remove_directory]], [[:chdir]] | |
596 | ||
597 | 11 | |
598 | atom pname, ret | |
599 | integer pos | |
600 | ||
601 | 11 | if length(name) = 0 then |
602 | 2 | return 0 -- failed |
603 | end if | |
604 | ||
605 | -- Remove any trailing slash. | |
606 | 9 | if name[$] = SLASH then |
607 | 1 | name = name[1 .. $-1] |
608 | end if | |
609 | ||
610 | 9 | if mkparent != 0 then |
611 | 9 | pos = rfind(SLASH, name) |
612 | 9 | if pos != 0 then |
613 | 6 | ret = create_directory(name[1.. pos-1], mode, mkparent) |
614 | end if | |
615 | end if | |
616 | ||
617 | 9 | pname = allocate_string(name) |
618 | ||
619 | 9 | ifdef UNIX then |
620 | 9 | ret = not c_func(xCreateDirectory, {pname, mode}) |
621 | elsifdef WIN32 then | |
622 | ret = c_func(xCreateDirectory, {pname, 0}) | |
623 | mode = mode -- get rid of not used warning | |
624 | end ifdef | |
625 | ||
626 | 9 | return ret |
627 | end function | |
628 | ||
629 | --** | |
630 | -- Create a new file. | |
631 | -- | |
632 | -- Parameters: | |
633 | -- # ##name## : a sequence, the name of the new file to create | |
634 | -- | |
635 | -- Returns: | |
636 | -- An **integer**, 0 on failure, 1 on success. | |
637 | -- | |
638 | -- Comments: | |
639 | -- * The created file will be empty, that is it has a length of zero. | |
640 | -- * The created file will not be open when this returns. | |
641 | -- | |
642 | -- Example 1: | |
643 | -- | |
644 | -- if not create_file("the_new_file") then | |
645 | -- crash("Filesystem problem - could not create the new file") | |
646 | -- end if | |
647 | -- | |
648 | -- | |
649 | -- See Also: | |
650 | -- [[:create_directory]] | |
651 | ||
652 | 5 | |
653 | 5 | integer fh = open(name, "wb") |
654 | 5 | close(fh) |
655 | 5 | return (fh != -1) |
656 | end function | |
657 | ||
658 | --** | |
659 | -- Delete a file. | |
660 | -- | |
661 | -- Parameters: | |
662 | -- # ##name## : a sequence, the name of the file to delete. | |
663 | -- | |
664 | -- Returns: | |
665 | -- An **integer**, 0 on failure, 1 on success. | |
666 | ||
667 | 57 | |
668 | ||
669 | 57 | atom pfilename = allocate_string(name) |
670 | 57 | integer success = c_func(xDeleteFile, {pfilename}) |
671 | ||
672 | 57 | ifdef UNIX then |
673 | 57 | success = not success |
674 | end ifdef | |
675 | ||
676 | 57 | free(pfilename) |
677 | ||
678 | 57 | return success |
679 | end function | |
680 | ||
681 | --** | |
682 | -- Returns the current directory, with a trailing SLASH | |
683 | -- | |
684 | -- Parameters: | |
685 | -- # ##drive_id## : For non-Unix systems only. This is the Drive letter to | |
686 | -- to get the current directory of. If omitted, the current drive is used. | |
687 | -- | |
688 | -- Returns: | |
689 | -- A **sequence**, the current directory. | |
690 | -- | |
691 | -- Comment: | |
692 | -- Windows maintain a current directory for each disk drive. You | |
693 | -- would use this routine if you wanted the current directory for a drive that | |
694 | -- may not be the current drive. | |
695 | -- | |
696 | -- For Unix systems, this is simply ignored because there is only one current | |
697 | -- directory at any time on Unix. | |
698 | -- | |
699 | -- Note: | |
700 | -- This always ensures that the returned value has a trailing SLASH | |
701 | -- character. | |
702 | -- | |
703 | -- Example 1: | |
704 | -- | |
705 | -- res = curdir('D') -- Find the current directory on the D: drive. | |
706 | -- -- res might be "D:\backup\music\" | |
707 | -- res = curdir() -- Find the current directory on the current drive. | |
708 | -- -- res might be "C:\myapp\work\" | |
709 | -- | |
710 | ||
711 | 112 | |
712 | ||
713 | sequence lCurDir | |
714 | 112 | ifdef not LINUX then |
715 | sequence lOrigDir = "" | |
716 | sequence lDrive | |
717 | object void | |
718 | ||
719 | if t_alpha(drive_id) then | |
720 | lOrigDir = current_dir() | |
721 | lDrive = " " | |
722 | lDrive[1] = drive_id | |
723 | lDrive[2] = ':' | |
724 | if chdir(lDrive) = 0 then | |
725 | lOrigDir = "" | |
726 | end if | |
727 | end if | |
728 | end ifdef | |
729 | ||
730 | 112 | lCurDir = current_dir() |
731 | 112 | ifdef not LINUX then |
732 | if length(lOrigDir) > 0 then | |
733 | void = chdir(lOrigDir[1..2]) | |
734 | end if | |
735 | end ifdef | |
736 | ||
737 | -- Ensure that it ends in a path separator. | |
738 | 112 | if (lCurDir[$] != SLASH) then |
739 | 112 | lCurDir &= SLASH |
740 | end if | |
741 | ||
742 | 112 | return lCurDir |
743 | end function | |
744 | ||
745 | 101 | sequence InitCurDir = curdir() -- Capture the original PWD |
746 | ||
747 | --** | |
748 | -- Returns the original current directory | |
749 | -- | |
750 | -- Parameters: | |
751 | -- # None. | |
752 | -- | |
753 | -- Returns: | |
754 | -- A **sequence**, the current directory at the time the program started running. | |
755 | -- | |
756 | -- Comment: | |
757 | -- You would use this if the program might change the current directory during | |
758 | -- its processing and you wanted to return to the original directory. | |
759 | -- | |
760 | -- Note: | |
761 | -- This always ensures that the returned value has a trailing SLASH | |
762 | -- character. | |
763 | -- | |
764 | -- Example 1: | |
765 | -- | |
766 | -- res = init_curdir() -- Find the original current directory. | |
767 | -- | |
768 | ||
769 | 0 | |
770 | 0 | return InitCurDir |
771 | end function | |
772 | ||
773 | --- TODO | |
774 | --- copy_directory( srcpath, destpath, structonly = 0) | |
775 | ||
776 | --** | |
777 | -- Clear (delete) a directory of all files, but retaining sub-directories. | |
778 | -- | |
779 | -- Parameters: | |
780 | -- # ##name## : a sequence, the name of the directory whose files you want to remove. | |
781 | -- # ##recurse## : an integer, whether or not to remove files in the | |
782 | -- directory's sub-directories. If 0 then this function is identical | |
783 | -- to remove_directory(). If 1, then we recursively delete the | |
784 | -- directory and its contents. Defaults to 1. | |
785 | -- | |
786 | -- Returns: | |
787 | -- An **integer**, 0 on failure, otherwise the number of files plus 1. | |
788 | -- | |
789 | -- Comment: | |
790 | -- This never removes a directory. It only ever removes files. It is used to | |
791 | -- clear a directory structure of all existing files, leaving the structure | |
792 | -- intact. | |
793 | -- | |
794 | -- Example 1: | |
795 | -- | |
796 | -- integer cnt = clear_directory("the_old_folder") | |
797 | -- if cnt = 0 then | |
798 | -- crash("Filesystem problem - could not remove one or more of the files.") | |
799 | -- end if | |
800 | -- printf(1, "Number of files removed: %d\n", cnt - 1) | |
801 | -- | |
802 | -- | |
803 | -- See Also: | |
804 | -- [[:remove_directory]], [[:delete_file]] | |
805 | ||
806 | 1 | |
807 | object files | |
808 | integer ret | |
809 | ||
810 | 1 | if length(path) > 0 then |
811 | 1 | if path[$] = SLASH then |
812 | 0 | path = path[1 .. $-1] |
813 | end if | |
814 | end if | |
815 | ||
816 | 1 | if length(path) = 0 then |
817 | 0 | return 0 -- Nothing specified to clear. Not safe to assume anything. |
818 | -- (btw, not allowed to clear root directory) | |
819 | end if | |
820 | 1 | ifdef WIN32 then |
821 | if length(path) = 2 then | |
822 | if path[2] = ':' then | |
823 | return 0 -- nothing specified to delete | |
824 | end if | |
825 | end if | |
826 | end ifdef | |
827 | ||
828 | ||
829 | 1 | files = dir(path) |
830 | 1 | if atom(files) then |
831 | 0 | return 0 |
832 | end if | |
833 | ||
834 | 1 | ifdef WINDOWS then |
835 | if length( files ) < 3 then | |
836 | return 0 -- Supplied name was not a directory | |
837 | end if | |
838 | if not equal(files[1][D_NAME], ".") then | |
839 | return 0 -- Supplied name was not a directory | |
840 | end if | |
841 | if not eu:find('d', files[1][D_ATTRIBUTES]) then | |
842 | return 0 -- Supplied name was not a directory | |
843 | end if | |
844 | elsedef | |
845 | 1 | if length( files ) < 2 then |
846 | 0 | return 0 -- not a directory |
847 | end if | |
848 | end ifdef | |
849 | ||
850 | 1 | ret = 1 |
851 | 1 | path &= SLASH |
852 | ||
853 | 1 | ifdef WINDOWS then |
854 | for i = 3 to length(files) do | |
855 | if eu:find('d', files[i][D_ATTRIBUTES]) then | |
856 | if recurse then | |
857 | integer cnt = clear_directory(path & files[i][D_NAME], recurse) | |
858 | if cnt = 0 then | |
859 | return 0 | |
860 | end if | |
861 | ret += cnt | |
862 | else | |
863 | continue | |
864 | end if | |
865 | else | |
866 | if delete_file(path & files[i][D_NAME]) = 0 then | |
867 | return 0 | |
868 | end if | |
869 | ret += 1 | |
870 | end if | |
871 | end for | |
872 | elsedef | |
873 | 1 | for i = 1 to length(files) do |
874 | 5 | if files[i][D_NAME][1] = '.' then |
875 | 2 | continue |
876 | end if | |
877 | 3 | if eu:find('d', files[i][D_ATTRIBUTES]) then |
878 | 2 | if recurse then |
879 | 0 | integer cnt = clear_directory(path & files[i][D_NAME], recurse) |
880 | 0 | if cnt = 0 then |
881 | 0 | return 0 |
882 | end if | |
883 | 0 | ret += cnt |
884 | else | |
885 | 2 | continue |
886 | end if | |
887 | else | |
888 | 1 | if delete_file(path & files[i][D_NAME]) = 0 then |
889 | 0 | return 0 |
890 | end if | |
891 | 1 | ret += 1 |
892 | end if | |
893 | 1 | end for |
894 | end ifdef | |
895 | 1 | return ret |
896 | end function | |
897 | ||
898 | --** | |
899 | -- Remove a directory. | |
900 | -- | |
901 | -- Parameters: | |
902 | -- # ##name## : a sequence, the name of the directory to remove. | |
903 | -- # ##force## : an integer, if 1 this will also remove files and | |
904 | -- sub-directories in the directory. The default is | |
905 | -- 0, which means that it will only remove the | |
906 | -- directory if it is already empty. | |
907 | -- | |
908 | -- Returns: | |
909 | -- An **integer**, 0 on failure, 1 on success. | |
910 | -- | |
911 | -- Example 1: | |
912 | -- | |
913 | -- if not remove_directory("the_old_folder") then | |
914 | -- crash("Filesystem problem - could not remove the old folder") | |
915 | -- end if | |
916 | -- | |
917 | -- | |
918 | -- See Also: | |
919 | -- [[:create_directory]], [[:chdir]], [[:clear_directory]] | |
920 | ||
921 | 3 | |
922 | atom pname, ret | |
923 | object files | |
924 | 3 | integer D_NAME = 1, D_ATTRIBUTES = 2 |
925 | ||
926 | -- Remove any trailing slash | |
927 | 3 | if length(dir_name) > 0 then |
928 | 3 | if dir_name[$] = SLASH then |
929 | 2 | dir_name = dir_name[1 .. $-1] |
930 | end if | |
931 | end if | |
932 | ||
933 | 3 | if length(dir_name) = 0 then |
934 | 0 | return 0 -- nothing specified to delete. |
935 | -- (not allowed to delete root directory btw) | |
936 | end if | |
937 | ||
938 | 3 | ifdef WIN32 then |
939 | if length(dir_name) = 2 then | |
940 | if dir_name[2] = ':' then | |
941 | return 0 -- nothing specified to delete | |
942 | end if | |
943 | end if | |
944 | end ifdef | |
945 | ||
946 | 3 | files = dir(dir_name) |
947 | 3 | if atom(files) then |
948 | 0 | return 0 |
949 | end if | |
950 | 3 | ifdef WINDOWS then |
951 | if length( files ) <= 2 then | |
952 | return 0 -- Supplied dir_name was not a directory | |
953 | end if | |
954 | ||
955 | if not equal(files[1][D_NAME], ".") then | |
956 | return 0 -- Supplied name was not a directory | |
957 | end if | |
958 | if not eu:find('d', files[1][D_ATTRIBUTES]) then | |
959 | return 0 -- Supplied name was not a directory | |
960 | end if | |
961 | if length(files) > 2 then | |
962 | if not force then | |
963 | return 0 -- Directory is not already emptied. | |
964 | end if | |
965 | end if | |
966 | elsedef | |
967 | 3 | if length( files ) < 2 then |
968 | 0 | return 0 |
969 | end if | |
970 | end ifdef | |
971 | ||
972 | 3 | dir_name &= SLASH |
973 | 3 | ifdef WINDOWS then |
974 | for i = 3 to length(files) do | |
975 | if eu:find('d', files[i][D_ATTRIBUTES]) then | |
976 | ret = remove_directory(dir_name & files[i][D_NAME] & SLASH, force) | |
977 | else | |
978 | ret = delete_file(dir_name & files[i][D_NAME]) | |
979 | end if | |
980 | if not ret then | |
981 | return 0 | |
982 | end if | |
983 | ||
984 | end for | |
985 | elsedef | |
986 | 3 | for i = 1 to length(files) do |
987 | 12 | if files[i][D_NAME][1] = '.' then |
988 | 6 | continue |
989 | end if | |
990 | 6 | if eu:find('d', files[i][D_ATTRIBUTES]) then |
991 | 2 | ret = remove_directory(dir_name & files[i][D_NAME] & SLASH, force) |
992 | else | |
993 | 4 | ret = delete_file(dir_name & files[i][D_NAME]) |
994 | end if | |
995 | 6 | if not ret then |
996 | 0 | return 0 |
997 | end if | |
998 | 6 | end for |
999 | end ifdef | |
1000 | 3 | pname = allocate_string(dir_name) |
1001 | 3 | ret = c_func(xRemoveDirectory, {pname}) |
1002 | 3 | ifdef UNIX then |
1003 | 3 | ret = not ret |
1004 | end ifdef | |
1005 | 3 | free(pname) |
1006 | 3 | return ret |
1007 | end function | |
1008 | ||
1009 | ||
1010 | --**** | |
1011 | -- === File name parsing | |
1012 | ||
1013 | public enum | |
1014 | 101 | PATH_DIR, |
1015 | 101 | PATH_FILENAME, |
1016 | 101 | PATH_BASENAME, |
1017 | 101 | PATH_FILEEXT, |
1018 | 101 | PATH_DRIVEID |
1019 | ||
1020 | --** | |
1021 | -- Parse a fully qualified pathname. | |
1022 | -- Parameters: | |
1023 | -- # ##path## : a sequence, the path to parse | |
1024 | -- | |
1025 | -- Returns: | |
1026 | -- A **sequence**, of length 5. Each of these elements is a string: | |
1027 | -- * The path name | |
1028 | -- * The full unqualified file name | |
1029 | -- * the file name, without extension | |
1030 | -- * the file extension | |
1031 | -- * the drive id | |
1032 | -- | |
1033 | -- Comments: | |
1034 | -- | |
1035 | -- The host operating system path separator is used in the parsing. | |
1036 | -- | |
1037 | -- Example 1: | |
1038 | -- | |
1039 | -- -- WIN32 | |
1040 | -- info = pathinfo("C:\\euphoria\\docs\\readme.txt") | |
1041 | -- -- info is {"C:\\euphoria\\docs", "readme.txt", "readme", "txt", "C"} | |
1042 | -- | |
1043 | -- | |
1044 | -- Example 2: | |
1045 | -- | |
1046 | -- -- Unix variants | |
1047 | -- info = pathinfo("/opt/euphoria/docs/readme.txt") | |
1048 | -- -- info is {"/opt/euphoria/docs", "readme.txt", "readme", "txt", ""} | |
1049 | -- | |
1050 | -- | |
1051 | -- Example 3: | |
1052 | -- | |
1053 | -- -- no extension | |
1054 | -- info = pathinfo("/opt/euphoria/docs/readme") | |
1055 | -- -- info is {"/opt/euphoria/docs", "readme", "readme", "", ""} | |
1056 | -- | |
1057 | -- | |
1058 | -- See Also: | |
1059 | -- [[:driveid]], [[:dirname]], [[:filename]], [[:fileext]], | |
1060 | -- [[:PATH_BASENAME]], [[:PATH_DIR]], [[:PATH_DRIVEID]], [[:PATH_FILEEXT]], | |
1061 | -- [[:PATH_FILENAME]] | |
1062 | ||
1063 | 29 | |
1064 | integer slash, period, ch | |
1065 | sequence dir_name, file_name, file_ext, file_full, drive_id | |
1066 | ||
1067 | 29 | dir_name = "" |
1068 | 29 | file_name = "" |
1069 | 29 | file_ext = "" |
1070 | 29 | file_full = "" |
1071 | 29 | drive_id = "" |
1072 | ||
1073 | 29 | slash = 0 |
1074 | 29 | period = 0 |
1075 | ||
1076 | 29 | for i = length(path) to 1 by -1 do |
1077 | 291 | ch = path[i] |
1078 | 291 | if period = 0 and ch = '.' then |
1079 | 24 | period = i |
1080 | 267 | elsif eu:find(ch, SLASHES) then |
1081 | 13 | slash = i |
1082 | 13 | exit |
1083 | end if | |
1084 | 278 | end for |
1085 | ||
1086 | 29 | if slash > 0 then |
1087 | 13 | dir_name = path[1..slash-1] |
1088 | ||
1089 | 13 | ifdef not UNIX then |
1090 | ch = eu:find(':', dir_name) | |
1091 | if ch != 0 then | |
1092 | drive_id = dir_name[1..ch-1] | |
1093 | dir_name = dir_name[ch+1..$] | |
1094 | end if | |
1095 | end ifdef | |
1096 | end if | |
1097 | 29 | if period > 0 then |
1098 | 24 | file_name = path[slash+1..period-1] |
1099 | 24 | file_ext = path[period+1..$] |
1100 | 24 | file_full = file_name & '.' & file_ext |
1101 | else | |
1102 | 5 | file_name = path[slash+1..$] |
1103 | 5 | file_full = file_name |
1104 | end if | |
1105 | ||
1106 | 29 | if std_slash != 0 then |
1107 | 0 | if std_slash < 0 then |
1108 | 0 | std_slash = SLASH |
1109 | 0 | ifdef UNIX then |
1110 | 0 | sequence from_slash = "\\" |
1111 | elsedef | |
1112 | sequence from_slash = "/" | |
1113 | end ifdef | |
1114 | 0 | dir_name = replace_all(dir_name, from_slash, std_slash) |
1115 | else | |
1116 | 0 | dir_name = replace_all(dir_name, "\\", std_slash) |
1117 | 0 | dir_name = replace_all(dir_name, "/", std_slash) |
1118 | end if | |
1119 | end if | |
1120 | ||
1121 | 29 | return {dir_name, file_full, file_name, file_ext, drive_id} |
1122 | end function | |
1123 | ||
1124 | --** | |
1125 | -- Return the directory name of a fully qualified filename | |
1126 | -- | |
1127 | -- Parameters: | |
1128 | -- # ##path## : the path from which to extract information | |
1129 | -- # ##pcd## : If not zero and there is no directory name in ##path## | |
1130 | -- then "." is returned. The default (0) will just return | |
1131 | -- any directory name in ##path##. | |
1132 | -- | |
1133 | -- Returns: | |
1134 | -- A **sequence**, the full file name part of ##path##. | |
1135 | -- | |
1136 | -- Comments: | |
1137 | -- The host operating system path separator is used. | |
1138 | -- | |
1139 | -- Example 1: | |
1140 | -- | |
1141 | -- fname = dirname("/opt/euphoria/docs/readme.txt") | |
1142 | -- -- fname is "/opt/euphoria/docs" | |
1143 | -- | |
1144 | -- | |
1145 | -- See Also: | |
1146 | -- [[:driveid]], [[:filename]], [[:pathinfo]] | |
1147 | ||
1148 | 16 | |
1149 | sequence data | |
1150 | 16 | data = pathinfo(path) |
1151 | 16 | if pcd then |
1152 | 3 | if length(data[1]) = 0 then |
1153 | 3 | return "." |
1154 | end if | |
1155 | end if | |
1156 | 13 | return data[1] |
1157 | end function | |
1158 | ||
1159 | --** | |
1160 | -- Return the file name portion of a fully qualified filename | |
1161 | -- | |
1162 | -- Parameters: | |
1163 | -- # ##path## : the path from which to extract information | |
1164 | -- | |
1165 | -- Returns: | |
1166 | -- A **sequence**, the file name part of ##path##. | |
1167 | -- | |
1168 | -- Comments: | |
1169 | -- The host operating system path separator is used. | |
1170 | -- | |
1171 | -- Example 1: | |
1172 | -- | |
1173 | -- fname = filename("/opt/euphoria/docs/readme.txt") | |
1174 | -- -- fname is "readme.txt" | |
1175 | -- | |
1176 | -- | |
1177 | -- See Also: | |
1178 | -- [[:pathinfo]], [[:filebase]], [[:fileext]] | |
1179 | ||
1180 | 3 | |
1181 | sequence data | |
1182 | ||
1183 | 3 | data = pathinfo(path) |
1184 | ||
1185 | 3 | return data[2] |
1186 | end function | |
1187 | ||
1188 | --** | |
1189 | -- Return the base filename of path. | |
1190 | -- | |
1191 | -- Parameters: | |
1192 | -- # ##path## : the path from which to extract information | |
1193 | -- | |
1194 | -- Returns: | |
1195 | -- A **sequence**, the base file name part of ##path##. | |
1196 | -- | |
1197 | -- TODO: Test | |
1198 | -- | |
1199 | -- Example 1: | |
1200 | -- | |
1201 | -- base = filebase("/opt/euphoria/readme.txt") | |
1202 | -- -- base is "readme" | |
1203 | -- | |
1204 | -- | |
1205 | -- See Also: | |
1206 | -- [[:pathinfo]], [[:filename]], [[:fileext]] | |
1207 | ||
1208 | 1 | |
1209 | sequence data | |
1210 | ||
1211 | 1 | data = pathinfo(path) |
1212 | ||
1213 | 1 | return data[3] |
1214 | end function | |
1215 | ||
1216 | --** | |
1217 | -- Return the file extension of a fully qualified filename | |
1218 | -- | |
1219 | -- Parameters: | |
1220 | -- # ##path## : the path from which to extract information | |
1221 | -- | |
1222 | -- Returns: | |
1223 | -- A **sequence**, the file extension part of ##path##. | |
1224 | -- | |
1225 | -- Comments: | |
1226 | -- The host operating system path separator is used. | |
1227 | -- | |
1228 | -- Example 1: | |
1229 | -- | |
1230 | -- fname = fileext("/opt/euphoria/docs/readme.txt") | |
1231 | -- -- fname is "txt" | |
1232 | -- | |
1233 | -- | |
1234 | -- See Also: | |
1235 | -- [[:pathinfo]], [[:filename]], [[:filebase]] | |
1236 | ||
1237 | 5 | |
1238 | sequence data | |
1239 | 5 | data = pathinfo(path) |
1240 | 5 | return data[4] |
1241 | end function | |
1242 | ||
1243 | --** | |
1244 | -- Return the drive letter of the path on //WIN32// platforms. | |
1245 | -- | |
1246 | -- Parameters: | |
1247 | -- # ##path## : the path from which to extract information | |
1248 | -- | |
1249 | -- Returns: | |
1250 | -- A **sequence**, the file extension part of ##path##. | |
1251 | -- | |
1252 | -- TODO: Test | |
1253 | -- | |
1254 | -- Example: | |
1255 | -- | |
1256 | -- letter = driveid("C:\\EUPHORIA\\Readme.txt") | |
1257 | -- -- letter is "C" | |
1258 | -- | |
1259 | -- | |
1260 | -- See Also: | |
1261 | -- [[:pathinfo]], [[:dirname]], [[:filename]] | |
1262 | ||
1263 | 0 | |
1264 | sequence data | |
1265 | 0 | data = pathinfo(path) |
1266 | 0 | return data[5] |
1267 | end function | |
1268 | ||
1269 | --** | |
1270 | -- Returns the supplied filepath with the supplied extension, if | |
1271 | -- the filepath does not have an extension already. | |
1272 | -- | |
1273 | -- Parameters: | |
1274 | -- # ##path## : the path to check for an extension. | |
1275 | -- # ##defext## : the extension to add if ##path## does not have one. | |
1276 | -- | |
1277 | -- Returns: | |
1278 | -- A **sequence**, the path with an extension. | |
1279 | -- | |
1280 | -- Example: | |
1281 | -- | |
1282 | -- -- ensure that the supplied path has an extension, but if it doesn't use "tmp". | |
1283 | -- theFile = defaultext(UserFileName, "tmp") | |
1284 | -- | |
1285 | -- | |
1286 | -- See Also: | |
1287 | -- [[:pathinfo]] | |
1288 | ||
1289 | 7 | |
1290 | 7 | if length(defext) = 0 then |
1291 | 0 | return path |
1292 | end if | |
1293 | ||
1294 | 7 | for i = length(path) to 1 by -1 do |
1295 | 28 | if path[i] = '.' then |
1296 | -- There is a dot in the file name part | |
1297 | 2 | return path |
1298 | end if | |
1299 | 26 | if path[i] = SLASH then |
1300 | 1 | if i = length(path) then |
1301 | -- No file name in supplied path | |
1302 | 0 | return path |
1303 | else | |
1304 | -- No dot in file name part. | |
1305 | 1 | exit |
1306 | end if | |
1307 | end if | |
1308 | 25 | end for |
1309 | ||
1310 | 5 | if defext[1] != '.' then |
1311 | 4 | path &= '.' |
1312 | end if | |
1313 | ||
1314 | 5 | return path & defext |
1315 | end function | |
1316 | ||
1317 | --** | |
1318 | -- Determine if the supplied string is an absolute path or a relative path. | |
1319 | -- | |
1320 | -- Parameters: | |
1321 | -- # ##filename## : a sequence, the name of the file path | |
1322 | -- | |
1323 | -- Returns: | |
1324 | -- An **integer**, 0 if ##filename## is a relative path or 1 otherwise. | |
1325 | -- | |
1326 | -- Comment: | |
1327 | -- A //relative// path is one which is relative to the current directory and | |
1328 | -- an //absolute// path is one that doesn't need to know the current directory | |
1329 | -- to find the file. | |
1330 | -- | |
1331 | -- Example 1: | |
1332 | -- | |
1333 | -- ? absolute_path("") -- returns 0 | |
1334 | -- ? absolute_path("/usr/bin/abc") -- returns 1 | |
1335 | -- ? absolute_path("\\temp\\somefile.doc") -- returns 1 | |
1336 | -- ? absolute_path("../abc") -- returns 0 | |
1337 | -- ? absolute_path("local/abc.txt") -- returns 0 | |
1338 | -- ? absolute_path("abc.txt") -- returns 0 | |
1339 | -- ? absolute_path("c:..\\abc") -- returns 0 | |
1340 | -- -- The next two examples return 0 on Unix platforms and 1 on Microsoft platforms | |
1341 | -- ? absolute_path("c:\\windows\\system32\\abc") | |
1342 | -- ? absolute_path("c:/windows/system32/abc") | |
1343 | -- | |
1344 | ||
1345 | 16 | |
1346 | 16 | if length(filename) = 0 then |
1347 | 1 | return 0 |
1348 | end if | |
1349 | ||
1350 | 15 | if eu:find(filename[1], SLASHES) then |
1351 | 1 | return 1 |
1352 | end if | |
1353 | ||
1354 | 14 | ifdef WINDOWS then |
1355 | if length(filename) = 1 then | |
1356 | return 0 | |
1357 | end if | |
1358 | ||
1359 | if filename[2] != ':' then | |
1360 | return 0 | |
1361 | end if | |
1362 | ||
1363 | if length(filename) < 3 then | |
1364 | return 0 | |
1365 | end if | |
1366 | ||
1367 | if eu:find(filename[3], SLASHES) then | |
1368 | return 1 | |
1369 | end if | |
1370 | end ifdef | |
1371 | 14 | return 0 |
1372 | end function | |
1373 | ||
1374 | ||
1375 | --** | |
1376 | -- Returns the full path and file name of the supplied file name. | |
1377 | -- | |
1378 | -- Parameters: | |
1379 | -- # ##path_in## : A sequence. This is the file name whose full path you want. | |
1380 | -- # ##directory_given## : An integer. This is zero if ##path_in## is | |
1381 | -- to be interpreted as a file specification otherwise it is assumed to be a | |
1382 | -- directory specification. The default is zero. | |
1383 | -- # ##no_case## : An integer. Only applies to the Windows platform. If zero (the default) | |
1384 | -- the path name is returned exactly as stored in the file system, otherwise the | |
1385 | -- returned value is all in lowercase. | |
1386 | -- | |
1387 | -- Returns: | |
1388 | -- A **sequence**, the full path and file name. | |
1389 | -- | |
1390 | -- Comment: | |
1391 | -- * In non-Unix systems, the result is always in lowercase. | |
1392 | -- * The supplied file/directory does not have to actually exist. | |
1393 | -- * Does not (yet) handle UNC paths or unix links. | |
1394 | -- | |
1395 | -- | |
1396 | -- Example 1: | |
1397 | -- | |
1398 | -- -- Assuming the current directory is "/usr/foo/bar" | |
1399 | -- res = canonical_path("../abc.def") | |
1400 | -- -- res is now "/usr/foo/abc.def" | |
1401 | -- | |
1402 | ||
1403 | 15 | |
1404 | 15 | sequence lPath = "" |
1405 | 15 | integer lPosA = -1 |
1406 | 15 | integer lPosB = -1 |
1407 | 15 | integer lPosC = -1 |
1408 | 15 | sequence lLevel = "" |
1409 | sequence lHome | |
1410 | ||
1411 | 15 | ifdef UNIX then |
1412 | 15 | lPath = path_in |
1413 | elsedef | |
1414 | sequence lDrive = "" | |
1415 | -- Replace unix style separators with Windows style | |
1416 | lPath = match_replace("/", path_in, SLASH) | |
1417 | end ifdef | |
1418 | ||
1419 | -- Strip off any enclosing quotes. | |
1420 | 15 | if (length(lPath) > 2 and lPath[1] = '"' and lPath[$] = '"') then |
1421 | 1 | lPath = lPath[2..$-1] |
1422 | end if | |
1423 | ||
1424 | -- Replace any leading tilde with 'HOME' directory. | |
1425 | 15 | if (length(lPath) > 0 and lPath[1] = '~') then |
1426 | 1 | ifdef UNIX then |
1427 | 1 | lHome = getenv("HOME") |
1428 | elsedef | |
1429 | lHome = getenv("HOMEDRIVE") & getenv("HOMEPATH") | |
1430 | end ifdef | |
1431 | ||
1432 | 1 | if lHome[$] != SLASH then |
1433 | 1 | lHome &= SLASH |
1434 | end if | |
1435 | ||
1436 | 1 | if length(lPath) > 1 and lPath[2] = SLASH then |
1437 | 0 | lPath = lHome & lPath[3 .. $] |
1438 | else | |
1439 | 1 | lPath = lHome & lPath[2 .. $] |
1440 | end if | |
1441 | end if | |
1442 | ||
1443 | 15 | ifdef not UNIX then |
1444 | -- Strip off any drive letter attached. | |
1445 | if ( (length(lPath) > 1) and (lPath[2] = ':' ) ) | |
1446 | then | |
1447 | lDrive = lPath[1..2] | |
1448 | lPath = lPath[3..$] | |
1449 | end if | |
1450 | end ifdef | |
1451 | ||
1452 | -- If a relative path, prepend the PWD of the appropriate drive. | |
1453 | 15 | if ( (length(lPath) = 0) or (lPath[1] != SLASH) ) |
1454 | then | |
1455 | 11 | ifdef UNIX then |
1456 | 11 | lPath = curdir() & lPath |
1457 | elsedef | |
1458 | if (length(lDrive) = 0) then | |
1459 | lPath = curdir() & lPath | |
1460 | else | |
1461 | lPath = curdir(lDrive[1]) & lPath | |
1462 | end if | |
1463 | -- Strip of the drive letter if it got attached again. | |
1464 | if ( (length(lPath) > 1) and (lPath[2] = ':' ) ) then | |
1465 | if (length(lDrive) = 0) then | |
1466 | lDrive = lPath[1..2] | |
1467 | end if | |
1468 | lPath = lPath[3..$] | |
1469 | end if | |
1470 | end ifdef | |
1471 | end if | |
1472 | ||
1473 | -- If the input is supposed to be a directory, ensure it ends in a path separator. | |
1474 | 15 | if ((directory_given != 0) and (lPath[$] != SLASH) ) then |
1475 | 0 | lPath &= SLASH |
1476 | end if | |
1477 | ||
1478 | -- Replace all instances of "/./" with "/" | |
1479 | 15 | lLevel = SLASH & '.' & SLASH |
1480 | 15 | while( lPosA != 0 ) with entry do |
1481 | 3 | lPath = lPath[1..lPosA-1] & lPath[lPosA + 2 .. $] |
1482 | ||
1483 | entry | |
1484 | 18 | lPosA = match(lLevel, lPath) |
1485 | 18 | end while |
1486 | ||
1487 | -- Replace all instances of "X/Y/../" with "X/" | |
1488 | 15 | lLevel = SLASH & ".." & SLASH |
1489 | ||
1490 | 15 | while( lPosA != 0 ) with entry do |
1491 | -- Locate preceding directory separator. | |
1492 | 1 | lPosB = lPosA-1 |
1493 | 1 | while((lPosB > 0) and (lPath[lPosB] != SLASH)) do |
1494 | 3 | lPosB -= 1 |
1495 | 3 | end while |
1496 | 1 | if (lPosB <= 0) then |
1497 | 0 | lPosB = 1 |
1498 | end if | |
1499 | ||
1500 | 1 | lPath = lPath[1..lPosB-1] & lPath[lPosA + 3 .. $] |
1501 | ||
1502 | entry | |
1503 | 16 | lPosA = match(lLevel, lPath) |
1504 | 16 | end while |
1505 | ||
1506 | 15 | ifdef WINDOWS then |
1507 | lPath = lDrive & lPath | |
1508 | if no_case then | |
1509 | lPath = lower(lPath) | |
1510 | end if | |
1511 | end ifdef | |
1512 | ||
1513 | 15 | return lPath |
1514 | end function | |
1515 | ||
1516 | ||
1517 | --**** | |
1518 | -- === File Types | |
1519 | ||
1520 | public enum | |
1521 | 101 | FILETYPE_UNDEFINED = -1, |
1522 | 101 | FILETYPE_NOT_FOUND, |
1523 | 101 | FILETYPE_FILE, |
1524 | 101 | FILETYPE_DIRECTORY |
1525 | ||
1526 | --** | |
1527 | -- Get the type of a file. | |
1528 | -- | |
1529 | -- Parameters: | |
1530 | -- # ##filename## : the name of the file to query. It must not have wildcards. | |
1531 | -- | |
1532 | -- Returns: | |
1533 | -- An **integer**, | |
1534 | -- * -1 if file could be multiply defined | |
1535 | -- * 0 if filename does not exist | |
1536 | -- * 1 if filename is a file | |
1537 | -- * 2 if filename is a directory | |
1538 | -- | |
1539 | -- See Also: | |
1540 | -- [[:dir]], [[:FILETYPE_DIRECTORY]], [[:FILETYPE_FILE]], [[:FILETYPE_NOT_FOUND]], | |
1541 | -- [[:FILETYPE_UNDEFINED]] | |
1542 | ||
1543 | 7 | |
1544 | object dirfil | |
1545 | 7 | if eu:find('*', filename) or eu:find('?', filename) then return FILETYPE_UNDEFINED end if |
1546 | ||
1547 | 7 | ifdef WINDOWS then |
1548 | if length(filename) = 2 and filename[2] = ':' then | |
1549 | filename &= "\\" | |
1550 | end if | |
1551 | end ifdef | |
1552 | ||
1553 | 7 | dirfil = dir(filename) |
1554 | 7 | if sequence(dirfil) then |
1555 | 5 | if length( dirfil ) > 1 or eu:find('d', dirfil[1][2]) or (length(filename)=3 and filename[2]=':') then |
1556 | 1 | return FILETYPE_DIRECTORY |
1557 | else | |
1558 | 4 | return FILETYPE_FILE |
1559 | end if | |
1560 | else | |
1561 | 2 | return FILETYPE_NOT_FOUND |
1562 | end if | |
1563 | end function | |
1564 | ||
1565 | --**** | |
1566 | -- === File Handling | |
1567 | -- | |
1568 | ||
1569 | public enum | |
1570 | 101 | SECTORS_PER_CLUSTER, |
1571 | 101 | BYTES_PER_SECTOR, |
1572 | 101 | NUMBER_OF_FREE_CLUSTERS, |
1573 | 101 | TOTAL_NUMBER_OF_CLUSTERS |
1574 | ||
1575 | public enum | |
1576 | 101 | TOTAL_BYTES, |
1577 | 101 | FREE_BYTES, |
1578 | 101 | USED_BYTES |
1579 | ||
1580 | public enum | |
1581 | 101 | COUNT_DIRS, |
1582 | 101 | COUNT_FILES, |
1583 | 101 | COUNT_SIZE, |
1584 | 101 | COUNT_TYPES |
1585 | ||
1586 | public enum | |
1587 | 101 | EXT_NAME, |
1588 | 101 | EXT_COUNT, |
1589 | 101 | EXT_SIZE |
1590 | ||
1591 | --** | |
1592 | -- Check to see if a file exists | |
1593 | -- | |
1594 | -- Parameters: | |
1595 | -- # ##name## : filename to check existence of | |
1596 | -- | |
1597 | -- Returns: | |
1598 | -- An **integer**, 1 on yes, 0 on no | |
1599 | -- | |
1600 | -- Example 1: | |
1601 | -- | |
1602 | -- if file_exists("abc.e") then | |
1603 | -- puts(1, "abc.e exists already\n") | |
1604 | -- end if | |
1605 | -- | |
1606 | ||
1607 | 70 | |
1608 | 70 | if atom(name) then |
1609 | 1 | return 0 |
1610 | end if | |
1611 | ||
1612 | 69 | ifdef WIN32 then |
1613 | atom pName = allocate_string(name) | |
1614 | atom r = c_func(xGetFileAttributes, {pName}) | |
1615 | free(pName) | |
1616 | ||
1617 | return r > 0 | |
1618 | ||
1619 | elsifdef UNIX then | |
1620 | 69 | atom pName = allocate_string(name) |
1621 | 69 | atom r = c_func(xGetFileAttributes, {pName, 0}) |
1622 | 69 | free(pName) |
1623 | ||
1624 | 69 | return r = 0 |
1625 | ||
1626 | elsedef | |
1627 | ||
1628 | return sequence(dir(name)) | |
1629 | end ifdef | |
1630 | end function | |
1631 | ||
1632 | --** | |
1633 | -- Get the timestamp of the file | |
1634 | -- | |
1635 | -- Parameters: | |
1636 | -- # ##name## : the filename to get the date of | |
1637 | -- | |
1638 | -- Returns: | |
1639 | -- A valid **datetime type**, representing the files date and time or -1 if the | |
1640 | -- file's date and time could not be read. | |
1641 | -- | |
1642 | ||
1643 | 0 | |
1644 | 0 | object d = dir(fname) |
1645 | 0 | if atom(d) then return -1 end if |
1646 | ||
1647 | 0 | return dt:new(d[1][D_YEAR], d[1][D_MONTH], d[1][D_DAY], |
1648 | d[1][D_HOUR], d[1][D_MINUTE], d[1][D_SECOND]) | |
1649 | end function | |
1650 | ||
1651 | --** | |
1652 | -- Copy a file. | |
1653 | -- | |
1654 | -- Parameters: | |
1655 | -- # ##src## : a sequence, the name of the file or directory to copy | |
1656 | -- # ##dest## : a sequence, the new name or location of the file | |
1657 | -- # ##overwrite## : an integer; 0 (the default) will prevent an existing destination | |
1658 | -- file from being overwritten. Non-zero will overwrite the | |
1659 | -- destination file. | |
1660 | -- | |
1661 | -- Returns: | |
1662 | -- An **integer**, 0 on failure, 1 on success. | |
1663 | -- | |
1664 | -- Comments: | |
1665 | -- If ##overwrite## is true, and if dest file already exists, | |
1666 | -- the function overwrites the existing file and succeeds. | |
1667 | -- | |
1668 | -- See Also: | |
1669 | -- [[:move_file]], [[:rename_file]] | |
1670 | ||
1671 | 3 | |
1672 | ||
1673 | 3 | if length(dest) then |
1674 | 3 | if file_type( dest ) = FILETYPE_DIRECTORY then |
1675 | 0 | if dest[$] != SLASH then |
1676 | 0 | dest &= SLASH |
1677 | end if | |
1678 | 0 | sequence info = pathinfo( src ) |
1679 | 0 | dest &= info[PATH_FILENAME] |
1680 | end if | |
1681 | end if | |
1682 | ||
1683 | 3 | ifdef WIN32 then |
1684 | atom psrc = allocate_string(src) | |
1685 | atom pdest = allocate_string(dest) | |
1686 | integer success = c_func(xCopyFile, {psrc, pdest, not overwrite}) | |
1687 | free({pdest, psrc}) | |
1688 | ||
1689 | elsedef | |
1690 | 3 | integer success = 0 |
1691 | ||
1692 | 3 | if file_exists(src) then |
1693 | 3 | if overwrite or not file_exists( dest ) then |
1694 | 1 | integer |
1695 | 1 | in = open( src, "rb" ), |
1696 | 1 | out = open( dest, "wb" ) |
1697 | 1 | if in != -1 and out != -1 then |
1698 | 1 | integer byte |
1699 | 1 | while byte != -1 with entry do |
1700 | 13 | puts( out, byte ) |
1701 | entry | |
1702 | 14 | byte = getc( in ) |
1703 | 14 | end while |
1704 | 1 | success = 1 |
1705 | 1 | close( in ) |
1706 | 1 | close( out ) |
1707 | end if | |
1708 | end if | |
1709 | end if | |
1710 | ||
1711 | end ifdef | |
1712 | ||
1713 | 3 | return success |
1714 | ||
1715 | end function | |
1716 | ||
1717 | --** | |
1718 | -- Rename a file. | |
1719 | -- | |
1720 | -- Parameters: | |
1721 | -- # ##src## : a sequence, the name of the file or directory to rename. | |
1722 | -- # ##dest## : a sequence, the new name for the renamed file | |
1723 | -- # ##overwrite## : an integer, 0 (the default) to prevent renaming if destination file exists, | |
1724 | -- 1 to delete existing destination file first | |
1725 | -- | |
1726 | -- Returns: | |
1727 | -- An **integer**, 0 on failure, 1 on success. | |
1728 | -- | |
1729 | -- Comments: | |
1730 | -- * If ##dest## contains a path specification, this is equivalent to moving the file, as | |
1731 | -- well as possibly changing its name. However, the path must be on the same drive for | |
1732 | -- this to work. | |
1733 | -- * If ##overwrite## was requested but the rename fails, any existing destination | |
1734 | -- file is preserved. | |
1735 | -- | |
1736 | -- See Also: | |
1737 | -- [[:move_file]], [[:copy_file]] | |
1738 | ||
1739 | 4 | |
1740 | atom psrc, pdest, ret | |
1741 | 4 | sequence tempfile = "" |
1742 | ||
1743 | 4 | if not overwrite then |
1744 | 2 | if file_exists(dest) then |
1745 | 2 | return 0 |
1746 | end if | |
1747 | else | |
1748 | 2 | if file_exists(dest) then |
1749 | 1 | tempfile = temp_file(dest) |
1750 | 1 | ret = move_file(dest, tempfile) |
1751 | end if | |
1752 | end if | |
1753 | ||
1754 | ||
1755 | 2 | psrc = allocate_string(src) |
1756 | 2 | pdest = allocate_string(dest) |
1757 | 2 | ret = c_func(xMoveFile, {psrc, pdest}) |
1758 | ||
1759 | 2 | ifdef UNIX then |
1760 | 2 | ret = not ret |
1761 | end ifdef | |
1762 | ||
1763 | 2 | free({pdest, psrc}) |
1764 | ||
1765 | 2 | if overwrite then |
1766 | 2 | if not ret then |
1767 | 0 | if length(tempfile) > 0 then |
1768 | -- rename was unsuccessful so restore from tempfile | |
1769 | 0 | ret = move_file(tempfile, dest) |
1770 | end if | |
1771 | end if | |
1772 | 2 | delete_file(tempfile) |
1773 | end if | |
1774 | ||
1775 | 2 | return ret |
1776 | end function | |
1777 | ||
1778 | 101 | ifdef LINUX then |
1779 | 14 | |
1780 | 14 | return c_func(xStatFile, {3, psrc, psrcbuf}) |
1781 | end function | |
1782 | elsifdef UNIX then | |
1783 | function xstat(atom psrc, atom psrcbuf) | |
1784 | return c_func(xStatFile, {psrc, psrcbuf}) | |
1785 | end function | |
1786 | end ifdef | |
1787 | ||
1788 | --** | |
1789 | -- Move a file to another location. | |
1790 | -- | |
1791 | -- Parameters: | |
1792 | -- # ##src## : a sequence, the name of the file or directory to move | |
1793 | -- # ##dest## : a sequence, the new location for the file | |
1794 | -- # ##overwrite## : an integer, 0 (the default) to prevent overwriting an existing destination file, | |
1795 | -- 1 to overwrite existing destination file | |
1796 | -- | |
1797 | -- Returns: | |
1798 | -- An **integer**, 0 on failure, 1 on success. | |
1799 | -- | |
1800 | -- Comments: | |
1801 | -- * If ##overwrite## was requested but the move fails, any existing destination | |
1802 | -- file is preserved. | |
1803 | -- See Also: | |
1804 | -- [[:rename_file]], [[:copy_file]] | |
1805 | ||
1806 | 8 | |
1807 | 8 | atom psrc = 0, pdest = 0, ret |
1808 | 8 | sequence tempfile = "" |
1809 | ||
1810 | 8 | if not file_exists(src) then |
1811 | 1 | return 0 |
1812 | end if | |
1813 | ||
1814 | 7 | if not overwrite then |
1815 | 5 | if file_exists( dest ) then |
1816 | 2 | return 0 |
1817 | end if | |
1818 | end if | |
1819 | ||
1820 | 5 | ifdef UNIX then |
1821 | 5 | atom psrcbuf = 0, pdestbuf = 0 |
1822 | 5 | integer stat_t_offset, dev_t_size, stat_buf_size |
1823 | end ifdef | |
1824 | 5 | ifdef LINUX then |
1825 | 5 | stat_t_offset = 0 |
1826 | 5 | stat_buf_size = 88 |
1827 | 5 | dev_t_size = 8 |
1828 | elsifdef OSX then | |
1829 | --TODO | |
1830 | stat_t_offset = 0 | |
1831 | stat_buf_size = 88 | |
1832 | dev_t_size = 8 | |
1833 | elsifdef FREEBSD or SUNOS then | |
1834 | --TODO | |
1835 | stat_t_offset = 0 | |
1836 | stat_buf_size = 88 | |
1837 | dev_t_size = 8 | |
1838 | end ifdef | |
1839 | ||
1840 | ||
1841 | 5 | ifdef UNIX then |
1842 | 5 | psrcbuf = allocate(stat_buf_size) |
1843 | 5 | psrc = allocate_string(src) |
1844 | 5 | ret = xstat(psrc, psrcbuf) |
1845 | 5 | if ret then |
1846 | 0 | free({psrcbuf, psrc}) |
1847 | 0 | return 0 |
1848 | end if | |
1849 | ||
1850 | 5 | pdestbuf = allocate(stat_buf_size) |
1851 | 5 | pdest = allocate_string(dest) |
1852 | 5 | ret = xstat(pdest, pdestbuf) |
1853 | 5 | if ret then |
1854 | -- Assume destination doesn't exist | |
1855 | 4 | atom pdir |
1856 | 4 | if length(dirname(dest)) = 0 then |
1857 | 1 | pdir = allocate_string(current_dir()) |
1858 | else | |
1859 | 3 | pdir = allocate_string(dirname(dest)) |
1860 | end if | |
1861 | 4 | ret = xstat(pdir, pdestbuf) |
1862 | 4 | free(pdir) |
1863 | end if | |
1864 | ||
1865 | 5 | if not ret and not equal(peek(pdestbuf+stat_t_offset), peek(psrcbuf+stat_t_offset)) then |
1866 | -- on different filesystems, can not use rename | |
1867 | -- fall back on copy&delete | |
1868 | 0 | ret = copy_file(src, dest, overwrite) |
1869 | 0 | if ret then |
1870 | 0 | ret = delete_file(src) |
1871 | end if | |
1872 | 0 | free({psrcbuf, psrc, pdestbuf, pdest}) |
1873 | 0 | return (not ret) |
1874 | end if | |
1875 | ||
1876 | elsedef | |
1877 | psrc = allocate_string(src) | |
1878 | pdest = allocate_string(dest) | |
1879 | end ifdef | |
1880 | ||
1881 | 5 | if overwrite then |
1882 | -- return value is ignored, we don't care if it existed or not | |
1883 | 2 | tempfile = temp_file(dest) |
1884 | 2 | move_file(dest, tempfile) |
1885 | end if | |
1886 | ||
1887 | 5 | ret = c_func(xMoveFile, {psrc, pdest}) |
1888 | ||
1889 | 5 | ifdef UNIX then |
1890 | 5 | ret = not ret |
1891 | 5 | free({psrcbuf, pdestbuf}) |
1892 | end ifdef | |
1893 | 5 | free({pdest, psrc}) |
1894 | ||
1895 | 5 | if overwrite then |
1896 | 2 | if not ret then |
1897 | -- move was unsuccessful so restore tempfile | |
1898 | 0 | move_file(tempfile, dest) |
1899 | end if | |
1900 | 2 | delete_file(tempfile) |
1901 | end if | |
1902 | ||
1903 | 5 | return ret |
1904 | end function | |
1905 | ||
1906 | ||
1907 | --** | |
1908 | -- Return the size of a file. | |
1909 | -- | |
1910 | -- Parameters: | |
1911 | -- # ##filename## : the name of the queried file | |
1912 | -- | |
1913 | -- Returns: | |
1914 | -- An **atom**, the file size, or -1 if file is not found. | |
1915 | -- | |
1916 | -- Comments: | |
1917 | -- This function does not compute the total size for a directory, and returns 0 instead. | |
1918 | -- See Also: | |
1919 | -- [[:dir]] | |
1920 | ||
1921 | 0 | |
1922 | object list | |
1923 | 0 | list = dir(filename) |
1924 | 0 | if atom(list) or length(list) = 0 then |
1925 | 0 | return -1 |
1926 | end if | |
1927 | 0 | return list[1][D_SIZE] |
1928 | end function | |
1929 | ||
1930 | --** | |
1931 | -- Locates a file by looking in a set of directories for it. | |
1932 | -- | |
1933 | -- Parameters: | |
1934 | -- # ##filename## : a sequence, the name of the file to search for. | |
1935 | -- # ##search_list## : a sequence, the list of directories to look in. By | |
1936 | -- default this is "", meaning that a predefined set of directories | |
1937 | -- is scanned. See comments below. | |
1938 | -- # ##subdir## : a sequence, the sub directory within the search directories | |
1939 | -- to check. This is optional. | |
1940 | -- | |
1941 | -- Returns: | |
1942 | -- A **sequence**, the located file path if found, else the original file name. | |
1943 | -- | |
1944 | -- Comments: | |
1945 | -- If ##filename## is an absolute path, it is just returned and no searching | |
1946 | -- takes place. | |
1947 | -- | |
1948 | -- If ##filename## is located, the full path of the file is returned. | |
1949 | -- | |
1950 | -- If ##search_list## is supplied, it can be either a sequence of directory names, | |
1951 | -- of a string of directory names delimited by ':' in UNIX and ';' in Windows. | |
1952 | -- | |
1953 | -- If the ##search_list## is omitted or "", this will look in the following places... | |
1954 | -- * The current directory | |
1955 | -- * The directory that the program is run from. | |
1956 | -- * The directory in $HOME ($HOMEDRIVE & $HOMEPATH in Windows) | |
1957 | -- * The parent directory of the current directory | |
1958 | -- * The directories returned by include_paths() | |
1959 | -- * $EUDIR/bin | |
1960 | -- * $EUDIR/docs | |
1961 | -- * $EUDIST/ | |
1962 | -- * $EUDIST/etc | |
1963 | -- * $EUDIST/data | |
1964 | -- * The directories listed in $USERPATH | |
1965 | -- * The directories listed in $PATH | |
1966 | -- | |
1967 | -- If the ##subdir## is supplied, the function looks in this sub directory for each | |
1968 | -- of the directories in the search list. | |
1969 | -- | |
1970 | -- Example 1: | |
1971 | -- | |
1972 | -- res = locate_file("abc.def", {"/usr/bin", "/u2/someapp", "/etc"}) | |
1973 | -- res = locate_file("abc.def", "/usr/bin:/u2/someapp:/etc") | |
1974 | -- res = locate_file("abc.def") -- Scan default locations. | |
1975 | -- res = locate_file("abc.def", , "app") -- Scan the 'app' sub directory in the default locations. | |
1976 | -- | |
1977 | ||
1978 | 4 | |
1979 | object extra_paths | |
1980 | sequence this_path | |
1981 | ||
1982 | 4 | if absolute_path(filename) then |
1983 | 0 | return filename |
1984 | end if | |
1985 | ||
1986 | 4 | if length(search_list) = 0 then |
1987 | 4 | search_list = append(search_list, "." & SLASH) |
1988 | ||
1989 | 4 | extra_paths = command_line() |
1990 | 4 | extra_paths = canonical_path(dirname(extra_paths[2]), 1) |
1991 | 4 | search_list = append(search_list, extra_paths) |
1992 | ||
1993 | 4 | ifdef UNIX then |
1994 | 4 | extra_paths = getenv("HOME") |
1995 | ||
1996 | elsedef | |
1997 | extra_paths = getenv("HOMEDRIVE") & getenv("HOMEPATH") | |
1998 | end ifdef | |
1999 | ||
2000 | 4 | if sequence(extra_paths) then |
2001 | 4 | search_list = append(search_list, extra_paths & SLASH) |
2002 | end if | |
2003 | ||
2004 | 4 | search_list = append(search_list, ".." & SLASH) |
2005 | ||
2006 | 4 | ifdef UNIX then |
2007 | -- typical install directories: | |
2008 | 4 | search_list = append( search_list, "/usr/local/share/euphoria/bin/" ) |
2009 | 4 | search_list = append( search_list, "/usr/share/euphoria/bin/" ) |
2010 | end ifdef | |
2011 | ||
2012 | 4 | search_list &= include_paths(1) |
2013 | ||
2014 | 4 | extra_paths = getenv("EUDIR") |
2015 | 4 | if sequence(extra_paths) then |
2016 | 4 | search_list = append(search_list, extra_paths & SLASH & "bin" & SLASH) |
2017 | 4 | search_list = append(search_list, extra_paths & SLASH & "docs" & SLASH) |
2018 | end if | |
2019 | ||
2020 | 4 | extra_paths = getenv("EUDIST") |
2021 | 4 | if sequence(extra_paths) then |
2022 | 0 | search_list = append(search_list, extra_paths & SLASH) |
2023 | 0 | search_list = append(search_list, extra_paths & SLASH & "etc" & SLASH) |
2024 | 0 | search_list = append(search_list, extra_paths & SLASH & "data" & SLASH) |
2025 | end if | |
2026 | ||
2027 | 4 | extra_paths = getenv("USERPATH") |
2028 | 4 | if sequence(extra_paths) then |
2029 | 0 | extra_paths = split(PATHSEP, extra_paths) |
2030 | 0 | search_list &= extra_paths |
2031 | end if | |
2032 | ||
2033 | 4 | extra_paths = getenv("PATH") |
2034 | 4 | if sequence(extra_paths) then |
2035 | 4 | extra_paths = split(PATHSEP, extra_paths) |
2036 | 4 | search_list &= extra_paths |
2037 | end if | |
2038 | else | |
2039 | 0 | if integer(search_list[1]) then |
2040 | 0 | search_list = split(PATHSEP, search_list) |
2041 | end if | |
2042 | end if | |
2043 | ||
2044 | 4 | if length(subdir) > 0 then |
2045 | 0 | if subdir[$] != SLASH then |
2046 | 0 | subdir &= SLASH |
2047 | end if | |
2048 | end if | |
2049 | ||
2050 | 4 | for i = 1 to length(search_list) do |
2051 | 28 | if length(search_list[i]) = 0 then |
2052 | 0 | continue |
2053 | end if | |
2054 | ||
2055 | 28 | if search_list[i][$] != SLASH then |
2056 | 10 | search_list[i] &= SLASH |
2057 | end if | |
2058 | ||
2059 | ||
2060 | 28 | if length(subdir) > 0 then |
2061 | 0 | this_path = search_list[i] & subdir & filename |
2062 | else | |
2063 | 28 | this_path = search_list[i] & filename |
2064 | end if | |
2065 | ||
2066 | 28 | if file_exists(this_path) then |
2067 | 3 | return canonical_path(this_path) |
2068 | end if | |
2069 | ||
2070 | 25 | end for |
2071 | 1 | return filename |
2072 | end function | |
2073 | ||
2074 | --** | |
2075 | -- Returns some information about a disk drive. | |
2076 | -- | |
2077 | -- Parameters: | |
2078 | -- # ##disk_path## : A sequence. This is the path that identifies the disk to inquire upon. | |
2079 | -- | |
2080 | -- Returns: | |
2081 | -- A **sequence**, containing ##SECTORS_PER_CLUSTER##, ##BYTES_PER_SECTOR##, | |
2082 | -- ##NUMBER_OF_FREE_CLUSTERS##, and ##TOTAL_NUMBER_OF_CLUSTERS## | |
2083 | -- | |
2084 | -- Example 1: | |
2085 | -- | |
2086 | -- res = disk_metrics("C:\\") | |
2087 | -- min_file_size = res[SECTORS_PER_CLUSTER] * res[BYTES_PER_SECTOR] | |
2088 | -- | |
2089 | ||
2090 | 0 | |
2091 | 0 | sequence result = {0, 0, 0, 0} |
2092 | 0 | atom path_addr = 0 |
2093 | 0 | atom metric_addr = 0 |
2094 | ||
2095 | 0 | ifdef WIN32 then |
2096 | if sequence(disk_path) then | |
2097 | path_addr = allocate_string(disk_path) | |
2098 | else | |
2099 | path_addr = 0 | |
2100 | end if | |
2101 | ||
2102 | metric_addr = allocate(16) | |
2103 | ||
2104 | if c_func(xGetDiskFreeSpace, {path_addr, | |
2105 | metric_addr + 0, | |
2106 | metric_addr + 4, | |
2107 | metric_addr + 8, | |
2108 | metric_addr + 12 | |
2109 | }) then | |
2110 | result = peek4s({metric_addr, 4}) | |
2111 | end if | |
2112 | ||
2113 | free({path_addr, metric_addr}) | |
2114 | elsifdef UNIX then | |
2115 | 0 | sequence disk_size = {0,0,0} |
2116 | ||
2117 | 0 | atom bytes_per_cluster |
2118 | 0 | atom psrc, ret, psrcbuf |
2119 | 0 | integer stat_t_offset, dev_t_size, stat_buf_size |
2120 | ||
2121 | 0 | ifdef LINUX then |
2122 | 0 | stat_t_offset = 48 |
2123 | 0 | stat_buf_size = 88 |
2124 | 0 | dev_t_size = 4 |
2125 | elsifdef OSX then | |
2126 | --TODO | |
2127 | stat_t_offset = 48 | |
2128 | stat_buf_size = 88 | |
2129 | dev_t_size = 4 | |
2130 | elsifdef FREEBSD or SUNOS then | |
2131 | --TODO | |
2132 | stat_t_offset = 48 | |
2133 | stat_buf_size = 88 | |
2134 | dev_t_size = 4 | |
2135 | end ifdef | |
2136 | ||
2137 | 0 | psrc = allocate_string(disk_path) |
2138 | 0 | psrcbuf = allocate(stat_buf_size) |
2139 | 0 | ret = xstat(psrc,psrcbuf) |
2140 | 0 | bytes_per_cluster = peek4s(psrcbuf+stat_t_offset) |
2141 | 0 | free({psrcbuf, psrc}) |
2142 | 0 | if ret then |
2143 | -- failure | |
2144 | 0 | return result |
2145 | end if | |
2146 | ||
2147 | 0 | disk_size = disk_size(disk_path) |
2148 | ||
2149 | -- this is hardcoded for now, but may be x86 specific | |
2150 | -- on other Unix platforms that run on non x86 hardware, this | |
2151 | -- may need to be changed - there is no portable way to get this | |
2152 | result[BYTES_PER_SECTOR] = 512 | |
2153 | ||
2154 | result[SECTORS_PER_CLUSTER] = bytes_per_cluster / result[BYTES_PER_SECTOR] | |
2155 | result[TOTAL_NUMBER_OF_CLUSTERS] = disk_size[TOTAL_BYTES] / bytes_per_cluster | |
2156 | result[NUMBER_OF_FREE_CLUSTERS] = disk_size[FREE_BYTES] / bytes_per_cluster | |
2157 | ||
2158 | end ifdef | |
2159 | ||
2160 | 0 | return result |
2161 | end function | |
2162 | ||
2163 | --** | |
2164 | -- Returns the amount of space for a disk drive. | |
2165 | -- | |
2166 | -- Parameters: | |
2167 | -- # ##disk_path## : A sequence. This is the path that identifies the disk to inquire upon. | |
2168 | -- | |
2169 | -- Returns: | |
2170 | -- A **sequence**, containing TOTAL_BYTES, USED_BYTES, FREE_BYTES, and a string which represents the filesystem name | |
2171 | -- | |
2172 | -- Example 1: | |
2173 | -- | |
2174 | -- res = disk_size("C:\\") | |
2175 | -- printf(1, "Drive %s has %3.2f%% free space\n", {"C:", res[FREE_BYTES] / res[TOTAL_BYTES]}) | |
2176 | -- | |
2177 | ||
2178 | 1 | |
2179 | 1 | sequence disk_size = {0,0,0, disk_path} |
2180 | ||
2181 | 1 | ifdef WIN32 then |
2182 | sequence result | |
2183 | atom bytes_per_cluster | |
2184 | ||
2185 | ||
2186 | result = disk_metrics(disk_path) | |
2187 | ||
2188 | bytes_per_cluster = result[BYTES_PER_SECTOR] * result[SECTORS_PER_CLUSTER] | |
2189 | ||
2190 | disk_size[TOTAL_BYTES] = bytes_per_cluster * result[TOTAL_NUMBER_OF_CLUSTERS] | |
2191 | disk_size[FREE_BYTES] = bytes_per_cluster * result[NUMBER_OF_FREE_CLUSTERS] | |
2192 | disk_size[USED_BYTES] = disk_size[TOTAL_BYTES] - disk_size[FREE_BYTES] | |
2193 | elsifdef UNIX then | |
2194 | 1 | integer temph |
2195 | 1 | sequence tempfile |
2196 | 1 | object data |
2197 | 1 | sequence filesys = "" |
2198 | ||
2199 | 1 | tempfile = "/tmp/eudf" & sprintf("%d", rand(1000)) & ".tmp" |
2200 | 1 | system("df "&disk_path&" > "&tempfile, 2) |
2201 | ||
2202 | 1 | temph = open(tempfile, "r") |
2203 | 1 | if temph = -1 then |
2204 | -- failure | |
2205 | 0 | return disk_size |
2206 | end if | |
2207 | -- skip the human readable header | |
2208 | 1 | data = gets(temph) |
2209 | -- skip the name of the device node | |
2210 | 1 | while 1 do |
2211 | 10 | data = getc(temph) |
2212 | 10 | if find(data," \t\r\n") then |
2213 | 1 | exit |
2214 | end if | |
2215 | 9 | if data = -1 then |
2216 | -- failure | |
2217 | 0 | close(temph) |
2218 | 0 | temph = delete_file(tempfile) |
2219 | 0 | disk_size[4] = filesys |
2220 | 0 | return disk_size |
2221 | end if | |
2222 | 9 | filesys &= data |
2223 | ||
2224 | 9 | end while |
2225 | ||
2226 | 1 | data = get(temph) |
2227 | 1 | disk_size[TOTAL_BYTES] = data[2] * 1024 |
2228 | 1 | data = get(temph) |
2229 | 1 | disk_size[USED_BYTES] = data[2] * 1024 |
2230 | 1 | data = get(temph) |
2231 | 1 | disk_size[FREE_BYTES] = data[2] * 1024 |
2232 | 1 | disk_size[4] = filesys |
2233 | ||
2234 | 1 | close(temph) |
2235 | 1 | temph = delete_file(tempfile) |
2236 | ||
2237 | end ifdef | |
2238 | ||
2239 | 1 | return disk_size |
2240 | end function | |
2241 | ||
2242 | 101 | sequence file_counters = {} |
2243 | ||
2244 | -- Parameter inst contains two items: 'count_all' flag, and 'index' into file_counters. | |
2245 | ||
2246 | 3 | |
2247 | 3 | integer pos = 0 |
2248 | sequence ext | |
2249 | ||
2250 | 3 | orig_path = orig_path |
2251 | 3 | if equal(dir_info[D_NAME], ".") then |
2252 | 0 | return 0 |
2253 | end if | |
2254 | 3 | if equal(dir_info[D_NAME], "..") then |
2255 | 0 | return 0 |
2256 | end if | |
2257 | ||
2258 | ||
2259 | 3 | if inst[1] = 0 then -- count all is false |
2260 | 3 | if find('h', dir_info[D_ATTRIBUTES]) then |
2261 | 0 | return 0 |
2262 | end if | |
2263 | ||
2264 | 3 | if find('s', dir_info[D_ATTRIBUTES]) then |
2265 | 0 | return 0 |
2266 | end if | |
2267 | end if | |
2268 | ||
2269 | 3 | file_counters[inst[2]][COUNT_SIZE] += dir_info[D_SIZE] |
2270 | 3 | if find('d', dir_info[D_ATTRIBUTES]) then |
2271 | 2 | file_counters[inst[2]][COUNT_DIRS] += 1 |
2272 | else | |
2273 | 1 | file_counters[inst[2]][COUNT_FILES] += 1 |
2274 | 1 | ifdef not UNIX then |
2275 | ext = fileext(lower(dir_info[D_NAME])) | |
2276 | elsedef | |
2277 | 1 | ext = fileext(dir_info[D_NAME]) |
2278 | end ifdef | |
2279 | ||
2280 | 1 | pos = 0 |
2281 | 1 | for i = 1 to length(file_counters[inst[2]][COUNT_TYPES]) do |
2282 | 0 | if equal(file_counters[inst[2]][COUNT_TYPES][i][EXT_NAME], ext) then |
2283 | 0 | pos = i |
2284 | 0 | exit |
2285 | end if | |
2286 | 0 | end for |
2287 | ||
2288 | 1 | if pos = 0 then |
2289 | 1 | file_counters[inst[2]][COUNT_TYPES] &= {{ext, 0, 0}} |
2290 | 1 | pos = length(file_counters[inst[2]][COUNT_TYPES]) |
2291 | end if | |
2292 | ||
2293 | 1 | file_counters[inst[2]][COUNT_TYPES][pos][EXT_COUNT] += 1 |
2294 | 1 | file_counters[inst[2]][COUNT_TYPES][pos][EXT_SIZE] += dir_info[D_SIZE] |
2295 | end if | |
2296 | ||
2297 | 3 | return 0 |
2298 | end function | |
2299 | ||
2300 | ||
2301 | --** | |
2302 | -- Returns the amount of space used by a directory. | |
2303 | -- | |
2304 | -- Parameters: | |
2305 | -- # ##dir_path## : A sequence. This is the path that identifies the directory to inquire upon. | |
2306 | -- # ##count_all## : An integer. Used by Windows systems. If zero (the default) | |
2307 | -- it will not include //system// or //hidden// files in the | |
2308 | -- count, otherwise they are included. | |
2309 | -- | |
2310 | -- Returns: | |
2311 | -- A **sequence**, containing four elements; the number of sub-directories [COUNT_DIRS], | |
2312 | -- the number of files [COUNT_FILES], | |
2313 | -- the total space used by the directory [COUNT_SIZE], and | |
2314 | -- breakdown of the file contents by file extension [COUNT_TYPES]. | |
2315 | -- | |
2316 | -- Comments: | |
2317 | -- * The total space used by the directory does not include space used by any sub-directories. | |
2318 | -- * The file breakdown is a sequence of three-element sub-sequences. Each sub-sequence | |
2319 | -- contains the extension [EXT_NAME], the number of files of this extension [EXT_COUNT], | |
2320 | -- and the space used by these files [EXT_SIZE]. The sub-sequences are presented in | |
2321 | -- extension name order. On Windows the extensions are all in lowercase. | |
2322 | -- | |
2323 | -- Example 1: | |
2324 | -- | |
2325 | -- res = dir_size("/usr/localbin") | |
2326 | -- printf(1, "Directory %s contains %d files\n", {"/usr/localbin", res[COUNT_FILES]}) | |
2327 | -- for i = 1 to length(res[COUNT_TYPES]) do | |
2328 | -- printf(1, " Type: %s (%d files %d bytes)\n", {res[COUNT_TYPES][i][EXT_NAME], | |
2329 | -- res[COUNT_TYPES][i][EXT_COUNT], | |
2330 | -- res[COUNT_TYPES][i][EXT_SIZE]}) | |
2331 | -- end for | |
2332 | -- | |
2333 | ||
2334 | 1 | |
2335 | integer ok | |
2336 | sequence fc | |
2337 | ||
2338 | -- We create our own instance of the global 'file_counters' to use in case | |
2339 | -- the application is using threads. | |
2340 | ||
2341 | 1 | file_counters = append(file_counters, {0,0,0,{}}) |
2342 | 1 | ok = walk_dir(dir_path, {routine_id("count_files"), {count_all, length(file_counters)}}, 0) |
2343 | ||
2344 | 1 | fc = file_counters[$] |
2345 | 1 | file_counters = file_counters[1 .. $-1] |
2346 | 1 | fc[COUNT_TYPES] = sort(fc[COUNT_TYPES]) |
2347 | ||
2348 | 1 | return fc |
2349 | end function | |
2350 | ||
2351 | --** | |
2352 | -- Returns a file name that can be used as a temporary file. | |
2353 | -- | |
2354 | -- Parameters: | |
2355 | -- # ##temp_location## : A sequence. A directory where the temporary file is expected | |
2356 | -- to be created. | |
2357 | -- ** If omitted (the default) the 'temporary' directory | |
2358 | -- will be used. The temporary directory is defined in the "TEMP" | |
2359 | -- environment symbol, or failing that the "TMP" symbol and failing | |
2360 | -- that "C:\TEMP\" is used in non-Unix systems and "/tmp/" is used | |
2361 | -- in Unix systems. | |
2362 | -- ** If ##temp_location## was supplied, | |
2363 | -- *** If it is an existing file, that file's directory is used. | |
2364 | -- *** If it is an existing directory, it is used. | |
2365 | -- *** If it doesn't exist, the directory name portion is used. | |
2366 | -- # ##temp_prefix## : A sequence: The is prepended to the start of the generated file name. | |
2367 | -- The default is "". | |
2368 | -- # ##temp_extn## : A sequence: The is a file extention used in the generated file. | |
2369 | -- The default is "_T_". | |
2370 | -- # ##reserve_temp## : An integer: If not zero an empty file is created using the | |
2371 | -- generated name. The default is not to reserve (create) the file. | |
2372 | -- | |
2373 | -- Returns: | |
2374 | -- A **sequence**, A generated file name. | |
2375 | -- | |
2376 | -- Comments: | |
2377 | -- | |
2378 | -- Example 1: | |
2379 | -- | |
2380 | -- ? temp_file("/usr/space", "myapp", "tmp") --> /usr/space/myapp736321.tmp | |
2381 | -- ? temp_file() --> /tmp/277382._T_ | |
2382 | -- ? temp_file("/users/me/abc.exw") --> /users/me/992831._T_ | |
2383 | -- | |
2384 | ||
2385 | 4 | |
2386 | sequence randname | |
2387 | ||
2388 | 4 | if length(temp_location) = 0 then |
2389 | 1 | object envtmp |
2390 | 1 | envtmp = getenv("TEMP") |
2391 | 1 | if atom(envtmp) then |
2392 | 1 | envtmp = getenv("TMP") |
2393 | end if | |
2394 | 1 | ifdef WIN32 then |
2395 | if atom(envtmp) then | |
2396 | envtmp = "C:\\temp\\" | |
2397 | end if | |
2398 | elsedef | |
2399 | 1 | if atom(envtmp) then |
2400 | 1 | envtmp = "/tmp/" |
2401 | end if | |
2402 | end ifdef | |
2403 | 1 | temp_location = envtmp |
2404 | else | |
2405 | 3 | switch file_type(temp_location) do |
2406 | case FILETYPE_FILE then | |
2407 | 2 | temp_location = dirname(temp_location, 1) |
2408 | ||
2409 | case FILETYPE_DIRECTORY then | |
2410 | -- use temp_location | |
2411 | 0 | temp_location = temp_location |
2412 | ||
2413 | case FILETYPE_NOT_FOUND then | |
2414 | 1 | object tdir = dirname(temp_location, 1) |
2415 | 1 | if file_exists(tdir) then |
2416 | 1 | temp_location = tdir |
2417 | else | |
2418 | 0 | temp_location = "." |
2419 | end if | |
2420 | ||
2421 | case else | |
2422 | 0 | temp_location = "." |
2423 | ||
2424 | end switch | |
2425 | end if | |
2426 | ||
2427 | 4 | if temp_location[$] != SLASH then |
2428 | 3 | temp_location &= SLASH |
2429 | end if | |
2430 | ||
2431 | ||
2432 | 4 | while 1 do |
2433 | 4 | randname = sprintf("%s%s%06d.%s", {temp_location, temp_prefix, rand(1_000_000) - 1, temp_extn}) |
2434 | 4 | if not file_exists( randname ) then |
2435 | 4 | exit |
2436 | end if | |
2437 | 0 | end while |
2438 | ||
2439 | 4 | if reserve_temp then |
2440 | 0 | integer ret |
2441 | -- Reserve the name by creating an empty file. | |
2442 | 0 | if not file_exists(temp_location) then |
2443 | 0 | if create_directory(temp_location) = 0 then |
2444 | 0 | return "" |
2445 | end if | |
2446 | end if | |
2447 | 0 | ret = write_file(randname, "") |
2448 | end if | |
2449 | ||
2450 | 4 | return randname |
2451 | ||
2452 | end function |