update dev300-m58
[ooovba.git] / dmake / msdos / dirlib.c
blob9097e5163c6dd07436c2520a968b7248e7a98b6a
1 /*
2 DIRLIB for MS-DOS
3 -----------------
5 Enclosed is an implementation of the `dirlib' package for MS-DOS.
6 The implementation is targeted for MS-C, although any reasonably
7 competent C compiler should manage. The package consists of:
9 dir.h the header file
10 dir.c the functions
11 testdir.c a q&d test program
13 The package tries to view directory naming in a Un*x light; in particular,
14 directories such as '/.' and '/..' (as well as `.' and `..' if your
15 current directory is root) are understood. Indefinite paths like
16 `/../.././../..' will correctly refer to the root (of the particular disk).
17 Names such as `a:////./../' are okay too.
19 I've tried to be as sensible about DTA's as possible, since you never
20 know who will be using one; they are set before use, and reset afterwards.
22 There is some cruft in the package, namely the way `seekdir' and
23 `telldir' are done. The code was derived from a little experimentation,
24 and may not work after a certain point (although I believe the 2.x version
25 to be solid). Caveat utilitor.
27 Documentation for the package is available in the public domain; the
28 package's functionality was derived from this documentation.
30 Bug reports and comments are welcome. Enjoy!
32 - Matt
34 -------
35 UUCP: {ucbvax,ihnp4,randvax,trwrb!trwspp,ism780}!ucla-cs!matt
36 ARPA: matt@LOCUS.UCLA.EDU
37 Ph: (213) 825-2756
39 --------
40 Modified for use in dmake by Dennis Vadura. Mostly just clean up and an
41 effort to make correctly typed objects are passed to functions in find.c.
42 Also deleted all dos version 2.0 specific code. It is not required any
43 more.
47 * revision history:
49 * VER MM/DD/YY COMMENTS
50 * ---- -------- --------
51 * 0.99 02/24/86 Beta release to INTERNET
54 #include <stdlib.h>
55 #include <ctype.h>
56 #include <errno.h>
57 #include <string.h>
58 #include <dos.h>
60 #include "dirent.h"
62 extern int find_err;
65 static char *
66 getdcwd(drive)
67 int drive;
69 union REGS r;
70 struct SREGS s;
71 static char xcwd[64];
72 char far *cwd = xcwd;
74 r.h.ah = 0x47;
75 r.h.dl = drive;
76 r.x.si = FP_OFF(cwd);
77 s.ds = FP_SEG(cwd);
78 intdosx(&r, &r, &s);
79 find_err = r.x.ax;
80 if (r.x.cflag)
81 return (char *) 0;
82 return xcwd;
88 * opendir
91 #define SUFFIX "\\*.*"
92 #define SLASH "\\"
93 #define streq(a,b) (strcmp(a,b)==0)
95 DIR *
96 opendir(name)
97 char *name;
99 register DIR *nd;
100 char *cwd;
101 char drive[3];
102 int atroot = 0;
103 int rooted = 0;
106 * hack off drive designator if present
109 if (name[1] == ':') {
110 cwd = getdcwd(toupper(name[0]) - 'A' + 1);
111 drive[0] = name[0]; drive[1] = ':'; drive[2] = '\0';
112 name += 2;
114 else {
115 cwd = getdcwd(0);
116 drive[0] = '\0';
119 /* is the name 'rooted'? */
120 if ((*name == '/') || (*name == '\\')) ++rooted;
122 /* see if we are at the root directory for this device */
123 if (!*cwd) ++atroot;
126 * MSDOS '/' doesn't have a '.' or '..'
127 * also, double '/' sequences don't make sense.
128 * many ported programs expect them to work, so we fix it up...
131 /* chop off leading . and .. if at root */
132 if (atroot && (*name == '.')) {
133 switch (*++name) {
134 case '\0':
135 case '/':
136 case '\\':
137 break;
139 case '.':
140 switch (*++name) {
141 case '\0':
142 case '/':
143 case '\\':
144 break;
145 default:
146 --name;
147 --name;
149 break;
151 default:
152 --name;
156 /* chop off leading /'s, /.'s and /..'s to make naming sensible */
157 while (*name && ((*name == '/') || (*name == '\\'))) {
158 if (*++name == '.') {
159 switch (*++name) {
160 case '\0':
161 case '/':
162 case '\\':
163 break;
165 case '.':
166 switch (*++name) {
167 case '\0':
168 case '/':
169 case '\\':
170 break;
172 default:
173 --name;
174 --name;
176 break;
178 default:
179 --name;
186 * name should now look like: path/path/path
187 * we must now construct name based on whether or not it
188 * was 'rooted' (started with a /)
191 if (rooted) cwd = "";
193 /* construct DIR */
194 if (!(nd = (DIR *)malloc(
195 sizeof(DIR)+strlen(drive)+strlen(cwd)+strlen(SLASH)+
196 strlen(name)+strlen(SUFFIX))))
197 return (DIR *) 0;
199 /* create long name */
200 strcpy(nd->dd_name, drive);
201 if (*cwd) {
202 strcat(nd->dd_name, SLASH);
203 strcat(nd->dd_name, cwd);
205 if (*name) {
206 strcat(nd->dd_name, SLASH);
207 strcat(nd->dd_name, name);
209 strcat(nd->dd_name, SUFFIX);
211 /* search */
212 if (!findfirst(&nd->dd_name[0], &nd->dd_dta)) {
213 free((char *)nd);
214 errno = ENOENT;
215 return (DIR *) 0;
217 nd->dd_stat = 0;
218 return nd;
222 struct dirent *
223 readdir(dirp)
224 DIR *dirp;
226 static struct dirent dir;
228 if (dirp->dd_stat)
229 return (struct dirent *) 0;
231 /* format structure */
232 dir.d_ino = 0; /* not valid for DOS */
233 dir.d_reclen = 0;
234 strcpy(dir.d_name, dirp->dd_dta.name);
235 dir.d_namlen = strlen(dir.d_name);
236 strlwr(dir.d_name); /* DOSism */
238 /* read ahead */
239 if (findnext(&dirp->dd_dta) != NULL)
240 dirp->dd_stat = 0;
241 else
242 dirp->dd_stat = find_err;
244 return &dir;
248 void
249 closedir(dirp)
250 DIR *dirp;
252 free((char *)dirp);
256 void
257 seekdir(dirp, pos)
258 DIR *dirp;
259 long pos;
262 * check against DOS limits
265 if ((pos < 0) || (pos > 4095)) {
266 dirp->dd_stat = 1;
267 return;
270 *(short *)&dirp->dd_dta.fcb[13] = pos + 1;
272 /* read ahead */
273 if (findnext(&dirp->dd_dta))
274 dirp->dd_stat = 0;
275 else
276 dirp->dd_stat = find_err;
280 long
281 telldir(dirp)
282 DIR *dirp;
284 return (long) (*(short *)&dirp->dd_dta.fcb[13] - 2);