perl 3.0 patch #30 patch #29, continued
[perl.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
9  */
10
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/dir.h>
14
15 #include <stdio.h>
16 #include <malloc.h>
17 #include <string.h>
18
19 #define INCL_NOPM
20 #include <os2.h>
21
22
23 int attributes = A_DIR | A_HIDDEN;
24
25
26 static char *getdirent(char *);
27 static void free_dircontents(struct _dircontents *);
28
29 static HDIR hdir;
30 static USHORT count;
31 static FILEFINDBUF find;
32
33
34 DIR *opendir(char *name)
35 {
36   struct stat statb;
37   DIR *dirp;
38   char c;
39   char *s;
40   struct _dircontents *dp;
41   char nbuf[MAXPATHLEN + 1];
42
43   strcpy(nbuf, name);
44
45   if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') &&
46        (strlen(nbuf) > 1) )
47   {
48     nbuf[strlen(nbuf) - 1] = 0;
49
50     if ( nbuf[strlen(nbuf) - 1] == ':' )
51       strcat(nbuf, "\\.");
52   }
53   else
54     if ( nbuf[strlen(nbuf) - 1] == ':' )
55       strcat(nbuf, ".");
56
57   if (stat(nbuf, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
58     return NULL;
59
60   if ( (dirp = malloc(sizeof(DIR))) == NULL )
61     return NULL;
62
63   if ( nbuf[strlen(nbuf) - 1] == '.' )
64     strcpy(nbuf + strlen(nbuf) - 1, "*.*");
65   else
66     if ( ((c = nbuf[strlen(nbuf) - 1]) == '\\' || c == '/') &&
67          (strlen(nbuf) == 1) )
68       strcat(nbuf, "*.*");
69     else
70       strcat(nbuf, "\\*.*");
71
72   dirp -> dd_loc = 0;
73   dirp -> dd_contents = dirp -> dd_cp = NULL;
74
75   if ((s = getdirent(nbuf)) == NULL)
76     return dirp;
77
78   do
79   {
80     if (((dp = malloc(sizeof(struct _dircontents))) == NULL) ||
81         ((dp -> _d_entry = malloc(strlen(s) + 1)) == NULL)      )
82     {
83       if (dp)
84         free(dp);
85       free_dircontents(dirp -> dd_contents);
86
87       return NULL;
88     }
89
90     if (dirp -> dd_contents)
91       dirp -> dd_cp = dirp -> dd_cp -> _d_next = dp;
92     else
93       dirp -> dd_contents = dirp -> dd_cp = dp;
94
95     strcpy(dp -> _d_entry, s);
96     dp -> _d_next = NULL;
97
98     dp -> _d_size = find.cbFile;
99     dp -> _d_mode = find.attrFile;
100     dp -> _d_time = *(unsigned *) &(find.ftimeLastWrite);
101     dp -> _d_date = *(unsigned *) &(find.fdateLastWrite);
102   }
103   while ((s = getdirent(NULL)) != NULL);
104
105   dirp -> dd_cp = dirp -> dd_contents;
106
107   return dirp;
108 }
109
110
111 void closedir(DIR * dirp)
112 {
113   free_dircontents(dirp -> dd_contents);
114   free(dirp);
115 }
116
117
118 struct direct *readdir(DIR * dirp)
119 {
120   static struct direct dp;
121
122   if (dirp -> dd_cp == NULL)
123     return NULL;
124
125   dp.d_namlen = dp.d_reclen =
126     strlen(strcpy(dp.d_name, dirp -> dd_cp -> _d_entry));
127
128   strlwr(dp.d_name);                   /* JF */
129   dp.d_ino = 0;
130
131   dp.d_size = dirp -> dd_cp -> _d_size;
132   dp.d_mode = dirp -> dd_cp -> _d_mode;
133   dp.d_time = dirp -> dd_cp -> _d_time;
134   dp.d_date = dirp -> dd_cp -> _d_date;
135
136   dirp -> dd_cp = dirp -> dd_cp -> _d_next;
137   dirp -> dd_loc++;
138
139   return &dp;
140 }
141
142
143 void seekdir(DIR * dirp, long off)
144 {
145   long i = off;
146   struct _dircontents *dp;
147
148   if (off >= 0)
149   {
150     for (dp = dirp -> dd_contents; --i >= 0 && dp; dp = dp -> _d_next);
151
152     dirp -> dd_loc = off - (i + 1);
153     dirp -> dd_cp = dp;
154   }
155 }
156
157
158 long telldir(DIR * dirp)
159 {
160   return dirp -> dd_loc;
161 }
162
163
164 static void free_dircontents(struct _dircontents * dp)
165 {
166   struct _dircontents *odp;
167
168   while (dp)
169   {
170     if (dp -> _d_entry)
171       free(dp -> _d_entry);
172
173     dp = (odp = dp) -> _d_next;
174     free(odp);
175   }
176 }
177
178
179 static char *getdirent(char *dir)
180 {
181   int done;
182
183   if (dir != NULL)
184   {                                    /* get first entry */
185     hdir = HDIR_CREATE;
186     count = 1;
187     done = DosFindFirst(dir, &hdir, attributes,
188                         &find, sizeof(find), &count, 0L);
189   }
190   else                                 /* get next entry */
191     done = DosFindNext(hdir, &find, sizeof(find), &count);
192
193   if (done == 0)
194     return find.achName;
195   else
196   {
197     DosFindClose(hdir);
198     return NULL;
199   }
200 }