1 /******************************************************************************
2 *
3 * Copyright (C) 2009, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * Author: Alexey Krivonogov ( gentee )
11 *
12 ******************************************************************************/
13
14 define
15 {
16 FL_FILES = 0x0001 // Seek just files
17 FL_RECURSIVE = 0x0002 // Recursive search
18 FL_EMPTYFLD = 0x0004 // Empty folders
19
20 FL_BLOCKSIZE = 1000000
21
22 FL_ROOT = 1
23 FL_FOLDER
24 FL_FILE
25 }
26
27 /* Block
28 uint count of items
29 [
30 byte type
31 short size
32 строка
33 ]
34 */
35
36 type flinfo
37 {
38 uint itype
39 str name
40 }
41
42 type filelist< index = flinfo>
43 {
44 uint flags
45 uint files // Count of files
46 long summarysize
47 uint bcount // Count block - 1
48 uint off // current offset in the block
49 str root // current root
50 str folder // current folder
51 arr block of uint
52 // Для foreach
53 uint iblock // Текущий блок
54 uint icur // Текущий элемент
55 uint eof
56 flinfo fl
57 }
58
59 method filelist.newblock
60 {
61 uint i = .block.expand(1)
62
63 .block[ i ] = malloc( $FL_BLOCKSIZE )
64 .block[ i ]->uint = 0
65 .bcount = *.block - 1
66 .off = sizeof( uint )
67 }
68
69 method filelist filelist.init()
70 {
71 this.newblock()
72 return this
73 }
74
75 method filelist filelist.delete()
76 {
77 uint i
78 fornum i, *this.block : mfree( this.block[ i ] )
79
80 return this
81 }
82
83 method uint str.isexclude( arrstr exclude )
84 {
85 if *exclude
86 {
87 foreach cure, exclude
88 {
89 if this.fwildcard( cure ) : return 1
90 }
91 }
92 return 0
93 }
94
95 method filelist.additem( uint itype, str value )
96 {
97 uint start
98 uint ptr size = *value + 1
99
100 if itype == $FL_FILE
101 {
102 str folder
103
104 folder.fgetdir( value )
105 if folder %!= this.folder : this.additem( $FL_FOLDER, folder )
106 start = *this.folder + 1
107 this.files++
108 }
109 elif itype == $FL_FOLDER
110 {
111 start = *this.root + ?( *value > *this.root, 1, 0 )
112 this.folder = value
113 }
114
115 if .off + size + 16 > $FL_BLOCKSIZE : this.newblock()
116
117
118 ptr = .block[ .bcount ] + .off
119
120 // print("Add=\(itype) \( value )\n")
121 ptr->ubyte = itype
122 size -= start
123 ( ptr + 1 )->ushort = size
124 mcopy( ptr + 3, value.ptr() + start, size )
125 .off += size + 3
126 .block[ .bcount ]->uint = .block[ .bcount ]->uint + 1
127 }
128
129 method uint filelist.adddir( str src, arrstr exclude, uint flags )
130 {
131 str wildcard dirsearch dirname = src
132 ffind fd fdfile
133 uint hasdirs
134
135 if direxist( dirname )
136 {
137 hasdirs = 1
138 dirname.faddname( "*.*" )
139 dirsearch = dirname
140 flags |= $FL_RECURSIVE
141 }
142 else : dirsearch.fgetdir( src ).faddname( "*.*" )
143
144 wildcard.fnameext( dirname )
145
146 fd.init( dirsearch, $FIND_DIR )
147 foreach cur, fd
148 {
149 str stemp
150
151 hasdirs = 2
152 if cur.name.isexclude( exclude ) : continue
153 if cur.name.fwildcard( wildcard )
154 {
155 this.adddir( cur.fullname, exclude, flags | $FL_RECURSIVE )
156 }
157 elif flags & $FL_RECURSIVE
158 {
159 this.adddir( ( stemp = cur.fullname ).faddname( wildcard ), exclude, flags )
160 }
161 }
162 fdfile.init( dirname, $FIND_FILE )
163 foreach curf, fdfile
164 {
165 if curf.name.isexclude( exclude ) : continue
166 this.summarysize += long( curf.sizelo )
167 // print("\(this.summarysize) \(cur.fullname)\n")
168 this.additem( $FL_FILE, curf.fullname )
169 }
170 if hasdirs == 1 && flags & $FL_EMPTYFLD
171 {
172 fdfile.init( dirsearch, $FIND_FILE )
173 foreach curf, fdfile
174 {
175 hasdirs = 0
176 break
177 }
178 if hasdirs : this.additem( $FL_FOLDER, src )
179 }
180 return 1
181 }
182
183 method uint filelist.addfiles( arrstr src exclude, arr aflags of uint )
184 {
185 uint icur
186 uint recurse
187
188 foreach cursrc, src
189 {
190 ffind fd
191 uint dir
192
193 if !*cursrc : continue
194 // wcard.fnameext( cursrc )
195 .root.fgetdir( cursrc )
196 .additem( $FL_ROOT, .root )
197 .folder = .root
198 // .folder.clear()
199 if *aflags > icur
200 {
201 this.flags = aflags[ icur ]
202 recurse = ?( this.flags & $FL_RECURSIVE, $FIND_RECURSE, 0 )
203 }
204 icur++
205 if this.flags & $FL_FILES
206 {
207 uint recok = recurse
208
209 if recok
210 {
211 str rdir
212
213 rdir.fgetdir( cursrc )
214 if *rdir > 1 && rdir[1] == ':' && cursrc.findch('*') >= *cursrc &&
215 cursrc.findch('?') >= *cursrc : recok = 0
216 }
217
218 fd.init( cursrc, $FIND_FILE | recok )
219 foreach cur, fd
220 {
221 if cur.name.isexclude( exclude ) : continue
222 this.summarysize += long( cur.sizelo )
223 // print("\(this.summarysize) \(cur.fullname)\n")
224 this.additem( $FL_FILE, cur.fullname )
225 }
226 continue
227 }
228 this.adddir( cursrc, exclude, this.flags )
229 }
230 return this.files
231 }
232
233 method uint filelist.eof( fordata fd )
234 {
235 return .eof
236 }
237
238 method uint filelist.first( fordata fd )
239 {
240 uint off
241
242 .iblock = 0
243 .icur = 0
244 fd.icur = sizeof( uint )
245 if !( .block[ .iblock ]->uint )
246 {
247 .eof = 1
248 return 0
249 }
250 .eof = 0
251 off = .block[ .iblock ] + fd.icur
252 this.fl.itype = off->ubyte
253 this.fl.name.copy( off + 3, (off + 1)->ushort - 1 )
254 fd.icur += (off + 1)->ushort + 3
255 return &this.fl
256 }
257
258 method uint filelist.next( fordata fd )
259 {
260 uint off
261
262 .icur++
263 if .icur == .block[.iblock]->uint
264 {
265 .iblock++
266 if .iblock > .bcount
267 {
268 .eof = 1
269 return 0
270 }
271 .icur++
272 fd.icur = sizeof( uint )
273 }
274 off = .block[ .iblock ] + fd.icur
275 this.fl.itype = off->ubyte
276 this.fl.name.copy( off + 3, (off + 1)->ushort - 1 )
277 fd.icur += (off + 1)->ushort + 3
278 return &this.fl
279 }
280
281