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