1 /*
2 * Copyright � 1994 the Free Software Foundation, Inc.
3 *
4 * Author: Richard Levitte (levitte@e.kth.se)
5 *
6 * This file is a part of GNU VMSLIB, the GNU library for porting GNU
7 * software to VMS.
8 *
9 * GNU VMSLIB is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * GNU VMSLIB is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
19
20 #ifndef __VMS_VER
21 #define __VMS_VER 0
22 #endif
23 #ifndef __DECC_VER
24 #define __DECC_VER 0
25 #endif
26
27 #include <varargs.h>
28 #include <rms.h>
29 #include <descrip.h>
30 #include <string.h>
31 #include <errno.h>
32
33 #ifdef __GNUC__
34 #include <sys/stat.h>
35 #else
36 #include <stat.h>
37 #endif
38 #include <lib$routines.h>
39
40 #include "ndir.h"
41 #include "filutils.h"
42
43 /* The following was snarfed from lib-src/alloca.c in GNU Emacs,
44 the hacked. */
45
46 #if __STDC__
47 typedef void procedure;
48 typedef void *pointer;
49 #else
50 typedef int procedure;
51 typedef char *pointer;
52 #endif
53
54 /* Different portions of Emacs need to call different versions of
55 malloc. The Emacs executable needs alloca to call xmalloc, because
56 ordinary malloc isn't protected from input signals. On the other
57 hand, the utilities in lib-src need alloca to call malloc; some of
58 them are very simple, and don't have an xmalloc routine.
59
60 Non-Emacs programs expect this to call use xmalloc.
61
62 Callers below should use malloc.
63
64 There is some need for BLOCK_INPUT and UNBLOCK_INPUT, but it is really
65 only used in Emacs, so that's the only time it's used. Otherwise,
66 they are just empty statements. */
67
68 #ifndef emacs
69 #include "misc.h"
70 #define malloc xmalloc
71 #define free xfree
72 #endif
73
74 #if 0
75 extern pointer malloc ();
76 extern procedure free ();
77 #endif
78
79 /* end of snarf. */
80
81 #ifndef BLOCK_INPUT
82 #define BLOCK_INPUT
83 #endif
84 #ifndef UNBLOCK_INPUT
85 #define UNBLOCK_INPUT
86 #endif
87
88 static struct direct *vms_low_readdir ();
89
90 typedef struct
91 {
92 DIR s_dir;
93 unsigned long context;
94 unsigned long uflags;
95 struct dsc$descriptor_s dir_spec;
96 struct dsc$descriptor_s file_spec;
97 int version_flag;
98 unsigned long status;
99 } VMS_DIR;
100
101 DIR *
vms_opendir(infilename,filepattern)102 vms_opendir (infilename, filepattern)
103 char *infilename; /* name of directory */
104 char *filepattern;
105 {
106 register VMS_DIR *dirp; /* -> malloc'ed storage */
107 register unsigned int length = 1024;
108 register int fd; /* file descriptor for read */
109 char *filename;
110 struct stat sbuf; /* result of fstat */
111
112 filename = (char *) malloc(length+1);
113 strcpy(filename, infilename);
114
115 strip_trailing_slashes (filename);
116 if(strcmp(filename, ".") == 0)
117 {
118 getcwd(filename, length+1, 1); /* Get a VMS filespec */
119 length = strlen(filename);
120 }
121
122 BLOCK_INPUT;
123 if ((filename[length-1] != ']'
124 && filename[length-1] != '>'
125 && filename[length-1] != ':'
126 && (stat (filename, &sbuf) < 0
127 || (sbuf.st_mode & S_IFMT) != S_IFDIR)))
128 {
129 errno = ENOTDIR;
130 UNBLOCK_INPUT;
131 free(filename);
132 return 0; /* bad luck today */
133 }
134
135 if ((dirp = (VMS_DIR *) xmalloc (sizeof (VMS_DIR))) == 0)
136 {
137 errno = ENOMEM;
138 UNBLOCK_INPUT;
139 free(filename);
140 return 0; /* bad luck today */
141 }
142
143 {
144 int count;
145 va_count(count);
146 if (count == 2)
147 {
148 dirp->file_spec.dsc$a_pointer =
149 (char *) xmalloc (strlen (filepattern) + 1);
150 strcpy (dirp->file_spec.dsc$a_pointer, filepattern);
151 }
152 else
153 {
154 dirp->file_spec.dsc$a_pointer =
155 (char *) xmalloc (4);
156 strcpy (dirp->file_spec.dsc$a_pointer, "*.*");
157 }
158 dirp->file_spec.dsc$w_length = strlen (dirp->file_spec.dsc$a_pointer);
159 dirp->file_spec.dsc$b_dtype = DSC$K_DTYPE_T;
160 dirp->file_spec.dsc$b_class = DSC$K_CLASS_S;
161 dirp->version_flag = strchr (dirp->file_spec.dsc$a_pointer, ';') != 0;
162 }
163 dirp->dir_spec.dsc$a_pointer = (char *) xmalloc (strlen (filename) + 10);
164 UNBLOCK_INPUT;
165 file_name_as_directory (dirp->dir_spec.dsc$a_pointer, filename);
166 dirp->dir_spec.dsc$w_length = strlen (dirp->dir_spec.dsc$a_pointer);
167 dirp->dir_spec.dsc$b_dtype = DSC$K_DTYPE_T;
168 dirp->dir_spec.dsc$b_class = DSC$K_CLASS_S;
169 dirp->context = 0;
170 dirp->uflags = 2;
171 dirp->s_dir.dd_fd = 0;
172 dirp->s_dir.dd_loc = dirp->s_dir.dd_size = 0; /* refill needed */
173
174 free(filename);
175
176 /* In the cases where the filename ended with `]', `>' or `:',
177 we never checked if it really was a directory, so let's do that
178 now, by trying to read the first entry. */
179 if (vms_low_readdir ((DIR *) dirp) == (struct direct *) -1)
180 {
181 vms_closedir (dirp); /* was: xfree (dirp); */
182 errno = ENOENT;
183 return 0;
184 }
185 dirp->s_dir.dd_loc = 0; /* Make sure the entry just read is
186 reused at the next call to readdir. */
187
188 return (DIR *) dirp; /* I had to cast, for VMS sake. */
189 }
190
191 int
vms_closedir(dirp)192 vms_closedir (dirp)
193 register DIR *dirp; /* stream from vms_opendir */
194 {
195 {
196 VMS_DIR *vms_dirp = (VMS_DIR *) dirp;
197
198 if (vms_dirp->context != 0)
199 lib$find_file_end (&(vms_dirp->context));
200 xfree (vms_dirp->dir_spec.dsc$a_pointer);
201 xfree (vms_dirp->file_spec.dsc$a_pointer);
202 }
203
204 xfree ((char *) dirp);
205 return 0;
206 }
207
208 struct direct dir_static; /* simulated directory contents */
209
210 static struct direct *
vms_low_readdir(dirp)211 vms_low_readdir (dirp)
212 register DIR *dirp;
213 {
214 static char rbuf[257];
215 static struct dsc$descriptor_s rdsc =
216 { sizeof (rbuf), DSC$K_DTYPE_T, DSC$K_CLASS_S, rbuf };
217 VMS_DIR * vms_dirp = (VMS_DIR *) dirp;
218
219 if (dirp->dd_size == 0)
220 {
221 char *cp, *cp2;
222 unsigned long status;
223
224 status = lib$find_file (&vms_dirp->file_spec, &rdsc, &vms_dirp->context,
225 &vms_dirp->dir_spec, 0, 0, &vms_dirp->uflags);
226 vms_dirp->status = status;
227 if (status == RMS$_NMF || status == RMS$_FNF)
228 return 0;
229 if (status != RMS$_NORMAL)
230 return (struct direct *) -1;
231
232 rbuf [256] = '\0';
233 if (cp = strchr (rbuf, ' '))
234 *cp = '\0';
235 if ((cp = strchr (rbuf, ';')) != 0
236 && !vms_dirp->version_flag)
237 *cp = '\0';
238
239 for (cp2 = rbuf - 1; cp2 != 0;)
240 {
241 char *cp2tmp = 0;
242 cp = cp2 + 1;
243 cp2 = strchr (cp, ']');
244 if (cp2 != 0)
245 cp2tmp = strchr (cp2 + 1, '>');
246 if (cp2tmp != 0)
247 cp2 = cp2tmp;
248 }
249
250 /* Propagate names as lower case only,
251 directories have ".dir" truncated,
252 do not propagate null extensions "makefile." */
253 {
254 char *p, *q;
255
256 if(strcmp(cp, "CVS.DIR") == 0)
257 strcpy(dirp->dd_buf, "CVS");
258 else
259 {
260 for(p = cp, q = dirp->dd_buf; *p;)
261 {
262 if(strcmp(p, ".DIR") == 0)
263 break;
264 else
265 *q++ = tolower(*p++);
266 }
267 *q = '\0';
268 if(*(q-1) == '.')
269 *(q-1) = '\0';
270 }
271 }
272 #if 0
273 strcpy (dirp->dd_buf, cp);
274 #endif
275
276 dirp->dd_size = strlen (dirp->dd_buf);
277 dirp->dd_loc = 0;
278 }
279
280 if (vms_dirp->status != RMS$_NORMAL)
281 return 0;
282
283 dir_static.d_ino = -1; /* Couldn't care less... */
284 dir_static.d_namlen = strlen (dirp->dd_buf);
285 dir_static.d_reclen = sizeof (struct direct)
286 - MAXNAMLEN + 3
287 + dir_static.d_namlen - dir_static.d_namlen % 4;
288 strcpy (dir_static.d_name, dirp->dd_buf);
289 dir_static.d_name[dir_static.d_namlen] = '\0';
290 dirp->dd_loc = dirp->dd_size; /* only one record at a time */
291
292 return &dir_static;
293 }
294
295 /* ARGUSED */
296 struct direct *
vms_readdir(dirp)297 vms_readdir (dirp)
298 register DIR *dirp; /* stream from vms_opendir */
299 {
300 register struct direct *dp;
301
302 for (; ;)
303 {
304 if (dirp->dd_loc >= dirp->dd_size)
305 dirp->dd_loc = dirp->dd_size = 0;
306
307 dp = vms_low_readdir (dirp);
308 if (dp == 0 || dp == (struct direct *) -1)
309 return 0;
310 return dp;
311 }
312 }
313