1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2007, 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 <export> {
15 /*-----------------------------------------------------------------------------
16 * Id: fcopyflags D
17 *
18 * Summary: Flags for copyfiles.
19 *
20 -----------------------------------------------------------------------------*/
21 COPYF_RO = 0x0100 // Overwrite files with the attribute read-only.
22 COPYF_SAVEPATH = 0x0200 // Keep relative paths while copying files /
23 // from subdirectories.
24 COPYF_ASK = 0x0400 // Prompt before copying files already existing.
25
26 /*-----------------------------------------------------------------------------
27 * Id: fcopymode D
28 *
29 * Summary: Mode for copyfiles.
30 *
31 -----------------------------------------------------------------------------*/
32 COPY_OVER = 0 // Overwrite.
33 COPY_SKIP // Skip.
34 COPY_NEWER // Overwrite if newer.
35 COPY_MODIFIED // Overwrite if modified.
36
37 /*-----------------------------------------------------------------------------
38 * Id: fcopymsg D
39 *
40 * Summary: Message codes for copyfiles.
41 *
42 -----------------------------------------------------------------------------*/
43 COPYN_FOUND = 1 // The object for copying is found.
44 COPYN_NEWDIR // A directory is created.
45 COPYN_ERRDIR // Cannot create a directory.
46 COPYN_ASK // Copy request.
47 COPYN_ERRFILE // Error while creating a file.
48 COPYN_NEWFILE // A file was created.
49 COPYN_BEGIN // Start copying file.
50 COPYN_PROCESS // A file is being copied.
51 COPYN_END // Copying is over.
52 COPYN_ERRWRITE // Error while writing a file.
53
54 /*-----------------------------------------------------------------------------
55 * Id: fcopyret D
56 *
57 * Summary: Return codes for copyfiles.
58 *
59 -----------------------------------------------------------------------------*/
60 COPYR_NOTHING = 0 // Do nothing.
61 COPYR_BREAK // Break copying.
62 COPYR_RETRY // Retry.
63 COPYR_SKIP // Skip.
64 COPYR_OVER // Write over.
65 COPYR_OVERALL // Write over all files.
66 COPYR_SKIPALL // Skip all files.
67 //-----------------------------------------------------------------------------
68 }
69
70 /*-----------------------------------------------------------------------------
71 * Id: isequalfiles F
72 *
73 * Summary: Check if files are equal. The function compares two files.
74 *
75 * Params: left - The name of the first file to be compared.
76 right - The name of the second file to be compared.
77 *
78 * Return: The function returns 1 if the files are equal, otherwise it
79 returns 0.
80 *
81 -----------------------------------------------------------------------------*/
82
83 func uint isequalfiles( str left, str right )
84 {
85 file fleft fright
86 uint lsize result temp size
87 buf lbuf rbuf
88
89 if !fleft.open( left, $OP_READONLY ) : return 0
90 lsize = fleft.getsize( )
91 size = 0x8000
92 if fright.open( right, $OP_READONLY ) && lsize == fright.getsize()
93 {
94 while lsize
95 {
96 temp = min( lsize, size )//300000 )
97 lbuf.use = 0
98 rbuf.use = 0
99 fleft.read( lbuf, temp )
100 fright.read( rbuf, temp )
101 if mcmp( lbuf.ptr(), rbuf.ptr(), temp ) : break
102 lsize -= temp
103 size = 0x80000
104 }
105 if !lsize : result = 1
106 }
107 fleft.close()
108 fright.close()
109 return result
110 }
111
112 /*-----------------------------------------------------------------------------
113 * Id: copyfiles F
114 *
115 * Summary: Copying files and directories by mask.
116 *
117 * Params: src - The names of mask of the files or directories being copied.
118 dir - The directory where files will be copied.
119 flag - The combination of search and copy flags./
120 $$[findflags]$$[fcopyflags]
121 mode - What to do if the file being copied already /
122 exists.$$[fcopymode]
123 proccess - The identifier of the function handling messages. /
124 You can use #b(&defcopyproc) as a default process function.
125 *
126 * Return: The function returns 1 if the copy operation is successful,
127 otherwise it returns 0.
128 *
129 -----------------------------------------------------------------------------*/
130
131 func uint copyfiles( str src, str dir, uint flag, uint mode, uint process )
132 {
133 uint notifyret
134
135 subfunc uint notify( uint code, uint left right )
136 {
137 if process : notifyret = process->func( code, left, right )
138 return notifyret
139 }
140
141 ffind fd
142 str destname srcdir temp wcard
143 arrstr dirs
144 uint i
145
146 src.ffullname( src )
147 dir.ffullname( dir )
148 srcdir.fgetdir( src )
149 wcard.fnameext( src )
150
151 fd.init( src, flag )
152
153 foreach finfo cur, fd
154 {
155 if flag & $COPYF_SAVEPATH : temp.copy( cur.fullname.ptr() + *srcdir + 1 )
156 else : temp = cur.name
157 ( destname = dir ).faddname( temp )
158
159 if notify( $COPYN_FOUND, &cur, &destname ) == $COPYR_SKIP : continue
160
161 if cur.attrib & $FILE_ATTRIBUTE_DIRECTORY : temp = destname
162 else : temp.fgetdir( destname )
163
164 label dirretry
165 if !verifypath( temp, dirs )
166 {
167 notify( $COPYN_ERRDIR, &dirs[*dirs - 1], 0 )
168 if notifyret == $COPYR_RETRY : goto dirretry
169 if notifyret == $COPYR_BREAK : return 0
170 }
171
172 foreach str ndir, dirs : notify( $COPYN_NEWDIR, &ndir, 0 )
173
174 if cur.attrib & $FILE_ATTRIBUTE_DIRECTORY
175 {
176 if !( flag & $FIND_RECURSE ) || wcard != "*.*"
177 {
178 ( temp = cur.fullname ).faddname( "*.*" )
179 copyfiles( temp, destname, flag | $FIND_RECURSE, mode, process )
180 }
181 }
182 else
183 {
184 uint noexist
185
186 if fileexist( destname )
187 {
188 finfo fi
189
190 if mode == $COPY_SKIP : continue
191
192 getfileinfo( destname, fi )
193
194 if mode == $COPY_NEWER &&
195 CompareFileTime( cur.lastwrite, fi.lastwrite ) <= 0
196 {
197 continue
198 }
199 if mode == $COPY_MODIFIED && fi.sizelo == cur.sizelo &&
200 isequalfiles( cur.fullname, destname )
201 {
202 continue
203 }
204 if flag & $COPYF_ASK
205 {
206 notify( $COPYN_ASK, &cur, &fi )
207 switch notifyret
208 {
209 case $COPYR_BREAK : return 0
210 case $COPYR_SKIP : continue
211 case $COPYR_OVERALL : flag &= ~$COPYF_ASK
212 case $COPYR_SKIPALL
213 {
214 mode = $COPY_SKIP
215 continue
216 }
217 }
218 }
219 if flag & $COPYF_RO && fi.attrib & $FILE_ATTRIBUTE_READONLY
220 {
221 setattribnormal( destname )
222 }
223 }
224 else : noexist = 1
225
226 file fsrc fdest
227 uint size icopy
228 buf cbuf
229
230 label fileretry
231
232 if !fsrc.open( cur.fullname, $OP_READONLY )
233 {
234 switch notify( $COPYN_ERRFILE, &cur.fullname, 0 )
235 {
236 case $COPYR_BREAK : return 0
237 case $COPYR_RETRY : goto fileretry
238 case $COPYR_SKIP : continue
239 }
240 }
241
242 if !fdest.open( destname, $OP_CREATE )
243 {
244 fsrc.close( )
245 switch notify( $COPYN_ERRFILE, &destname, 0 )
246 {
247 case $COPYR_BREAK : return 0
248 case $COPYR_RETRY : goto fileretry
249 case $COPYR_SKIP : continue
250 }
251 }
252
253 if noexist : notify( $COPYN_NEWFILE, &destname, 0 )
254
255 notify( $COPYN_BEGIN, &cur, &destname )
256 size = cur.sizelo
257
258 uint copied = 0
259 while size
260 {
261 icopy = min( size, 0x80000 )//300000 )
262 cbuf.use = 0
263 fsrc.read( cbuf, icopy )
264 label writeretry
265 if !fdest.write( cbuf )
266 {
267 switch notify( $COPYN_ERRWRITE, &destname, 0 )
268 {
269 case $COPYR_BREAK : return 0
270 case $COPYR_RETRY : goto writeretry
271 case $COPYR_SKIP : break
272 }
273 }
274 notify( $COPYN_PROCESS, &destname,
275 uint( long( copied += icopy ) * 100L / long( cur.sizelo )))
276 size -= icopy
277 }
278 //SetFileTime( hdest, 0->filetime, 0->filetime, cur.lastwrite )
279 fdest.settime( cur.lastwrite )
280 fdest.close( )
281 fsrc.close( )
282 setfileattrib( destname, cur.attrib )
283 notify( $COPYN_END, &cur, &destname )
284 }
285 }
286 return 1
287 }
288
289 /*-----------------------------------------------------------------------------
290 ** Id: copyfiles_1 F8
291 *
292 * Summary: This is a default process function for #b(copyfiles). You can
293 develop and use your own process function like it.
294 *
295 * Params: code - The message code.$$[fcopymsg]
296 left - Additional parameter.
297 right - Additional parameter.
298 *
299 * Return: You should return one of the following values: $$[fcopyret]
300 *
301 -----------------------------------------------------------------------------*/
302
303 func uint defcopyproc( uint code, uint left, uint right )
304 {
305 switch code
306 {
307 /* case $COPYN_FOUND {
308 print("FOUND = \( left->finfo.fullname ) to \( right->str )\n")
309 }
310 case $COPYN_NEWDIR {
311 print("NEWDIR = \( left->str )\n")
312 }
313 case $COPYN_NEWFILE {
314 print("NEWFILE = \( left->str )\n")
315 }*/
316 case $COPYN_BEGIN {
317 print("Copying \( right->str ) 0%\r")
318 }
319 case $COPYN_PROCESS {
320 print("Copying \( left->str ) \( right )%\r")
321 }
322 case $COPYN_END {
323 print("Copied \( right->str ) 100%\n")
324 }
325 case $COPYN_ERRDIR {
326 return ?( conrequest("Cannot create a directory \( left->str )!
327 Abort [A] | Retry [R] : ", "Aa|Rr" ), $COPYR_RETRY, $COPYR_BREAK )
328 }
329 case $COPYN_ASK {
330 str edate etime
331 str ndate ntime
332 uint ret
333
334 getfiledatetime( right->finfo.lastwrite, edate, etime )
335 getfiledatetime( left->finfo.lastwrite, ndate, ntime )
336
337 ret = conrequest("File already exists
338 Existing File: \( right->finfo.fullname )
339 Size: \( right->finfo.sizelo ) Date: \(edate) Time: \(etime)
340 New File: \( left->finfo.fullname )
341 Size: \( left->finfo.sizelo ) Date: \(ndate) Time: \(ntime)
342
343 Overwrite [O] | Skip [S] | Overwrite All [V] | Skip All [K] | Abort [A] : ",
344 "Oo|Ss|Vv|Kk|Aa" )
345 switch ret
346 {
347 case 0 : return $COPYR_OVER
348 case 1 : return $COPYR_SKIP
349 case 2 : return $COPYR_OVERALL
350 case 3 : return $COPYR_SKIPALL
351 case 4 : return $COPYR_BREAK
352 }
353 }
354 case $COPYN_ERRFILE, $COPYN_ERRWRITE {
355 switch conrequest( "Cannot \( ?( code == $COPYN_ERRFILE,"open/create a file","write to a file" )) \( left->str )!
356 Abort [A] | Retry [R] | Skip [S]: ", "Aa|Rr|Ss" )
357 {
358 case 0: return $COPYR_BREAK
359 case 1: return $COPYR_RETRY
360 case 2: return $COPYR_SKIP
361 }
362 }
363 }
364 return 0
365 }
366