refresh
[alioth/cvs.git] / vms / filutils.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 #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 *
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>
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 *) xmalloc (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.  */