whyever the aclocal call was commented out…
[alioth/cvs.git] / vms / ndir.c
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 *
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
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 *
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 *
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 }