perl 4.0.00: (no release announcement available)
[p5sagit/p5-mst-13.2.git] / os2 / director.c
1 /*
2  * @(#)dir.c 1.4 87/11/06 Public Domain.
3  *
4  *  A public domain implementation of BSD directory routines for
5  *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
6  *  August 1897
7  *  Ported to OS/2 by Kai Uwe Rommel
8  *  December 1989, February 1990
9  *  Change for HPFS support, October 1990
10  */
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/dir.h>
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <malloc.h>
19 #include <string.h>
20 #include <ctype.h>
21
22 #define INCL_NOPM
23 #include <os2.h>
24
25
26 #ifndef PERLGLOB
27 int attributes = A_DIR | A_HIDDEN;
28
29
30 static char *getdirent(char *);
31 static void free_dircontents(struct _dircontents *);
32
33 static HDIR hdir;
34 static USHORT count;
35 static FILEFINDBUF find;
36 static BOOL lower;
37
38
39 DIR *opendir(char *name)
40 {
41   struct stat statb;
42   DIR *dirp;
43   char c;
44   char *s;
45   struct _dircontents *dp;
46   char nbuf[MAXPATHLEN + 1];
47
48   strcpy(nbuf, name);
49
50   if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') &&
51        (strlen(nbuf) > 1) )
52   {
53     nbuf[strlen(nbuf) - 1] = 0;
54
55     if ( nbuf[strlen(nbuf) - 1] == ':' )
56       strcat(nbuf, "\\.");
57   }
58   else
59     if ( nbuf[strlen(nbuf) - 1] == ':' )
60       strcat(nbuf, ".");
61
62   if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
63     return NULL;
64
65   if ( (dirp = malloc(sizeof(DIR))) == NULL )
66     return NULL;
67
68   if ( nbuf[strlen(nbuf) - 1] == '.' )
69     strcpy(nbuf + strlen(nbuf) - 1, "*.*");
70   else
71     if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') &&
72          (strlen(nbuf) == 1) )
73       strcat(nbuf, "*.*");
74     else
75       strcat(nbuf, "\\*.*");
76
77   dirp -> dd_loc = 0;
78   dirp -> dd_contents = dirp -> dd_cp = NULL;
79
80   if ((s = getdirent(nbuf)) == NULL)
81     return dirp;
82
83   do
84   {
85     if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
86         ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL)      )
87     {
88       if (dp)
89         free(dp);
90       free_dircontents(dirp -> dd_contents);
91
92       return NULL;
93     }
94
95     if (dirp -> dd_contents)
96       dirp -> dd_cp = dirp -> dd_cp -> _d_next = dp;
97     else
98       dirp -> dd_contents = dirp -> dd_cp = dp;
99
100     strcpy(dp -> _d_entry, s);
101     dp -> _d_next = NULL;
102
103     dp -> _d_size = find.cbFile;
104     dp -> _d_mode = find.attrFile;
105     dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
106     dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
107   }
108   while ((s = getdirent(NULL)) != NULL);
109
110   dirp -> dd_cp = dirp -> dd_contents;
111
112   return dirp;
113 }
114
115
116 void closedir(DIR * dirp)
117 {
118   free_dircontents(dirp -> dd_contents);
119   free(dirp);
120 }
121
122
123 struct direct *readdir(DIR * dirp)
124 {
125   static struct direct dp;
126
127   if (dirp -> dd_cp == NULL)
128     return NULL;
129
130   dp.d_namlen = dp.d_reclen =
131     strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
132
133   dp.d_ino = 0;
134
135   dp.d_size = dirp -> dd_cp -> _d_size;
136   dp.d_mode = dirp -> dd_cp -> _d_mode;
137   dp.d_time = dirp -> dd_cp -> _d_time;
138   dp.d_date = dirp -> dd_cp -> _d_date;
139
140   dirp -> dd_cp = dirp -> dd_cp -> _d_next;
141   dirp -> dd_loc++;
142
143   return &dp;
144 }
145
146
147 void seekdir(DIR * dirp, long off)
148 {
149   long i = off;
150   struct _dircontents *dp;
151
152   if (off >= 0)
153   {
154     for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
155
156     dirp -> dd_loc = off - (i + 1);
157     dirp -> dd_cp = dp;
158   }
159 }
160
161
162 long telldir(DIR * dirp)
163 {
164   return dirp -> dd_loc;
165 }
166
167
168 static void free_dircontents(struct _dircontents * dp)
169 {
170   struct _dircontents *odp;
171
172   while (dp)
173   {
174     if (dp -> _d_entry)
175       free(dp -> _d_entry);
176
177     dp = (odp = dp) -> _d_next;
178     free(odp);
179   }
180 }
181
182
183 static
184 #endif
185 int IsFileSystemFAT(char *dir)
186 {
187   USHORT nDrive;
188   ULONG lMap;
189   BYTE bData[64], bName[3];
190   USHORT cbData;
191
192   if ( _osmode == DOS_MODE )
193     return TRUE;
194   else
195   {
196     /* We separate FAT and HPFS file systems here.
197      * Filenames read from a FAT system are converted to lower case
198      * while the case of filenames read from a HPFS (and other future
199      * file systems, like Unix-compatibles) is preserved.
200      */
201
202     if ( isalpha(dir[0]) && (dir[1] == ':') )
203       nDrive = toupper(dir[0]) - '@';
204     else
205       DosQCurDisk(&nDrive, &lMap);
206
207     bName[0] = (char) (nDrive + '@');
208     bName[1] = ':';
209     bName[2] = 0;
210
211     cbData = sizeof(bData);
212
213     if ( !DosQFSAttach(bName, 0U, 1U, bData, &cbData, 0L) )
214       return !strcmp(bData + (*(USHORT *) (bData + 2) + 7), "FAT");
215     else
216       return FALSE;
217
218     /* End of this ugly code */
219   }
220 }
221
222 #ifndef PERLGLOB
223 static char *getdirent(char *dir)
224 {
225   int done;
226
227   if (dir != NULL)
228   {                                    /* get first entry */
229     lower = IsFileSystemFAT(dir);
230
231     hdir = HDIR_CREATE;
232     count = 1;
233     done = DosFindFirst(dir, &hdir, attributes,
234                         &find, sizeof(find), &count, 0L);
235   }
236   else                                 /* get next entry */
237     done = DosFindNext(hdir, &find, sizeof(find), &count);
238
239   if ( lower )
240     strlwr(find.achName);
241
242   if (done == 0)
243     return find.achName;
244   else
245   {
246     DosFindClose(hdir);
247     return NULL;
248   }
249 }
250 #endif