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