xref: /openbsd-src/gnu/usr.bin/cvs/vms/ndir.c (revision 43c1707e6f6829177cb1974ee6615ce6c1307689)
150bf276cStholo /*
250bf276cStholo  * Copyright � 1994 the Free Software Foundation, Inc.
350bf276cStholo  *
450bf276cStholo  * Author: Richard Levitte (levitte@e.kth.se)
550bf276cStholo  *
650bf276cStholo  * This file is a part of GNU VMSLIB, the GNU library for porting GNU
750bf276cStholo  * software to VMS.
850bf276cStholo  *
950bf276cStholo  * GNU VMSLIB is free software; you can redistribute it and/or modify
1050bf276cStholo  * it under the terms of the GNU General Public License as published by
1150bf276cStholo  * the Free Software Foundation; either version 2 of the License, or
1250bf276cStholo  * (at your option) any later version.
1350bf276cStholo  *
1450bf276cStholo  * GNU VMSLIB is distributed in the hope that it will be useful,
1550bf276cStholo  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1650bf276cStholo  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1750bf276cStholo  * GNU General Public License for more details.
1850bf276cStholo  */
1950bf276cStholo 
20*43c1707eStholo #ifndef __VMS_VER
21*43c1707eStholo #define __VMS_VER 0
22*43c1707eStholo #endif
23*43c1707eStholo #ifndef __DECC_VER
24*43c1707eStholo #define __DECC_VER 0
25*43c1707eStholo #endif
26*43c1707eStholo 
2750bf276cStholo #include <varargs.h>
2850bf276cStholo #include <rms.h>
2950bf276cStholo #include <descrip.h>
3050bf276cStholo #include <string.h>
3150bf276cStholo #include <errno.h>
3250bf276cStholo 
3350bf276cStholo #ifdef __GNUC__
3450bf276cStholo #include <sys/stat.h>
3550bf276cStholo #else
3650bf276cStholo #include <stat.h>
3750bf276cStholo #endif
3850bf276cStholo #include <lib$routines.h>
3950bf276cStholo 
4050bf276cStholo #include "ndir.h"
4150bf276cStholo #include "filutils.h"
4250bf276cStholo 
4350bf276cStholo /* The following was snarfed from lib-src/alloca.c in GNU Emacs,
4450bf276cStholo    the hacked.  */
4550bf276cStholo 
4650bf276cStholo #if __STDC__
4750bf276cStholo typedef void procedure;
4850bf276cStholo typedef void *pointer;
4950bf276cStholo #else
5050bf276cStholo typedef int procedure;
5150bf276cStholo typedef char *pointer;
5250bf276cStholo #endif
5350bf276cStholo 
5450bf276cStholo /* Different portions of Emacs need to call different versions of
5550bf276cStholo    malloc.  The Emacs executable needs alloca to call xmalloc, because
5650bf276cStholo    ordinary malloc isn't protected from input signals.  On the other
5750bf276cStholo    hand, the utilities in lib-src need alloca to call malloc; some of
5850bf276cStholo    them are very simple, and don't have an xmalloc routine.
5950bf276cStholo 
6050bf276cStholo    Non-Emacs programs expect this to call use xmalloc.
6150bf276cStholo 
6250bf276cStholo    Callers below should use malloc.
6350bf276cStholo 
6450bf276cStholo    There is some need for BLOCK_INPUT and UNBLOCK_INPUT, but it is really
6550bf276cStholo    only used in Emacs, so that's the only time it's used.  Otherwise,
6650bf276cStholo    they are just empty statements.  */
6750bf276cStholo 
6850bf276cStholo #ifndef emacs
6950bf276cStholo #include "misc.h"
7050bf276cStholo #define malloc xmalloc
7150bf276cStholo #define free xfree
7250bf276cStholo #endif
7350bf276cStholo 
7450bf276cStholo #if 0
7550bf276cStholo extern pointer malloc ();
7650bf276cStholo extern procedure free ();
7750bf276cStholo #endif
7850bf276cStholo 
7950bf276cStholo /* end of snarf.  */
8050bf276cStholo 
8150bf276cStholo #ifndef BLOCK_INPUT
8250bf276cStholo #define BLOCK_INPUT
8350bf276cStholo #endif
8450bf276cStholo #ifndef UNBLOCK_INPUT
8550bf276cStholo #define UNBLOCK_INPUT
8650bf276cStholo #endif
8750bf276cStholo 
8850bf276cStholo static struct direct *vms_low_readdir ();
8950bf276cStholo 
9050bf276cStholo typedef struct
9150bf276cStholo {
9250bf276cStholo   DIR s_dir;
9350bf276cStholo   unsigned long context;
9450bf276cStholo   unsigned long uflags;
9550bf276cStholo   struct dsc$descriptor_s dir_spec;
9650bf276cStholo   struct dsc$descriptor_s file_spec;
9750bf276cStholo   int version_flag;
9850bf276cStholo   unsigned long status;
9950bf276cStholo } VMS_DIR;
10050bf276cStholo 
10150bf276cStholo DIR *
vms_opendir(infilename,filepattern)102*43c1707eStholo vms_opendir (infilename, filepattern)
10350bf276cStholo      char *infilename;	/* name of directory */
10450bf276cStholo      char *filepattern;
10550bf276cStholo {
10650bf276cStholo   register VMS_DIR *dirp;	/* -> malloc'ed storage */
10750bf276cStholo   register unsigned int length = 1024;
10850bf276cStholo   register int fd;		/* file descriptor for read */
10950bf276cStholo   char *filename;
11050bf276cStholo   struct stat sbuf;		/* result of fstat */
11150bf276cStholo 
11250bf276cStholo   filename = (char *) malloc(length+1);
11350bf276cStholo   strcpy(filename, infilename);
11450bf276cStholo 
115461cc63eStholo   strip_trailing_slashes (filename);
11650bf276cStholo   if(strcmp(filename, ".") == 0)
11750bf276cStholo      {
11850bf276cStholo      getcwd(filename, length+1, 1); /* Get a VMS filespec */
11950bf276cStholo      length = strlen(filename);
12050bf276cStholo      }
12150bf276cStholo 
12250bf276cStholo   BLOCK_INPUT;
12350bf276cStholo   if ((filename[length-1] != ']'
12450bf276cStholo        && filename[length-1] != '>'
12550bf276cStholo        && filename[length-1] != ':'
12650bf276cStholo        && (stat (filename, &sbuf) < 0
12750bf276cStholo 	   || (sbuf.st_mode & S_IFMT) != S_IFDIR)))
12850bf276cStholo     {
12950bf276cStholo       errno = ENOTDIR;
13050bf276cStholo       UNBLOCK_INPUT;
13150bf276cStholo       free(filename);
13250bf276cStholo       return 0;		/* bad luck today */
13350bf276cStholo     }
13450bf276cStholo 
13550bf276cStholo   if ((dirp = (VMS_DIR *) xmalloc (sizeof (VMS_DIR))) == 0)
13650bf276cStholo     {
13750bf276cStholo       errno = ENOMEM;
13850bf276cStholo       UNBLOCK_INPUT;
13950bf276cStholo       free(filename);
14050bf276cStholo       return 0;		/* bad luck today */
14150bf276cStholo     }
14250bf276cStholo 
14350bf276cStholo   {
14450bf276cStholo     int count;
14550bf276cStholo     va_count(count);
14650bf276cStholo     if (count == 2)
14750bf276cStholo       {
14850bf276cStholo 	dirp->file_spec.dsc$a_pointer =
14950bf276cStholo 	  (char *) xmalloc (strlen (filepattern) + 1);
15050bf276cStholo 	strcpy (dirp->file_spec.dsc$a_pointer, filepattern);
15150bf276cStholo       }
15250bf276cStholo     else
15350bf276cStholo       {
15450bf276cStholo 	dirp->file_spec.dsc$a_pointer =
15550bf276cStholo 	  (char *) xmalloc (4);
15650bf276cStholo 	strcpy (dirp->file_spec.dsc$a_pointer, "*.*");
15750bf276cStholo       }
15850bf276cStholo     dirp->file_spec.dsc$w_length = strlen (dirp->file_spec.dsc$a_pointer);
15950bf276cStholo     dirp->file_spec.dsc$b_dtype = DSC$K_DTYPE_T;
16050bf276cStholo     dirp->file_spec.dsc$b_class = DSC$K_CLASS_S;
16150bf276cStholo     dirp->version_flag = strchr (dirp->file_spec.dsc$a_pointer, ';') != 0;
16250bf276cStholo   }
16350bf276cStholo   dirp->dir_spec.dsc$a_pointer = (char *) xmalloc (strlen (filename) + 10);
16450bf276cStholo   UNBLOCK_INPUT;
16550bf276cStholo   file_name_as_directory (dirp->dir_spec.dsc$a_pointer, filename);
16650bf276cStholo   dirp->dir_spec.dsc$w_length = strlen (dirp->dir_spec.dsc$a_pointer);
16750bf276cStholo   dirp->dir_spec.dsc$b_dtype = DSC$K_DTYPE_T;
16850bf276cStholo   dirp->dir_spec.dsc$b_class = DSC$K_CLASS_S;
16950bf276cStholo   dirp->context = 0;
17050bf276cStholo   dirp->uflags = 2;
17150bf276cStholo   dirp->s_dir.dd_fd = 0;
17250bf276cStholo   dirp->s_dir.dd_loc = dirp->s_dir.dd_size = 0;	/* refill needed */
17350bf276cStholo 
17450bf276cStholo   free(filename);
17550bf276cStholo 
17650bf276cStholo   /* In the cases where the filename ended with `]', `>' or `:',
17750bf276cStholo      we never checked if it really was a directory, so let's do that
17850bf276cStholo      now, by trying to read the first entry.  */
17950bf276cStholo   if (vms_low_readdir ((DIR *) dirp) == (struct direct *) -1)
18050bf276cStholo     {
181*43c1707eStholo       vms_closedir (dirp);		/* was: xfree (dirp);  */
18250bf276cStholo       errno = ENOENT;
18350bf276cStholo       return 0;
18450bf276cStholo     }
18550bf276cStholo   dirp->s_dir.dd_loc = 0;	/* Make sure the entry just read is
18650bf276cStholo 				   reused at the next call to readdir.  */
18750bf276cStholo 
18850bf276cStholo   return (DIR *) dirp;		/* I had to cast, for VMS sake.  */
18950bf276cStholo }
19050bf276cStholo 
1912286d8edStholo int
vms_closedir(dirp)192*43c1707eStholo vms_closedir (dirp)
193*43c1707eStholo      register DIR *dirp;		/* stream from vms_opendir */
19450bf276cStholo {
19550bf276cStholo   {
19650bf276cStholo     VMS_DIR *vms_dirp = (VMS_DIR *) dirp;
19750bf276cStholo 
19850bf276cStholo     if (vms_dirp->context != 0)
19950bf276cStholo       lib$find_file_end (&(vms_dirp->context));
20050bf276cStholo     xfree (vms_dirp->dir_spec.dsc$a_pointer);
20150bf276cStholo     xfree (vms_dirp->file_spec.dsc$a_pointer);
20250bf276cStholo   }
20350bf276cStholo 
20450bf276cStholo   xfree ((char *) dirp);
2052286d8edStholo   return 0;
20650bf276cStholo }
20750bf276cStholo 
20850bf276cStholo struct direct dir_static;	/* simulated directory contents */
20950bf276cStholo 
21050bf276cStholo static struct direct *
vms_low_readdir(dirp)21150bf276cStholo vms_low_readdir (dirp)
21250bf276cStholo      register DIR *dirp;
21350bf276cStholo {
21450bf276cStholo   static char rbuf[257];
21550bf276cStholo   static struct dsc$descriptor_s rdsc =
21650bf276cStholo     { sizeof (rbuf), DSC$K_DTYPE_T, DSC$K_CLASS_S, rbuf };
21750bf276cStholo   VMS_DIR * vms_dirp = (VMS_DIR *) dirp;
21850bf276cStholo 
21950bf276cStholo   if (dirp->dd_size == 0)
22050bf276cStholo     {
22150bf276cStholo       char *cp, *cp2;
22250bf276cStholo       unsigned long status;
22350bf276cStholo 
22450bf276cStholo       status = lib$find_file (&vms_dirp->file_spec, &rdsc, &vms_dirp->context,
22550bf276cStholo 			      &vms_dirp->dir_spec, 0, 0, &vms_dirp->uflags);
22650bf276cStholo       vms_dirp->status = status;
22750bf276cStholo       if (status == RMS$_NMF || status == RMS$_FNF)
22850bf276cStholo 	return 0;
22950bf276cStholo       if (status != RMS$_NORMAL)
23050bf276cStholo 	return (struct direct *) -1;
23150bf276cStholo 
23250bf276cStholo       rbuf [256] = '\0';
23350bf276cStholo       if (cp = strchr (rbuf, ' '))
23450bf276cStholo 	*cp = '\0';
23550bf276cStholo       if ((cp = strchr (rbuf, ';')) != 0
23650bf276cStholo 	  && !vms_dirp->version_flag)
23750bf276cStholo 	*cp = '\0';
23850bf276cStholo 
23950bf276cStholo       for (cp2 = rbuf - 1; cp2 != 0;)
24050bf276cStholo 	{
24150bf276cStholo 	  char *cp2tmp = 0;
24250bf276cStholo 	  cp = cp2 + 1;
24350bf276cStholo 	  cp2 = strchr (cp, ']');
24450bf276cStholo 	  if (cp2 != 0)
24550bf276cStholo 	    cp2tmp = strchr (cp2 + 1, '>');
24650bf276cStholo 	  if (cp2tmp != 0)
24750bf276cStholo 	    cp2 = cp2tmp;
24850bf276cStholo 	}
24950bf276cStholo 
25050bf276cStholo       /* Propagate names as lower case only,
25150bf276cStholo          directories have ".dir" truncated,
25250bf276cStholo          do not propagate null extensions "makefile." */
25350bf276cStholo       {
25450bf276cStholo       char *p, *q;
25550bf276cStholo 
25650bf276cStholo       if(strcmp(cp, "CVS.DIR") == 0)
25750bf276cStholo         strcpy(dirp->dd_buf, "CVS");
25850bf276cStholo       else
25950bf276cStholo         {
26050bf276cStholo         for(p = cp, q = dirp->dd_buf; *p;)
26150bf276cStholo            {
26250bf276cStholo            if(strcmp(p, ".DIR") == 0)
26350bf276cStholo               break;
26450bf276cStholo            else
26550bf276cStholo              *q++ = tolower(*p++);
26650bf276cStholo            }
26750bf276cStholo         *q = '\0';
26850bf276cStholo         if(*(q-1) == '.')
26950bf276cStholo           *(q-1) = '\0';
27050bf276cStholo         }
27150bf276cStholo      }
27250bf276cStholo #if 0
27350bf276cStholo       strcpy (dirp->dd_buf, cp);
27450bf276cStholo #endif
27550bf276cStholo 
27650bf276cStholo       dirp->dd_size = strlen (dirp->dd_buf);
27750bf276cStholo       dirp->dd_loc = 0;
27850bf276cStholo     }
27950bf276cStholo 
28050bf276cStholo   if (vms_dirp->status != RMS$_NORMAL)
28150bf276cStholo     return 0;
28250bf276cStholo 
28350bf276cStholo   dir_static.d_ino = -1;	/* Couldn't care less...  */
28450bf276cStholo   dir_static.d_namlen = strlen (dirp->dd_buf);
28550bf276cStholo   dir_static.d_reclen = sizeof (struct direct)
28650bf276cStholo     - MAXNAMLEN + 3
28750bf276cStholo       + dir_static.d_namlen - dir_static.d_namlen % 4;
28850bf276cStholo   strcpy (dir_static.d_name, dirp->dd_buf);
28950bf276cStholo   dir_static.d_name[dir_static.d_namlen] = '\0';
29050bf276cStholo   dirp->dd_loc = dirp->dd_size; /* only one record at a time */
29150bf276cStholo 
29250bf276cStholo   return &dir_static;
29350bf276cStholo }
29450bf276cStholo 
29550bf276cStholo /* ARGUSED */
29650bf276cStholo struct direct *
vms_readdir(dirp)297*43c1707eStholo vms_readdir (dirp)
298*43c1707eStholo      register DIR *dirp;	/* stream from vms_opendir */
29950bf276cStholo {
30050bf276cStholo   register struct direct *dp;
30150bf276cStholo 
30250bf276cStholo   for (; ;)
30350bf276cStholo     {
30450bf276cStholo       if (dirp->dd_loc >= dirp->dd_size)
30550bf276cStholo 	dirp->dd_loc = dirp->dd_size = 0;
30650bf276cStholo 
30750bf276cStholo       dp = vms_low_readdir (dirp);
30850bf276cStholo       if (dp == 0 || dp == (struct direct *) -1)
30950bf276cStholo 	return 0;
31050bf276cStholo       return dp;
31150bf276cStholo     }
31250bf276cStholo }
313