COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/filesys.e303585.71%51463580.94%121
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
disk_metrics()0220.00%22
locate_file()395176.47%12
clear_directory()223170.97%9
temp_file()233271.88%9
walk_dir()273675.00%9
count_files()223073.33%8
move_file()435184.31%8
pathinfo()273479.41%7
disk_size()293485.29%5
file_length()050.00%5
copy_file()202483.33%4
file_timestamp()040.00%4
remove_directory()273187.10%4
canonical_path()394292.86%3
driveid()030.00%3
defaultext()121485.71%2
dir()182090.00%2
init_curdir()020.00%2
rename_file()182090.00%2
default_dir()4580.00%1
absolute_path()77100.00%0
chdir()22100.00%0
create_directory()1313100.00%0
create_file()44100.00%0
curdir()77100.00%0
current_dir()22100.00%0
delete_file()77100.00%0
dir_size()77100.00%0
dirname()66100.00%0
file_exists()88100.00%0
file_type()99100.00%0
filebase()33100.00%0
fileext()33100.00%0
filename()33100.00%0
xstat()22100.00%0
LINE COVERAGE DETAIL
#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
24101
ifdef UNIX then
25
include std/get.e -- for disk_size()
26
end ifdef
27
28
constant
29101
M_DIR = 22,
30101
M_CURRENT_DIR = 23,
31101
M_CHDIR = 63
32
33101
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
47101
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
65101
ifdef LINUX then
66101
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
71101
ifdef UNIX then
72101
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)
74101
constant xDeleteFile = define_c_func(lib, "unlink", {C_POINTER}, C_INT)
75101
constant xCreateDirectory = define_c_func(lib, "mkdir", {C_POINTER, C_INT}, C_INT)
76101
constant xRemoveDirectory = define_c_func(lib, "rmdir", {C_POINTER}, C_INT)
77101
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
152101
ifdef UNIX then
153101
public constant SLASH='/'
154101
public constant SLASHES = "/"
155101
public constant EOLSEP = "\n"
156101
public constant PATHSEP = ':'
157101
public constant NULLDEVICE = "/dev/null"
158101
ifdef OSX then
159
public constant SHARED_LIB_EXT = "dylib"
160
elsedef
161101
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
174101
public constant EOL = '\n'
175
176
--****
177
-- === Directory Handling
178
179
public enum
180101
D_NAME,
181101
D_ATTRIBUTES,
182101
D_SIZE,
183101
D_YEAR,
184101
D_MONTH,
185101
D_DAY,
186101
D_HOUR,
187101
D_MINUTE,
188101
D_SECOND
189
190
--**
191
-- Bad path error code. See [[:walk_dir]]
192
193101
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
27923
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.
28423
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
28821
return machine_func(M_DIR, name)
289
end if
290
291
-- Is there a path involved?
2922
if eu:find(SLASH, name) = 0 then
2931
the_dir = "."
2941
the_name = name
295
else
296
-- Find a SLASH character and break the name there resulting in
297
-- a directory and file name.
2981
idx = rfind(SLASH, name)
2991
the_dir = name[1 .. idx]
3001
the_name = name[idx+1 .. $]
301
end if
302
303
-- Get directory contents
3042
dir_data = machine_func(M_DIR, the_dir)
305
306
-- Did an error occur?
3072
if atom(dir_data) then
3080
return dir_data
309
end if
310
3112
data = {}
312
-- Filter the directory contents returning only those items
313
-- matching name.
3142
for i = 1 to length(dir_data) do
315252
if wildcard_file(the_name, dir_data[i][1]) then
316242
data = append(data, dir_data[i])
317
end if
318252
end for
319
3202
if not length(data) then
321
-- no matches found, act like it doesn't exist
3220
return -1
323
end if
3242
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
347122
348
-- returns name of current working directory
349122
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
3847
3857
return machine_func(M_CHDIR, newdir)
386
end function
387
388
-- Generalized recursive directory walker
389
3904
391
-- Default directory sorting function for walk_dir().
392
-- * sorts by name *
393
object d
394
3954
d = dir(path)
3964
if atom(d) then
3970
return d
398
else
399
-- sort by name
4004
return sort(d)
401
end if
402
end function
403
404
-- override the dir sorting function with your own routine id
405101
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.
412101
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
4894
490
object d, abort_now
491
object orig_func
4924
sequence user_data = {path_name, 0}
493
object source_orig_func
494
object source_user_data
495
4964
orig_func = your_function
4974
if sequence(your_function) then
4981
user_data = append(user_data, your_function[2])
4991
your_function = your_function[1]
500
end if
501
5024
source_orig_func = dir_source
5034
if sequence(dir_source) then
5040
source_user_data = dir_source[2]
5050
dir_source = dir_source[1]
506
end if
507
508
-- get the full directory information
5094
if not equal(dir_source, NO_ROUTINE_ID) then
5100
if atom(source_orig_func) then
5110
d = call_func(dir_source, {path_name})
512
else
5130
d = call_func(dir_source, {path_name, source_user_data})
514
end if
515
5164
elsif my_dir = DEFAULT_DIR_SOURCE then
5174
d = default_dir(path_name)
518
else
5190
d = call_func(my_dir, {path_name})
520
end if
5214
if atom(d) then
5220
return W_BAD_PATH
523
end if
524
525
-- trim any trailing blanks or '\' '/' characters from the path
5264
ifdef not UNIX then
527
path_name = replace_all(path_name, '/', '\\')
528
end ifdef
5294
path_name = trim_tail(path_name, {' ', SLASH, '\n'})
5304
user_data[1] = path_name
531
5324
for i = 1 to length(d) do
53318
if eu:find(d[i][D_NAME], {".", ".."}) then
5348
continue
535
end if
536
53710
user_data[2] = d[i]
53810
abort_now = call_func(your_function, user_data)
53910
if not equal(abort_now, 0) then
5400
return abort_now
541
end if
542
54310
if eu:find('d', d[i][D_ATTRIBUTES]) then
544
-- a directory
5454
if scan_subdirs then
5462
abort_now = walk_dir(path_name & SLASH & d[i][D_NAME],
547
orig_func, scan_subdirs, source_orig_func)
548
5492
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
5520
return abort_now
553
end if
554
end if
555
end if
55610
end for
5574
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
59711
598
atom pname, ret
599
integer pos
600
60111
if length(name) = 0 then
6022
return 0 -- failed
603
end if
604
605
-- Remove any trailing slash.
6069
if name[$] = SLASH then
6071
name = name[1 .. $-1]
608
end if
609
6109
if mkparent != 0 then
6119
pos = rfind(SLASH, name)
6129
if pos != 0 then
6136
ret = create_directory(name[1.. pos-1], mode, mkparent)
614
end if
615
end if
616
6179
pname = allocate_string(name)
618
6199
ifdef UNIX then
6209
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
6269
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
6525
6535
integer fh = open(name, "wb")
6545
close(fh)
6555
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
66757
668
66957
atom pfilename = allocate_string(name)
67057
integer success = c_func(xDeleteFile, {pfilename})
671
67257
ifdef UNIX then
67357
success = not success
674
end ifdef
675
67657
free(pfilename)
677
67857
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
711112
712
713
sequence lCurDir
714112
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
730112
lCurDir = current_dir()
731112
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.
738112
if (lCurDir[$] != SLASH) then
739112
lCurDir &= SLASH
740
end if
741
742112
return lCurDir
743
end function
744
745101
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
7690
7700
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
8061
807
object files
808
integer ret
809
8101
if length(path) > 0 then
8111
if path[$] = SLASH then
8120
path = path[1 .. $-1]
813
end if
814
end if
815
8161
if length(path) = 0 then
8170
return 0 -- Nothing specified to clear. Not safe to assume anything.
818
-- (btw, not allowed to clear root directory)
819
end if
8201
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
8291
files = dir(path)
8301
if atom(files) then
8310
return 0
832
end if
833
8341
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
8451
if length( files ) < 2 then
8460
return 0 -- not a directory
847
end if
848
end ifdef
849
8501
ret = 1
8511
path &= SLASH
852
8531
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
8731
for i = 1 to length(files) do
8745
if files[i][D_NAME][1] = '.' then
8752
continue
876
end if
8773
if eu:find('d', files[i][D_ATTRIBUTES]) then
8782
if recurse then
8790
integer cnt = clear_directory(path & files[i][D_NAME], recurse)
8800
if cnt = 0 then
8810
return 0
882
end if
8830
ret += cnt
884
else
8852
continue
886
end if
887
else
8881
if delete_file(path & files[i][D_NAME]) = 0 then
8890
return 0
890
end if
8911
ret += 1
892
end if
8931
end for
894
end ifdef
8951
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
9213
922
atom pname, ret
923
object files
9243
integer D_NAME = 1, D_ATTRIBUTES = 2
925
926
-- Remove any trailing slash
9273
if length(dir_name) > 0 then
9283
if dir_name[$] = SLASH then
9292
dir_name = dir_name[1 .. $-1]
930
end if
931
end if
932
9333
if length(dir_name) = 0 then
9340
return 0 -- nothing specified to delete.
935
-- (not allowed to delete root directory btw)
936
end if
937
9383
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
9463
files = dir(dir_name)
9473
if atom(files) then
9480
return 0
949
end if
9503
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
9673
if length( files ) < 2 then
9680
return 0
969
end if
970
end ifdef
971
9723
dir_name &= SLASH
9733
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
9863
for i = 1 to length(files) do
98712
if files[i][D_NAME][1] = '.' then
9886
continue
989
end if
9906
if eu:find('d', files[i][D_ATTRIBUTES]) then
9912
ret = remove_directory(dir_name & files[i][D_NAME] & SLASH, force)
992
else
9934
ret = delete_file(dir_name & files[i][D_NAME])
994
end if
9956
if not ret then
9960
return 0
997
end if
9986
end for
999
end ifdef
10003
pname = allocate_string(dir_name)
10013
ret = c_func(xRemoveDirectory, {pname})
10023
ifdef UNIX then
10033
ret = not ret
1004
end ifdef
10053
free(pname)
10063
return ret
1007
end function
1008
1009
1010
--****
1011
-- === File name parsing
1012
1013
public enum
1014101
PATH_DIR,
1015101
PATH_FILENAME,
1016101
PATH_BASENAME,
1017101
PATH_FILEEXT,
1018101
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
106329
1064
integer slash, period, ch
1065
sequence dir_name, file_name, file_ext, file_full, drive_id
1066
106729
dir_name = ""
106829
file_name = ""
106929
file_ext = ""
107029
file_full = ""
107129
drive_id = ""
1072
107329
slash = 0
107429
period = 0
1075
107629
for i = length(path) to 1 by -1 do
1077291
ch = path[i]
1078291
if period = 0 and ch = '.' then
107924
period = i
1080267
elsif eu:find(ch, SLASHES) then
108113
slash = i
108213
exit
1083
end if
1084278
end for
1085
108629
if slash > 0 then
108713
dir_name = path[1..slash-1]
1088
108913
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
109729
if period > 0 then
109824
file_name = path[slash+1..period-1]
109924
file_ext = path[period+1..$]
110024
file_full = file_name & '.' & file_ext
1101
else
11025
file_name = path[slash+1..$]
11035
file_full = file_name
1104
end if
1105
110629
if std_slash != 0 then
11070
if std_slash < 0 then
11080
std_slash = SLASH
11090
ifdef UNIX then
11100
sequence from_slash = "\\"
1111
elsedef
1112
sequence from_slash = "/"
1113
end ifdef
11140
dir_name = replace_all(dir_name, from_slash, std_slash)
1115
else
11160
dir_name = replace_all(dir_name, "\\", std_slash)
11170
dir_name = replace_all(dir_name, "/", std_slash)
1118
end if
1119
end if
1120
112129
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
114816
1149
sequence data
115016
data = pathinfo(path)
115116
if pcd then
11523
if length(data[1]) = 0 then
11533
return "."
1154
end if
1155
end if
115613
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
11803
1181
sequence data
1182
11833
data = pathinfo(path)
1184
11853
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
12081
1209
sequence data
1210
12111
data = pathinfo(path)
1212
12131
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
12375
1238
sequence data
12395
data = pathinfo(path)
12405
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
12630
1264
sequence data
12650
data = pathinfo(path)
12660
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
12897
12907
if length(defext) = 0 then
12910
return path
1292
end if
1293
12947
for i = length(path) to 1 by -1 do
129528
if path[i] = '.' then
1296
-- There is a dot in the file name part
12972
return path
1298
end if
129926
if path[i] = SLASH then
13001
if i = length(path) then
1301
-- No file name in supplied path
13020
return path
1303
else
1304
-- No dot in file name part.
13051
exit
1306
end if
1307
end if
130825
end for
1309
13105
if defext[1] != '.' then
13114
path &= '.'
1312
end if
1313
13145
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
134516
134616
if length(filename) = 0 then
13471
return 0
1348
end if
1349
135015
if eu:find(filename[1], SLASHES) then
13511
return 1
1352
end if
1353
135414
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
137114
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
140315
140415
sequence lPath = ""
140515
integer lPosA = -1
140615
integer lPosB = -1
140715
integer lPosC = -1
140815
sequence lLevel = ""
1409
sequence lHome
1410
141115
ifdef UNIX then
141215
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.
142015
if (length(lPath) > 2 and lPath[1] = '"' and lPath[$] = '"') then
14211
lPath = lPath[2..$-1]
1422
end if
1423
1424
-- Replace any leading tilde with 'HOME' directory.
142515
if (length(lPath) > 0 and lPath[1] = '~') then
14261
ifdef UNIX then
14271
lHome = getenv("HOME")
1428
elsedef
1429
lHome = getenv("HOMEDRIVE") & getenv("HOMEPATH")
1430
end ifdef
1431
14321
if lHome[$] != SLASH then
14331
lHome &= SLASH
1434
end if
1435
14361
if length(lPath) > 1 and lPath[2] = SLASH then
14370
lPath = lHome & lPath[3 .. $]
1438
else
14391
lPath = lHome & lPath[2 .. $]
1440
end if
1441
end if
1442
144315
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.
145315
if ( (length(lPath) = 0) or (lPath[1] != SLASH) )
1454
then
145511
ifdef UNIX then
145611
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.
147415
if ((directory_given != 0) and (lPath[$] != SLASH) ) then
14750
lPath &= SLASH
1476
end if
1477
1478
-- Replace all instances of "/./" with "/"
147915
lLevel = SLASH & '.' & SLASH
148015
while( lPosA != 0 ) with entry do
14813
lPath = lPath[1..lPosA-1] & lPath[lPosA + 2 .. $]
1482
1483
entry
148418
lPosA = match(lLevel, lPath)
148518
end while
1486
1487
-- Replace all instances of "X/Y/../" with "X/"
148815
lLevel = SLASH & ".." & SLASH
1489
149015
while( lPosA != 0 ) with entry do
1491
-- Locate preceding directory separator.
14921
lPosB = lPosA-1
14931
while((lPosB > 0) and (lPath[lPosB] != SLASH)) do
14943
lPosB -= 1
14953
end while
14961
if (lPosB <= 0) then
14970
lPosB = 1
1498
end if
1499
15001
lPath = lPath[1..lPosB-1] & lPath[lPosA + 3 .. $]
1501
1502
entry
150316
lPosA = match(lLevel, lPath)
150416
end while
1505
150615
ifdef WINDOWS then
1507
lPath = lDrive & lPath
1508
if no_case then
1509
lPath = lower(lPath)
1510
end if
1511
end ifdef
1512
151315
return lPath
1514
end function
1515
1516
1517
--****
1518
-- === File Types
1519
1520
public enum
1521101
FILETYPE_UNDEFINED = -1,
1522101
FILETYPE_NOT_FOUND,
1523101
FILETYPE_FILE,
1524101
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
15437
1544
object dirfil
15457
if eu:find('*', filename) or eu:find('?', filename) then return FILETYPE_UNDEFINED end if
1546
15477
ifdef WINDOWS then
1548
if length(filename) = 2 and filename[2] = ':' then
1549
filename &= "\\"
1550
end if
1551
end ifdef
1552
15537
dirfil = dir(filename)
15547
if sequence(dirfil) then
15555
if length( dirfil ) > 1 or eu:find('d', dirfil[1][2]) or (length(filename)=3 and filename[2]=':') then
15561
return FILETYPE_DIRECTORY
1557
else
15584
return FILETYPE_FILE
1559
end if
1560
else
15612
return FILETYPE_NOT_FOUND
1562
end if
1563
end function
1564
1565
--****
1566
-- === File Handling
1567
--
1568
1569
public enum
1570101
SECTORS_PER_CLUSTER,
1571101
BYTES_PER_SECTOR,
1572101
NUMBER_OF_FREE_CLUSTERS,
1573101
TOTAL_NUMBER_OF_CLUSTERS
1574
1575
public enum
1576101
TOTAL_BYTES,
1577101
FREE_BYTES,
1578101
USED_BYTES
1579
1580
public enum
1581101
COUNT_DIRS,
1582101
COUNT_FILES,
1583101
COUNT_SIZE,
1584101
COUNT_TYPES
1585
1586
public enum
1587101
EXT_NAME,
1588101
EXT_COUNT,
1589101
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
160770
160870
if atom(name) then
16091
return 0
1610
end if
1611
161269
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
162069
atom pName = allocate_string(name)
162169
atom r = c_func(xGetFileAttributes, {pName, 0})
162269
free(pName)
1623
162469
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
16430
16440
object d = dir(fname)
16450
if atom(d) then return -1 end if
1646
16470
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
16713
1672
16733
if length(dest) then
16743
if file_type( dest ) = FILETYPE_DIRECTORY then
16750
if dest[$] != SLASH then
16760
dest &= SLASH
1677
end if
16780
sequence info = pathinfo( src )
16790
dest &= info[PATH_FILENAME]
1680
end if
1681
end if
1682
16833
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
16903
integer success = 0
1691
16923
if file_exists(src) then
16933
if overwrite or not file_exists( dest ) then
16941
integer
16951
in = open( src, "rb" ),
16961
out = open( dest, "wb" )
16971
if in != -1 and out != -1 then
16981
integer byte
16991
while byte != -1 with entry do
170013
puts( out, byte )
1701
entry
170214
byte = getc( in )
170314
end while
17041
success = 1
17051
close( in )
17061
close( out )
1707
end if
1708
end if
1709
end if
1710
1711
end ifdef
1712
17133
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
17394
1740
atom psrc, pdest, ret
17414
sequence tempfile = ""
1742
17434
if not overwrite then
17442
if file_exists(dest) then
17452
return 0
1746
end if
1747
else
17482
if file_exists(dest) then
17491
tempfile = temp_file(dest)
17501
ret = move_file(dest, tempfile)
1751
end if
1752
end if
1753
1754
17552
psrc = allocate_string(src)
17562
pdest = allocate_string(dest)
17572
ret = c_func(xMoveFile, {psrc, pdest})
1758
17592
ifdef UNIX then
17602
ret = not ret
1761
end ifdef
1762
17632
free({pdest, psrc})
1764
17652
if overwrite then
17662
if not ret then
17670
if length(tempfile) > 0 then
1768
-- rename was unsuccessful so restore from tempfile
17690
ret = move_file(tempfile, dest)
1770
end if
1771
end if
17722
delete_file(tempfile)
1773
end if
1774
17752
return ret
1776
end function
1777
1778101
ifdef LINUX then
177914
178014
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
18068
18078
atom psrc = 0, pdest = 0, ret
18088
sequence tempfile = ""
1809
18108
if not file_exists(src) then
18111
return 0
1812
end if
1813
18147
if not overwrite then
18155
if file_exists( dest ) then
18162
return 0
1817
end if
1818
end if
1819
18205
ifdef UNIX then
18215
atom psrcbuf = 0, pdestbuf = 0
18225
integer stat_t_offset, dev_t_size, stat_buf_size
1823
end ifdef
18245
ifdef LINUX then
18255
stat_t_offset = 0
18265
stat_buf_size = 88
18275
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
18415
ifdef UNIX then
18425
psrcbuf = allocate(stat_buf_size)
18435
psrc = allocate_string(src)
18445
ret = xstat(psrc, psrcbuf)
18455
if ret then
18460
free({psrcbuf, psrc})
18470
return 0
1848
end if
1849
18505
pdestbuf = allocate(stat_buf_size)
18515
pdest = allocate_string(dest)
18525
ret = xstat(pdest, pdestbuf)
18535
if ret then
1854
-- Assume destination doesn't exist
18554
atom pdir
18564
if length(dirname(dest)) = 0 then
18571
pdir = allocate_string(current_dir())
1858
else
18593
pdir = allocate_string(dirname(dest))
1860
end if
18614
ret = xstat(pdir, pdestbuf)
18624
free(pdir)
1863
end if
1864
18655
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
18680
ret = copy_file(src, dest, overwrite)
18690
if ret then
18700
ret = delete_file(src)
1871
end if
18720
free({psrcbuf, psrc, pdestbuf, pdest})
18730
return (not ret)
1874
end if
1875
1876
elsedef
1877
psrc = allocate_string(src)
1878
pdest = allocate_string(dest)
1879
end ifdef
1880
18815
if overwrite then
1882
-- return value is ignored, we don't care if it existed or not
18832
tempfile = temp_file(dest)
18842
move_file(dest, tempfile)
1885
end if
1886
18875
ret = c_func(xMoveFile, {psrc, pdest})
1888
18895
ifdef UNIX then
18905
ret = not ret
18915
free({psrcbuf, pdestbuf})
1892
end ifdef
18935
free({pdest, psrc})
1894
18955
if overwrite then
18962
if not ret then
1897
-- move was unsuccessful so restore tempfile
18980
move_file(tempfile, dest)
1899
end if
19002
delete_file(tempfile)
1901
end if
1902
19035
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
19210
1922
object list
19230
list = dir(filename)
19240
if atom(list) or length(list) = 0 then
19250
return -1
1926
end if
19270
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
19784
1979
object extra_paths
1980
sequence this_path
1981
19824
if absolute_path(filename) then
19830
return filename
1984
end if
1985
19864
if length(search_list) = 0 then
19874
search_list = append(search_list, "." & SLASH)
1988
19894
extra_paths = command_line()
19904
extra_paths = canonical_path(dirname(extra_paths[2]), 1)
19914
search_list = append(search_list, extra_paths)
1992
19934
ifdef UNIX then
19944
extra_paths = getenv("HOME")
1995
1996
elsedef
1997
extra_paths = getenv("HOMEDRIVE") & getenv("HOMEPATH")
1998
end ifdef
1999
20004
if sequence(extra_paths) then
20014
search_list = append(search_list, extra_paths & SLASH)
2002
end if
2003
20044
search_list = append(search_list, ".." & SLASH)
2005
20064
ifdef UNIX then
2007
-- typical install directories:
20084
search_list = append( search_list, "/usr/local/share/euphoria/bin/" )
20094
search_list = append( search_list, "/usr/share/euphoria/bin/" )
2010
end ifdef
2011
20124
search_list &= include_paths(1)
2013
20144
extra_paths = getenv("EUDIR")
20154
if sequence(extra_paths) then
20164
search_list = append(search_list, extra_paths & SLASH & "bin" & SLASH)
20174
search_list = append(search_list, extra_paths & SLASH & "docs" & SLASH)
2018
end if
2019
20204
extra_paths = getenv("EUDIST")
20214
if sequence(extra_paths) then
20220
search_list = append(search_list, extra_paths & SLASH)
20230
search_list = append(search_list, extra_paths & SLASH & "etc" & SLASH)
20240
search_list = append(search_list, extra_paths & SLASH & "data" & SLASH)
2025
end if
2026
20274
extra_paths = getenv("USERPATH")
20284
if sequence(extra_paths) then
20290
extra_paths = split(PATHSEP, extra_paths)
20300
search_list &= extra_paths
2031
end if
2032
20334
extra_paths = getenv("PATH")
20344
if sequence(extra_paths) then
20354
extra_paths = split(PATHSEP, extra_paths)
20364
search_list &= extra_paths
2037
end if
2038
else
20390
if integer(search_list[1]) then
20400
search_list = split(PATHSEP, search_list)
2041
end if
2042
end if
2043
20444
if length(subdir) > 0 then
20450
if subdir[$] != SLASH then
20460
subdir &= SLASH
2047
end if
2048
end if
2049
20504
for i = 1 to length(search_list) do
205128
if length(search_list[i]) = 0 then
20520
continue
2053
end if
2054
205528
if search_list[i][$] != SLASH then
205610
search_list[i] &= SLASH
2057
end if
2058
2059
206028
if length(subdir) > 0 then
20610
this_path = search_list[i] & subdir & filename
2062
else
206328
this_path = search_list[i] & filename
2064
end if
2065
206628
if file_exists(this_path) then
20673
return canonical_path(this_path)
2068
end if
2069
207025
end for
20711
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
20900
20910
sequence result = {0, 0, 0, 0}
20920
atom path_addr = 0
20930
atom metric_addr = 0
2094
20950
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
21150
sequence disk_size = {0,0,0}
2116
21170
atom bytes_per_cluster
21180
atom psrc, ret, psrcbuf
21190
integer stat_t_offset, dev_t_size, stat_buf_size
2120
21210
ifdef LINUX then
21220
stat_t_offset = 48
21230
stat_buf_size = 88
21240
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
21370
psrc = allocate_string(disk_path)
21380
psrcbuf = allocate(stat_buf_size)
21390
ret = xstat(psrc,psrcbuf)
21400
bytes_per_cluster = peek4s(psrcbuf+stat_t_offset)
21410
free({psrcbuf, psrc})
21420
if ret then
2143
-- failure
21440
return result
2145
end if
2146
21470
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
21600
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
21781
21791
sequence disk_size = {0,0,0, disk_path}
2180
21811
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
21941
integer temph
21951
sequence tempfile
21961
object data
21971
sequence filesys = ""
2198
21991
tempfile = "/tmp/eudf" & sprintf("%d", rand(1000)) & ".tmp"
22001
system("df "&disk_path&" > "&tempfile, 2)
2201
22021
temph = open(tempfile, "r")
22031
if temph = -1 then
2204
-- failure
22050
return disk_size
2206
end if
2207
-- skip the human readable header
22081
data = gets(temph)
2209
-- skip the name of the device node
22101
while 1 do
221110
data = getc(temph)
221210
if find(data," \t\r\n") then
22131
exit
2214
end if
22159
if data = -1 then
2216
-- failure
22170
close(temph)
22180
temph = delete_file(tempfile)
22190
disk_size[4] = filesys
22200
return disk_size
2221
end if
22229
filesys &= data
2223
22249
end while
2225
22261
data = get(temph)
22271
disk_size[TOTAL_BYTES] = data[2] * 1024
22281
data = get(temph)
22291
disk_size[USED_BYTES] = data[2] * 1024
22301
data = get(temph)
22311
disk_size[FREE_BYTES] = data[2] * 1024
22321
disk_size[4] = filesys
2233
22341
close(temph)
22351
temph = delete_file(tempfile)
2236
2237
end ifdef
2238
22391
return disk_size
2240
end function
2241
2242101
sequence file_counters = {}
2243
2244
-- Parameter inst contains two items: 'count_all' flag, and 'index' into file_counters.
2245
22463
22473
integer pos = 0
2248
sequence ext
2249
22503
orig_path = orig_path
22513
if equal(dir_info[D_NAME], ".") then
22520
return 0
2253
end if
22543
if equal(dir_info[D_NAME], "..") then
22550
return 0
2256
end if
2257
2258
22593
if inst[1] = 0 then -- count all is false
22603
if find('h', dir_info[D_ATTRIBUTES]) then
22610
return 0
2262
end if
2263
22643
if find('s', dir_info[D_ATTRIBUTES]) then
22650
return 0
2266
end if
2267
end if
2268
22693
file_counters[inst[2]][COUNT_SIZE] += dir_info[D_SIZE]
22703
if find('d', dir_info[D_ATTRIBUTES]) then
22712
file_counters[inst[2]][COUNT_DIRS] += 1
2272
else
22731
file_counters[inst[2]][COUNT_FILES] += 1
22741
ifdef not UNIX then
2275
ext = fileext(lower(dir_info[D_NAME]))
2276
elsedef
22771
ext = fileext(dir_info[D_NAME])
2278
end ifdef
2279
22801
pos = 0
22811
for i = 1 to length(file_counters[inst[2]][COUNT_TYPES]) do
22820
if equal(file_counters[inst[2]][COUNT_TYPES][i][EXT_NAME], ext) then
22830
pos = i
22840
exit
2285
end if
22860
end for
2287
22881
if pos = 0 then
22891
file_counters[inst[2]][COUNT_TYPES] &= {{ext, 0, 0}}
22901
pos = length(file_counters[inst[2]][COUNT_TYPES])
2291
end if
2292
22931
file_counters[inst[2]][COUNT_TYPES][pos][EXT_COUNT] += 1
22941
file_counters[inst[2]][COUNT_TYPES][pos][EXT_SIZE] += dir_info[D_SIZE]
2295
end if
2296
22973
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
23341
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
23411
file_counters = append(file_counters, {0,0,0,{}})
23421
ok = walk_dir(dir_path, {routine_id("count_files"), {count_all, length(file_counters)}}, 0)
2343
23441
fc = file_counters[$]
23451
file_counters = file_counters[1 .. $-1]
23461
fc[COUNT_TYPES] = sort(fc[COUNT_TYPES])
2347
23481
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
23854
2386
sequence randname
2387
23884
if length(temp_location) = 0 then
23891
object envtmp
23901
envtmp = getenv("TEMP")
23911
if atom(envtmp) then
23921
envtmp = getenv("TMP")
2393
end if
23941
ifdef WIN32 then
2395
if atom(envtmp) then
2396
envtmp = "C:\\temp\\"
2397
end if
2398
elsedef
23991
if atom(envtmp) then
24001
envtmp = "/tmp/"
2401
end if
2402
end ifdef
24031
temp_location = envtmp
2404
else
24053
switch file_type(temp_location) do
2406
case FILETYPE_FILE then
24072
temp_location = dirname(temp_location, 1)
2408
2409
case FILETYPE_DIRECTORY then
2410
-- use temp_location
24110
temp_location = temp_location
2412
2413
case FILETYPE_NOT_FOUND then
24141
object tdir = dirname(temp_location, 1)
24151
if file_exists(tdir) then
24161
temp_location = tdir
2417
else
24180
temp_location = "."
2419
end if
2420
2421
case else
24220
temp_location = "."
2423
2424
end switch
2425
end if
2426
24274
if temp_location[$] != SLASH then
24283
temp_location &= SLASH
2429
end if
2430
2431
24324
while 1 do
24334
randname = sprintf("%s%s%06d.%s", {temp_location, temp_prefix, rand(1_000_000) - 1, temp_extn})
24344
if not file_exists( randname ) then
24354
exit
2436
end if
24370
end while
2438
24394
if reserve_temp then
24400
integer ret
2441
-- Reserve the name by creating an empty file.
24420
if not file_exists(temp_location) then
24430
if create_directory(temp_location) = 0 then
24440
return ""
2445
end if
2446
end if
24470
ret = write_file(randname, "")
2448
end if
2449
24504
return randname
2451
2452
end function