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