[asperl] added AS patch#6
[p5sagit/p5-mst-13.2.git] / win32 / ipdir.c
CommitLineData
76e3520e 1/*
2
3 ipdir.c
4 Interface for perl directory functions
5
6*/
7
8#include <ipdir.h>
9
10class CPerlDir : public IPerlDir
11{
12public:
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; };
25protected:
26 CPerlObj *pPerl;
27};
28
29int CPerlDir::MKdir(const char *dirname, int mode, int &err)
30{
31 return mkdir(dirname); /* just ignore mode */
32}
33
34int CPerlDir::Chdir(const char *dirname, int &err)
35{
36 return chdir(dirname);
37}
38
39int 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.
48DIR *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
135int 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.
144struct 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
171void CPerlDir::Rewind(DIR *dirp, int &err)
172{
173 dirp->curr = dirp->start;
174}
175
176void CPerlDir::Seek(DIR *dirp, long loc, int &err)
177{
178 dirp->curr = (char *)loc;
179}
180
181long CPerlDir::Tell(DIR *dirp, int &err)
182{
183 return (long) dirp->curr;
184}
185
186