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 } 313