[asperl] integrate latest win32 branch
[p5sagit/p5-mst-13.2.git] / win32 / ipdir.c
1 /*
2
3         ipdir.c
4         Interface for perl directory functions
5
6 */
7
8 #include <ipdir.h>
9
10 class CPerlDir : public IPerlDir
11 {
12 public:
13         CPerlDir() { pPerl = NULL; };
14         virtual int MKdir(const char *dirname, int mode, int &err);
15         virtual int Chdir(const char *dirname, int &err);
16         virtual int Rmdir(const char *dirname, int &err);
17         virtual int Close(DIR *dirp, int &err);
18         virtual DIR *Open(char *filename, int &err);
19         virtual struct direct *Read(DIR *dirp, int &err);
20         virtual void Rewind(DIR *dirp, int &err);
21         virtual void Seek(DIR *dirp, long loc, int &err);
22         virtual long Tell(DIR *dirp, int &err);
23
24         inline void SetPerlObj(CPerlObj *p) { pPerl = p; };
25 protected:
26         CPerlObj *pPerl;
27 };
28
29 int CPerlDir::MKdir(const char *dirname, int mode, int &err)
30 {
31     return mkdir(dirname); /* just ignore mode */
32 }
33
34 int CPerlDir::Chdir(const char *dirname, int &err)
35 {
36     return chdir(dirname);
37 }
38
39 int CPerlDir::Rmdir(const char *dirname, int &err)
40 {
41     return rmdir(dirname);
42 }
43
44 #define PATHLEN 1024
45 // The idea here is to read all the directory names into a string table
46 // (separated by nulls) and when one of the other dir functions is called
47 // return the pointer to the current file name. 
48 DIR *CPerlDir::Open(char *filename, int &err)
49 {
50         DIR            *p;
51         long            len;
52         long            idx;
53         char            scannamespc[PATHLEN];
54         char       *scanname = scannamespc;
55         struct stat     sbuf;
56         WIN32_FIND_DATA FindData;
57         HANDLE          fh;
58
59         // Create the search pattern
60         strcpy(scanname, filename);
61
62         len = strlen(scanname);
63         if(len > 1 && ((scanname[len-1] == '/') || (scanname[len-1] == '\\')))
64         {
65                 // allow directory names of 'x:\' to pass
66                 if(!(len == 3 && scanname[1] == ':'))
67                         scanname[len-1] = '\0';
68         }
69
70         // check to see if filename is a directory
71         if(stat(scanname, &sbuf) < 0 || sbuf.st_mode & _S_IFDIR == 0)
72         {
73                 DWORD dTemp = GetFileAttributes(scanname);
74                 if(dTemp == 0xffffffff || !(dTemp & FILE_ATTRIBUTE_DIRECTORY))
75                 {
76                         return NULL;
77                 }
78         }
79
80         if((scanname[len-1] == '/') || (scanname[len-1] == '\\'))
81                 scanname[len-1] = '\0';
82
83         strcat(scanname, "/*");
84
85         // Get a DIR structure
86         Newz(1501, p, 1, DIR);
87         if(p == NULL)
88                 return NULL;
89
90         // do the FindFirstFile call
91         fh = FindFirstFile(scanname, &FindData);
92         if(fh == INVALID_HANDLE_VALUE) 
93         {
94             Safefree(p);
95                 return NULL;
96         }
97
98         // now allocate the first part of the string table for the filenames that we find.
99         idx = strlen(FindData.cFileName)+1;
100         New(1502, p->start, idx, char);
101         if(p->start == NULL) 
102         {
103                 FindClose(fh);
104                 croak("opendir: malloc failed!\n");
105         }
106         strcpy(p->start, FindData.cFileName);
107         p->nfiles++;
108
109         // loop finding all the files that match the wildcard
110         // (which should be all of them in this directory!).
111         // the variable idx should point one past the null terminator
112         // of the previous string found.
113         //
114         while(FindNextFile(fh, &FindData)) 
115         {
116                 len = strlen(FindData.cFileName);
117                 // bump the string table size by enough for the
118                 // new name and it's null terminator 
119                 Renew(p->start, idx+len+1, char);
120                 if(p->start == NULL) 
121                 {
122                         FindClose(fh);
123                 croak("opendir: malloc failed!\n");
124                 }
125                 strcpy(&p->start[idx], FindData.cFileName);
126                 p->nfiles++;
127                 idx += len+1;
128         }
129         FindClose(fh);
130         p->size = idx;
131         p->curr = p->start;
132         return p;
133 }
134
135 int CPerlDir::Close(DIR *dirp, int &err)
136 {
137         Safefree(dirp->start);
138         Safefree(dirp);
139         return 1;
140 }
141
142 // Readdir just returns the current string pointer and bumps the
143 // string pointer to the next entry.
144 struct direct *CPerlDir::Read(DIR *dirp, int &err)
145 {
146         int         len;
147         static int  dummy = 0;
148
149         if(dirp->curr) 
150         {       // first set up the structure to return
151                 len = strlen(dirp->curr);
152                 strcpy(dirp->dirstr.d_name, dirp->curr);
153                 dirp->dirstr.d_namlen = len;
154
155                 // Fake an inode
156                 dirp->dirstr.d_ino = dummy++;
157
158                 // Now set up for the next call to readdir
159                 dirp->curr += len + 1;
160                 if(dirp->curr >= (dirp->start + dirp->size)) 
161                 {
162                 dirp->curr = NULL;
163                 }
164
165                 return &(dirp->dirstr);
166         } 
167         else
168                 return NULL;
169 }
170
171 void CPerlDir::Rewind(DIR *dirp, int &err)
172 {
173     dirp->curr = dirp->start;
174 }
175
176 void CPerlDir::Seek(DIR *dirp, long loc, int &err)
177 {
178     dirp->curr = (char *)loc;
179 }
180
181 long CPerlDir::Tell(DIR *dirp, int &err)
182 {
183     return (long) dirp->curr;
184 }
185
186