Version:
~ [ 10.0 ] ~
** Warning: Cannot open xref database.
1
2 /* $Id: fileloop.c,v 1.5 2005/01/24 17:16:47 icreedon Exp $ */
3
4 /******************************************************************************
5
6 UserLand Frontier(tm) -- High performance Web content management,
7 object database, system-level and Internet scripting environment,
8 including source code editing and debugging.
9
10 Copyright (C) 1992-2004 UserLand Software, Inc.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
26 ******************************************************************************/
27
28 #include "frontier.h"
29 #include "standard.h"
30
31 #include "memory.h"
32 #include "strings.h"
33 #include "error.h"
34 #include "file.h"
35 #include "oplist.h"
36 #include "fileloop.h"
37
38
39
40
41 #ifdef MACVERSION
42 typedef struct tyfilelooprecord {
43
44 short vnum; /*the volume we're looping through*/
45
46 long dirid; /*the folder we're looking in*/
47
48 short ixdirectory; /*index for the next file to look at*/
49
50 hdllistrecord hfilelist; /*a list of filenames to be looped over*/
51 } tyfilelooprecord, *ptrfilelooprecord, **hdlfilelooprecord;
52
53
54
55
56 static boolean fileloopreleaseitem (Handle h) {
57
58 /*
59 callback routine that disposes of one of our items. since there are no
60 handles linked into our handle, there's nothing to release.
61
62 I just wanted to have one of these around so the next guy that uses the
63 list facilty knows how to link a releaseitem callback routine.
64 */
65
66 return (true);
67 } /*fileloopreleaseitem*/
68
69
70 boolean diskinitloop (tyfileloopcallback diskfilter, Handle *hdiskloop) {
71
72 /*
73 same as fileinitloop, but for volumes on line
74
75 8/15/92 dmb: added, but commented out, diskfilter support
76 */
77
78 tyfilelooprecord info;
79 ParamBlockRec pb;
80 register hdlfilelooprecord h;
81 short ix;
82 hdllistrecord hlist;
83
84 clearbytes (&pb, sizeof (pb)); /*init all fields to zero*/
85
86 clearbytes (&info, sizeof (info));
87
88 info.ixdirectory = 1; /*start with the first file*/
89
90 if (!newfilledhandle (&info, sizeof (info), hdiskloop))
91 return (false);
92
93 h = (hdlfilelooprecord) *hdiskloop; /*copy into register*/
94
95 hlist = nil;
96
97 if (!opnewlist (&hlist, false))
98 goto error;
99
100 (**h).hfilelist = hlist;
101
102 opsetreleaseitemcallback (hlist, &fileloopreleaseitem);
103
104 ix = 1; /*start with file index 1*/
105
106 while (true) {
107 FSSpec fsvol;
108 OSErr errcode;
109 Handle hstring;
110 #if TARGET_API_MAC_CARBON == 1
111 HFSUniStr255 theName;
112 //Code change by Timothy Paustian Thursday, June 29, 2000 10:29:59 AM
113 //Updated to modern call for volume infomation
114 //Ii am checking this now against the original.
115 FSVolumeRefNum vRefNum;//this is just a SInt16
116
117 //Watch out that the fsvol.name parameter works as expected.
118 //this is still not working the way it should
119 errcode = FSGetVolumeInfo(0, ix, &vRefNum, kFSVolInfoNone, nil, &theName, nil);
120 if (errcode == nsvErr) /*not an error, just ran out of volumes*/
121 return (true);
122
123 {
124 UnicodeToTextInfo theInfo;
125 UnicodeMapping theMapping;
126 theMapping.unicodeEncoding = kTextEncodingUnicodeDefault;
127 theMapping.otherEncoding = kTextEncodingMacRoman;
128 theMapping.mappingVersion = kUnicodeUseLatestMapping;
129 errcode = CreateUnicodeToTextInfo(&theMapping,&theInfo);
130 if (oserror (errcode)) // 1/29/97 dmb: call oserror
131 goto error;
132 //fsvol.name[0] = theName.length;
133 errcode = ConvertFromUnicodeToPString (theInfo, theName.length * 2, theName.unicode, fsvol.name);
134 if (oserror (errcode)) // 1/29/97 dmb: call oserror
135 goto error;
136 }
137 ix++;
138 fsvol.vRefNum = vRefNum;
139
140 #else //not carbon
141 pb.volumeParam.ioVolIndex = ix++;
142
143 pb.volumeParam.ioNamePtr = fsvol.name;
144
145 errcode = PBGetVInfoSync (&pb);
146 fsvol.vRefNum = pb.volumeParam.ioVRefNum;
147
148 if (errcode == nsvErr) /*not an error, just ran out of volumes*/
149 return (true);
150 #endif//end carbon
151
152 if (errcode == nsvErr) /*not an error, just ran out of volumes*/
153 return (true);
154
155 if (oserror (errcode)) // 1/29/97 dmb: call oserror
156 goto error;
157
158 fsvol.parID = fsRtParID;
159
160 if (!newfilledhandle (&fsvol, sizeof (fsvol), &hstring))
161 goto error;
162
163 if (!oppushhandle (hlist, nil, (Handle) hstring))
164 goto error;
165
166 } /*while*/
167
168 error:
169
170 opdisposelist (hlist);
171
172 disposehandle (*hdiskloop);
173
174 *hdiskloop = nil;
175
176 return (false);
177 } /*diskinitloop*/
178
179
180 boolean fileinitloop (const tyfilespec *fs, tyfileloopcallback filefilter, Handle *hfileloop) {
181
182 /*
183 a conglomeration of filemanager incantations which sets up a UserLand
184 fileloop construct. we create a new handle (allows fileloops to be
185 nested inside other file loops, not statically allocated) and fill it
186 with information that each iteration of a fileloop will need. took
187 a minimum of two days fiddling (3/16-17/90) to get this to work -- DW.
188
189 12/6/91 dmb: generate dirNFErr when fileparsevolname fails
190
191 8/15/92 dmb: added, but commented out, filefilter support
192
193 2.1b2 dmb: updated to use filespecs
194
195 3.0.2 dmb: make sure fs is a folder, not a file
196 */
197
198 tyfilelooprecord info;
199 CInfoPBRec pb;
200 long dirid;
201 register hdlfilelooprecord h;
202 short ix;
203 hdllistrecord hlist;
204
205 clearbytes (&pb, sizeof (CInfoPBRec)); /*init all fields to zero*/
206
207 setoserrorparam ((ptrstring) (*fs).name);
208
209 pb.hFileInfo.ioVRefNum = (*fs).vRefNum;
210
211 pb.hFileInfo.ioDirID = (*fs).parID;
212
213 pb.hFileInfo.ioNamePtr = (StringPtr) (*fs).name;
214
215 if (oserror (PBGetCatInfoSync (&pb)))
216 return (false);
217
218 if (!foldertest (&pb)) { /*3.0.2*/
219
220 oserror (dirNFErr);
221
222 return (false);
223 }
224
225 dirid = pb.dirInfo.ioDrDirID; /*must remember this for loop body*/
226
227 clearbytes (&info, sizeof (info));
228
229 info.vnum = pb.hFileInfo.ioVRefNum;
230
231 info.dirid = pb.hFileInfo.ioDirID;
232
233 info.ixdirectory = 1; /*start with the first file*/
234
235 if (!newfilledhandle (&info, sizeof (info), hfileloop))
236 return (false);
237
238 h = (hdlfilelooprecord) *hfileloop; /*copy into register*/
239
240 hlist = nil;
241
242 if (!opnewlist (&hlist, false))
243 goto error;
244
245 (**h).hfilelist = hlist;
246
247 opsetreleaseitemcallback (hlist, &fileloopreleaseitem);
248
249 ix = 1; /*start with file index 1*/
250
251 while (true) {
252
253 bigstring bsfile;
254 Handle hstring;
255 OSErr errcode;
256
257 pb.dirInfo.ioDrDirID = dirid; /*may be smashed by ioFlNum on previous loop*/
258
259 pb.dirInfo.ioFDirIndex = ix++;
260
261 pb.dirInfo.ioNamePtr = bsfile;
262
263 errcode = PBGetCatInfoSync (&pb);
264
265 if (errcode == fnfErr) /*not an error, just ran out of files*/
266 return (true);
267
268 #if TARGET_API_MAC_CARBON == 1
269
270 if (errcode == dirNFErr) /*On OS X, this is what's returned for a read permission error. Weird.*/
271 return (true);
272
273 if (errcode == afpAccessDenied) /* 2005-01-05 creedon - don't bail when user does not have the correct permissions < http://sourceforge.net/tracker/index.php?func=detail&aid=1096641&group_id=120666&atid=687798 > */
274 return (true);
275
276 #endif
277
278 if (oserror (errcode)) /*errcode != noErr*/
279 goto error;
280
281 /*if it's a folder, insert a colon at the end of the file name*/
282
283 if (foldertest (&pb))
284 if (!pushchar (':', bsfile))
285 goto error;
286
287 /*
288 if (filefilter != nil) {
289
290 if (!(*filefilter) (bspath, bsfile))
291 continue;
292 }
293 */
294
295 if (!newtexthandle (bsfile, &hstring))
296 goto error;
297
298 if (!oppushhandle (hlist, nil, (Handle) hstring))
299 goto error;
300 } /*while*/
301
302 error:
303
304 opdisposelist (hlist);
305
306 disposehandle (*hfileloop);
307
308 *hfileloop = nil;
309
310 return (false);
311 } /*fileinitloop*/
312
313
314 void fileendloop (Handle hfileloop) {
315
316 register hdlfilelooprecord h = (hdlfilelooprecord) hfileloop;
317
318 opdisposelist ((**h).hfilelist);
319
320 disposehandle ((Handle) h);
321 } /*fileendloop*/
322
323
324 boolean filenextloop (Handle hfileloop, tyfilespec *fsfile, boolean *flfolder) {
325
326 /*
327 8/17/92 dmb: we're using text handles now instead of string handles.
328
329 2.1b2 dmb: now we're using filespecs!
330
331 2.1b11 dmb: for volumes, whole fsspec is now stashed in handle
332
333 3.0.2b1 dmb: must set flfolder to true for disks
334
335 3.0.4b1 dmb: return true of fnfErr; script will have to handle error anyway
336
337 5.0.2b21 dmb: don't call FSMakeFSSpec for each file; just the first.
338 */
339
340 register hdlfilelooprecord h = (hdlfilelooprecord) hfileloop;
341 Handle hdata;
342 bigstring bs;
343 short vnum;
344 long dirid;
345 OSErr err;
346
347 if (!opgetlisthandle ((**h).hfilelist, (**h).ixdirectory++, nil, &hdata))
348 return (false);
349
350 vnum = (**h).vnum;
351
352 if (vnum == 0) { /*item is a volume, hdata contains refnum*/
353
354 /*
355 vnum = **(short **) hdata;
356
357 setemptystring (bs);
358 */
359
360 *fsfile = **(FSSpec **) hdata;
361
362 *flfolder = true; /*3.0.2b1*/
363
364 return (true);
365 }
366 else {
367
368 dirid = (**h).dirid;
369
370 texthandletostring (hdata, bs);
371
372 *flfolder = bs [*bs] == ':';
373
374 if (*flfolder)
375 --*bs;
376
377 if ((**h).ixdirectory == 2) { //first time
378
379 err = FSMakeFSSpec (vnum, dirid, bs, fsfile);
380
381 (**h).vnum = (*fsfile).vRefNum;
382
383 (**h).dirid = (*fsfile).parID;
384
385 if ((err == noErr) || (err == fnfErr)) /* 3.0.4b1 dmb */
386 return (true);
387
388 return (!oserror (err)); /* false */
389 }
390 else {
391
392 (*fsfile).vRefNum = vnum;
393
394 (*fsfile).parID = dirid;
395
396 copystring (bs, (*fsfile).name);
397
398 return (true);
399 }
400 }
401 } /*filenextloop*/
402
403
404 boolean diskloop (tyfileloopcallback diskcallback, long refcon) {
405
406 /*
407 dmb 9/21/93: filegetvolumeinfo takes a vRefNum, not a string.
408 */
409
410 HVolumeParam pb;
411 short ix;
412
413 clearbytes (&pb, sizeof (pb)); /*init all fields to zero*/
414
415 ix = 1; /*start with file index 1*/
416
417 while (true) {
418
419 bigstring bsvolume;
420 tyfileinfo info;
421 OSErr errcode;
422
423 pb.ioVolIndex = ix++;
424
425 pb.ioNamePtr = bsvolume;
426
427 errcode = PBHGetVInfoSync ((HParmBlkPtr) &pb);
428
429 if (errcode == nsvErr) /*not an error, just ran out of volumes*/
430 return (true);
431
432 if (oserror (errcode))
433 return (false);
434
435 filegetvolumeinfo (pb.ioVRefNum, &info);
436
437 if (!(*diskcallback) (bsvolume, &info, refcon))
438 return (false);
439 } /*while*/
440 } /*diskloop*/
441
442
443 boolean folderloop (const tyfilespec *pfs, boolean flreverse, tyfileloopcallback filecallback, long refcon) {
444
445 /*
446 loop through all of the files in the folder at fs, and call filecallback
447 for each one.
448
449 if flreverse is true, loop through files backwards to allow for deletions
450
451 DW 8/28/93: inexplicably, getmacfileinfo is determining that ctfiles is 1
452 greater than the actual number of files in our folder (it's the History
453 folder in clayhistorymenu.c). the way the loop was structured, we visit
454 no files in the folder in this case. changed it so that on fnfErr we
455 continue the loop. the next time thru it will find a file. hope this
456 doesn't break anything else (it shouldn't).
457 */
458
459 FSSpec fs = *pfs; /*work with a copy*/
460 CInfoPBRec pb;
461 long dirid;
462 bigstring bsfile;
463 short ix;
464 long ctfiles;
465 tyfileinfo info;
466 OSErr ec;
467
468 setoserrorparam ((ptrstring) fs.name);
469
470 if (!getmacfileinfo (&fs, &pb))
471 return (false);
472
473 assert (BitTst (&pb.dirInfo.ioFlAttrib, 3)); /*be sure it's a folder*/
474
475 dirid = pb.dirInfo.ioDrDirID; /*must remember this for loop body*/
476
477 ctfiles = pb.dirInfo.ioDrNmFls;
478
479 if (flreverse)
480 ix = ctfiles;
481 else
482 ix = 1; /*start with file index 1*/
483
484 while (--ctfiles >= 0) {
485
486 pb.dirInfo.ioDrDirID = dirid; /*may be smashed by ioFlNum on previous loop*/
487
488 pb.dirInfo.ioFDirIndex = ix;
489
490 if (flreverse)
491 --ix;
492 else
493 ++ix;
494
495 pb.dirInfo.ioNamePtr = bsfile;
496
497 ec = PBGetCatInfoSync (&pb);
498
499 if (ec == fnfErr) /*DW 8/28/93: continue instead of returning true*/
500 continue;
501
502 if (oserror (ec))
503 return (false);
504
505 filegetinfofrompb (&pb, &info);
506
507 if (!(*filecallback) (bsfile, &info, refcon))
508 return (false);
509 } /*while*/
510
511 return (true);
512 } /*folderloop*/
513 #endif
514
515
516
517
518 #ifdef WIN95VERSION
519 // start windows version......
520 typedef struct tyfindloopinfo
521 {
522 tyfilespec fs;
523 HANDLE findhandle;
524 tyfileloopcallback ffilter;
525 boolean doingDrives;
526 short drivenum;
527 } findloopinfo;
528
529 static boolean initfileloopspec (tyfilespec *fs)
530 {
531 HANDLE findHandle;
532 WIN32_FIND_DATA fileinfo;
533 char fn[300];
534 char * filename;
535 short isFolder;
536
537 copystring (fsname (fs), fn);
538 filename = fsname (fs);
539
540 if (fileisvolume (fs)) {
541 cleanendoffilename (fsname (fs));
542 appendcstring (filename, "\\*");
543 return (true);
544 }
545
546 cleanendoffilename (fn);
547 nullterminate (fn);
548
549 findHandle = FindFirstFile (stringbaseaddress(fn), &fileinfo);
550
551 if (findHandle == INVALID_HANDLE_VALUE)
552 {
553 oserror (GetLastError());
554 return (false); //no match
555 }
556
557 isFolder = (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)?true:false;
558
559 if (FindNextFile (findHandle, &fileinfo))
560 {
561 FindClose (findHandle);
562 return (true); //wild card must be present to find second
563 }
564
565 FindClose (findHandle);
566 if (isFolder) {
567 cleanendoffilename (filename);
568
569 appendcstring (filename, "\\*");
570
571 nullterminate (filename);
572 }
573
574 return (true);
575 }
576
577 boolean fileinitloop (const tyfilespec *pfs, tyfileloopcallback filefilter, Handle *hfileloop) {
578
579 findloopinfo ** fi;
580
581 *hfileloop = NULL;
582 fi = (findloopinfo **) NewHandle (sizeof(findloopinfo));
583
584 if (fi == NULL)
585 return (false);
586
587 (**fi).fs = *pfs;
588 (**fi).findhandle = NULL;
589 (**fi).ffilter = filefilter;
590 (**fi).doingDrives = false;
591 (**fi).drivenum = 0; /*start with A*/
592
593 if (isemptystring ((**fi).fs.fullSpecifier)) { /* do disks */
594 (**fi).doingDrives = true;
595 }
596 else {
597 initfileloopspec (&((**fi).fs));
598 }
599
600 *hfileloop = (Handle)fi;
601 return (true);
602 }
603
604 void fileendloop (Handle hfileloop) {
605
606 findloopinfo ** fi;
607 fi = (findloopinfo **) hfileloop;
608
609 if (fi != NULL)
610 {
611 if ((**fi).findhandle != NULL)
612 FindClose ((**fi).findhandle);
613
614 disposehandle ((Handle) fi);
615 }
616 } /*fileendloop*/
617
618
619 boolean filenextloop (Handle hfileloop, tyfilespec *fsfile, boolean *flfolder) {
620 findloopinfo ** fi;
621 HANDLE findHandle;
622 WIN32_FIND_DATA fileinfo;
623 char fn[300];
624 char pathname[300];
625 char * endofpath;
626 int errCode;
627 short drivenum;
628 DWORD drivemap, drivemask;
629
630 if (hfileloop == NULL)
631 return (false);
632
633 if (fsfile == NULL)
634 return (false);
635
636 fi = (findloopinfo **) hfileloop;
637
638 if ((**fi).doingDrives) { /*We are looping over each volume - not files*/
639 while (true) {
640 drivenum = (**fi).drivenum;
641
642 ++((**fi).drivenum);
643
644 if (drivenum >= 26)
645 return (false);
646
647 drivemap = GetLogicalDrives();
648
649 drivemask = 1 << drivenum;
650
651 if ((drivemap & drivemask) == drivemask) { /* we found one */
652 /*convert drivenum to filespec */
653 wsprintf (stringbaseaddress(fsname(fsfile)), "%c:\\", drivenum + 'A');
654 setstringlength (fsname(fsfile), strlen(stringbaseaddress(fsname(fsfile))));
655 *flfolder = true;
656 return (true);
657 }
658 }
659 }
660
661 if ((**fi).findhandle == NULL) /*we are looking for the first one...*/
662 {
663 copystring (fsname (&(**fi).fs), fn);
664
665 cleanendoffilename (fn);
666
667 nullterminate (fn);
668
669 findHandle = FindFirstFile (stringbaseaddress(fn), &fileinfo);
670
671 if (findHandle == INVALID_HANDLE_VALUE)
672 {
673 oserror (GetLastError());
674 return (false);
675 }
676
677 GetFullPathName (stringbaseaddress(fn), 300, stringbaseaddress(pathname), &endofpath);
678
679 *endofpath = 0; /*terminates path name*/
680
681 setstringlength(pathname, strlen(stringbaseaddress(pathname)));
682
683 copystring (pathname, fsname (&(**fi).fs));
684 buildfilename (fsname (&(**fi).fs), 0, fileinfo.cFileName, 1, fsname (fsfile));
685
686 if (flfolder != NULL)
687 *flfolder = (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)?true:false;
688
689 (**fi).findhandle = findHandle;
690
691 if (strcmp (fileinfo.cFileName, ".") == 0)
692 goto SkippingDotandDotDot;
693
694 if (strcmp (fileinfo.cFileName, "..") == 0)
695 goto SkippingDotandDotDot;
696
697 if (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
698 cleanendoffilename (fsname(fsfile));
699 appendcstring (fsname(fsfile), "\\");
700 }
701
702 return (true);
703 }
704 else
705 {
706 SkippingDotandDotDot:
707 if (FindNextFile ((**fi).findhandle, &fileinfo))
708 {
709 buildfilename (fsname (&(**fi).fs), 0, fileinfo.cFileName, 1, fsname (fsfile));
710
711 if (flfolder != NULL)
712 *flfolder = (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)?true:false;
713
714 if (strcmp (fileinfo.cFileName, ".") == 0)
715 goto SkippingDotandDotDot;
716
717 if (strcmp (fileinfo.cFileName, "..") == 0)
718 goto SkippingDotandDotDot;
719
720 if (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
721 cleanendoffilename (fsname(fsfile));
722 appendcstring (fsname(fsfile), "\\");
723 }
724
725 return (true);
726 }
727
728 errCode = GetLastError();
729
730 // FindClose((**fi).findhandle);
731
732 if (errCode != ERROR_NO_MORE_FILES)
733 oserror(errCode);
734 }
735
736 return (false);
737 }
738
739
740 boolean folderloop (const tyfilespec *pfs, boolean flreverse, tyfileloopcallback filecallback, long refcon) {
741 HANDLE findHandle;
742 WIN32_FIND_DATA fileinfo;
743 char fn[300];
744 char pathname[300];
745 char * endofpath;
746 bigstring bsfile;
747 tyfileinfo info;
748 int errCode;
749
750
751 copystring (fsname (pfs), fn);
752
753 cleanendoffilename (fn);
754
755 nullterminate (fn);
756
757 findHandle = FindFirstFile (stringbaseaddress(fn), &fileinfo);
758
759 if (findHandle == INVALID_HANDLE_VALUE)
760 {
761 oserror (GetLastError());
762 return (false);
763 }
764
765 winsetfileinfo (&fileinfo, &info);
766
767 GetFullPathName (stringbaseaddress(fn), 300, stringbaseaddress(pathname), &endofpath);
768
769 *endofpath = 0; /*terminates path name*/
770
771 setstringlength(pathname, strlen(stringbaseaddress(pathname)));
772
773 buildfilename (pathname, 0, fileinfo.cFileName, 1, bsfile);
774
775 if (!(*filecallback) (bsfile, &info, refcon))
776 {
777 FindClose(findHandle);
778 return (false);
779 }
780
781 while (FindNextFile (findHandle, &fileinfo))
782 {
783 winsetfileinfo (&fileinfo, &info);
784
785 buildfilename (pathname, 0, fileinfo.cFileName, 1, bsfile);
786
787 if (!(*filecallback) (bsfile, &info, refcon))
788 {
789 FindClose(findHandle);
790 return (false);
791 }
792 }
793
794 errCode = GetLastError();
795
796 FindClose(findHandle);
797
798 if (errCode == ERROR_NO_MORE_FILES)
799 return (true);
800
801 oserror(errCode);
802 return (false);
803 }
804
805 #endif
806
807
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.