xref: /openbsd/gnu/usr.bin/cvs/vms/ndir.c (revision 43c1707e)
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