xref: /openbsd-src/gnu/usr.bin/cvs/vms/filutils.c (revision 461cc63e7458ce60db55037c1a7656349538b52f)
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 <string.h>
21 #include <file.h>
22 #include <rmsdef.h>
23 #include <fab.h>
24 #include <nam.h>
25 #include <stdlib.h>
26 #include <lib$routines.h>
27 #include <descrip.h>
28 #include "filutils.h"
29 
30 /* file_name_as_directory was snarfed from src/fileio.c in GNU Emacs.  */
31 
32 char *
file_name_as_directory(out,in)33 file_name_as_directory (out, in)
34      char *out, *in;
35 {
36   int size = strlen (in) - 1;
37   int ext_point = 0;
38 
39   strcpy (out, in);
40 
41   /* Is it already a directory string? */
42   if (in[size] == ':' || in[size] == ']' || in[size] == '>')
43     return out;
44   /* Is it a VMS directory file name?  If so, hack VMS syntax.  */
45   else
46     if (! strchr (in, '/'))
47       {
48 	ext_point = 1;
49 	if (size > 3 && (! strcmp (&in[size - 3], ".DIR")
50 			 || ! strcmp (&in[size - 3], ".dir")))
51 	  ext_point = -3;
52 	else
53 	  if (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
54 			   || ! strncmp (&in[size - 5], ".dir", 4))
55 	      && (in[size - 1] == '.' || in[size - 1] == ';')
56 	      && in[size] == '1')
57 	    ext_point = -5;
58       }
59   if (ext_point != 0)
60     {
61       register char *p, *dot;
62       char brack;
63 
64       /* dir:[000000]x.dir --> dir:x.dir --> dir:[x]
65 	 dir:[000000.x]y.dir --> dir:[x]y.dir --> dir:[x.y]
66 	 but dir:[000000.000000]x.dir --> dir:[000000.000000.x]
67 	     dir:[000000.000000.x]y.dir --> dir:[000000.000000.x.y] */
68       static char tem[256];
69 
70       p = dot = strchr(in,':');
71       if (p != 0 && (p[1] == '[' || p[1] == '<'))
72 	{
73 	  p += 2;
74 	  if (strncmp(p,"000000",6) == 0)
75 	    {
76 	      p += 6;
77 	      if (strncmp(p,".000000",7) != 0
78 		  && (*p == ']' || *p == '>' || *p == '.'))
79 		{
80 		  size = dot - in + 1;
81 		  strncpy(tem, in, size);
82 		  if (*p == '.')
83 		    tem[size++] = '[';
84 		  strcpy(tem + size, p + 1);
85 		  in = tem;
86 		  size = strlen(in) - 1;
87 		}
88 	    }
89 	}
90       /* x.dir -> [.x]
91 	 dir:x.dir --> dir:[x]
92 	 dir:[x]y.dir --> dir:[x.y] */
93       p = in + size;
94       while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
95       {
96 	char *emergency_dir = 0;
97 	int emergency_point = 0; /* relative to the end of `out' */
98 
99 	if (p != in)
100 	  {
101 	    strncpy (out, in, p - in);
102 	    out[p - in] = '\0';
103 	    if (*p == ':')
104 	      {
105 		brack = ']';
106 		strcat (out, ":[");
107 		emergency_dir = "000000";
108 		emergency_point = 0;
109 	      }
110 	    else
111 	      {
112 		brack = *p;
113 		strcat (out, ".");
114 		emergency_dir = "";
115 		emergency_point = -1;
116 	      }
117 	    p++;
118 	  }
119 	else
120 	  {
121 	    brack = ']';
122 	    strcpy (out, "[.");
123 	    emergency_dir = "";
124 	    emergency_point = -2;
125 	  }
126 	if (strncmp (p, "000000.", 7) == 0
127 	    && (strncmp (p+7, "000000", 6) != 0
128 		|| (p[13] != ']' && p[13] != '>' && p[13] != '.')))
129 	  p += 7;
130 	if (p < (in + size + ext_point))
131 	  {
132 	    register copy_len = ((in + size + ext_point) - p);
133 	    size = strlen (out) + copy_len;
134 	    strncat (out, p, copy_len);
135 	  }
136 	else
137 	  {
138 	    size = strlen (out) + emergency_point;
139 	    strcpy (out + size, emergency_dir);
140 	    size += strlen (emergency_dir);
141 	  }
142       }
143       out[size++] = brack;
144       out[size] = '\0';
145     }
146   return out;
147 }
148 
149 /*
150  * Convert from directory name to filename.
151  * On VMS:
152  *       xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
153  *       xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
154  * On UNIX, it's simple: just make sure there is a terminating /
155 
156  * Value is nonzero if the string output is different from the input.
157  */
158 
159 /* directory_file_name was snarfed from src/fileio.c in GNU Emacs.  */
160 
161 #include <stdio.h>
directory_file_name(src,dst)162 directory_file_name (src, dst)
163      char *src, *dst;
164 {
165   long slen;
166   long rlen;
167   char * ptr, * rptr;
168   char bracket;
169   struct FAB fab = cc$rms_fab;
170   struct NAM nam = cc$rms_nam;
171   char esa[NAM$C_MAXRSS];
172 
173   slen = strlen (src);
174 
175   if (! strchr (src, '/')
176       && (src[slen - 1] == ']'
177 	  || src[slen - 1] == ':'
178 	  || src[slen - 1] == '>'))
179     {
180       /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
181       fab.fab$l_fna = src;
182       fab.fab$b_fns = slen;
183       fab.fab$l_nam = &nam;
184       fab.fab$l_fop = FAB$M_NAM;
185 
186       nam.nam$l_esa = esa;
187       nam.nam$b_ess = sizeof esa;
188       nam.nam$b_nop |= NAM$M_SYNCHK;
189 
190       /* We call SYS$PARSE to handle such things as [--] for us. */
191       if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
192 	{
193 	  slen = nam.nam$b_esl;
194 	  if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
195 	    slen -= 2;
196 	  esa[slen] = '\0';
197 	  src = esa;
198 	}
199       if (src[slen - 1] != ']' && src[slen - 1] != '>')
200 	{
201 	  /* what about when we have logical_name:???? */
202 	  if (src[slen - 1] == ':')
203 	    {			/* Xlate logical name and see what we get */
204 	      ptr = strcpy (dst, src); /* upper case for getenv */
205 	      while (*ptr)
206 		{
207 		  if ('a' <= *ptr && *ptr <= 'z')
208 		    *ptr -= 040;
209 		  ptr++;
210 		}
211 	      dst[slen - 1] = 0;	/* remove colon */
212 	      if (!(src = getenv (dst)))
213 		return 0;
214 	      /* should we jump to the beginning of this procedure?
215 		 Good points: allows us to use logical names that xlate
216 		 to Unix names,
217 		 Bad points: can be a problem if we just translated to a device
218 		 name...
219 		 For now, I'll punt and always expect VMS names, and hope for
220 		 the best! */
221 	      slen = strlen (src);
222 	      if (src[slen - 1] != ']' && src[slen - 1] != '>')
223 		{ /* no recursion here! */
224 		  strcpy (dst, src);
225 		  return 0;
226 		}
227 	    }
228 	  else
229 	    {		/* not a directory spec */
230 	      strcpy (dst, src);
231 	      return 0;
232 	    }
233 	}
234       bracket = src[slen - 1];
235 
236       /* If bracket is ']' or '>', bracket - 2 is the corresponding
237 	 opening bracket.  */
238       ptr = strchr (src, bracket - 2);
239       if (ptr == 0)
240 	{ /* no opening bracket */
241 	  strcpy (dst, src);
242 	  return 0;
243 	}
244       if (!(rptr = strrchr (src, '.')))
245 	rptr = ptr;
246       slen = rptr - src;
247       strncpy (dst, src, slen);
248       dst[slen] = '\0';
249 #if 0
250       fprintf (stderr, "dst = \"%s\"\nsrc = \"%s\"\nslen = %d\n",
251 	       dst, src, slen);
252 #endif
253       if (*rptr == '.')
254 	{
255 	  dst[slen++] = bracket;
256 	  dst[slen] = '\0';
257 	}
258       else
259 	{
260 	  /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
261 	     then translate the device and recurse. */
262 	  if (dst[slen - 1] == ':'
263 	      && dst[slen - 2] != ':'	/* skip decnet nodes */
264 	      && ((src[slen] == '['
265 		   && strcmp(src + slen + 1, "000000]") == 0)
266 		  || src[slen] == '<'
267 		  && strcmp(src + slen + 1, "000000>") == 0))
268 	    {
269 	      static char equiv_buf[256];
270 	      static struct dsc$descriptor_s equiv
271 		= {sizeof (equiv_buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, equiv_buf};
272 	      static struct dsc$descriptor_s d_name
273 		= {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
274 	      short eqlen;
275 
276 	      dst[slen - 1] = '\0';
277 	      d_name.dsc$w_length = strlen (dst);
278 	      d_name.dsc$a_pointer = dst;
279 	      if (LIB$SYS_TRNLOG (&d_name, &eqlen, &equiv) == 1
280 		  && (equiv_buf[eqlen] = '\0', ptr = equiv_buf) != 0
281 		  && (rlen = strlen (ptr) - 1) > 0
282 		  && (ptr[rlen] == ']' || ptr[rlen] == '>')
283 		  && ptr[rlen - 1] == '.')
284 		{
285 		  char * buf = (char *) malloc (strlen (ptr) + 1);
286 		  int tmp = ptr[rlen];
287 		  if (buf == 0)
288 		    return 0; /* bad luck */
289 		  strcpy (buf, ptr);
290 		  buf[rlen - 1] = tmp;
291 		  buf[rlen] = '\0';
292 		  tmp = directory_file_name (buf, dst);
293 		  free (buf);
294 		  return tmp;
295 		}
296 	      else
297 		dst[slen - 1] = ':';
298 	    }
299 	  strcat (dst, "[000000]");
300 	  slen += 8;
301 	}
302       rptr++;
303       rlen = strlen (rptr) - 1;
304       strncat (dst, rptr, rlen);
305       dst[slen + rlen] = '\0';
306       strcat (dst, ".DIR.1");
307       return 1;
308     }
309 
310   /* Process as Unix format: just remove any final slash.
311      But leave "/" unchanged; do not change it to "".  */
312   strcpy (dst, src);
313   if (slen > 1 && dst[slen - 1] == '/')
314     {
315       dst[slen - 1] = 0;
316       return 1;
317     }
318   return 0;
319 }
320 
321 /* end of snarf.  */
322