1 /* vmsify.c -- Module for vms <-> unix file name conversion
2 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007 Free Software Foundation, Inc.
4 This file is part of GNU Make.
6 GNU Make is free software; you can redistribute it and/or modify it under the
7 terms of the GNU General Public License as published by the Free Software
8 Foundation; either version 3 of the License, or (at your option) any later
11 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along with
16 this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* Written by Klaus Kämpf (kkaempf@progis.de)
19 of proGIS Software, Aachen, Germany */
34 #include <lib$routines.h>
35 /* Initialize a string descriptor (struct dsc$descriptor_s) for an
36 arbitrary string. ADDR is a pointer to the first character
37 of the string, and LEN is the length of the string. */
39 #define INIT_DSC_S(dsc, addr, len) do { \
40 (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \
41 (dsc).dsc$b_class = DSC$K_CLASS_S; \
42 (dsc).dsc$w_length = (len); \
43 (dsc).dsc$a_pointer = (addr); \
46 /* Initialize a string descriptor (struct dsc$descriptor_s) for a
47 NUL-terminated string. S is a pointer to the string; the length
48 is determined by calling strlen(). */
50 #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
54 copy 'from' to 'to' up to but not including 'upto'
55 return 0 if eos on from
56 return 1 if upto found
58 return 'to' at last char + 1
59 return 'from' at match + 1 or eos if no match
61 if as_dir == 1, change all '.' to '_'
62 else change all '.' but the last to '_'
66 copyto (char **to
, const char **from
, char upto
, int as_dir
)
70 s
= strrchr (*from
, '.');
80 while (**from
== upto
);
93 #ifdef HAVE_CASE_INSENSITIVE_FS
94 if (isupper ((unsigned char)**from
))
95 **to
= tolower ((unsigned char)**from
);
109 get translation of logical name
114 trnlog (const char *name
)
117 static char reslt
[1024];
118 $
DESCRIPTOR (reslt_dsc
, reslt
);
120 struct dsc$descriptor_s name_dsc
;
123 INIT_DSC_CSTRING (name_dsc
, name
);
125 stat
= lib$
sys_trnlog (&name_dsc
, &resltlen
, &reslt_dsc
);
131 if (stat
== SS$_NOTRAN
)
135 reslt
[resltlen
] = '\0';
137 s
= malloc (resltlen
+1);
151 if (strchr (s
, '\\') == 0)
165 enum namestate
{ N_START
, N_DEVICE
, N_OPEN
, N_DOT
, N_CLOSED
, N_DONE
};
168 convert unix style name to vms style
169 type = 0 -> name is a full name (directory and filename part)
170 type = 1 -> name is a directory
171 type = 2 -> name is a filename without directory
173 The following conversions are applied
175 input full name dir name file name
177 1 ./ <cwd> [] <current directory>.dir
178 2 ../ <home of cwd> <home of cwd> <home of cwd>.dir
180 3 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir
182 5 //a/ a: a: a:000000.dir
184 9 / [000000] [000000] 000000.dir
185 10 /a [000000]a [a] [000000]a
186 11 /a/ [a] [a] [000000]a.dir
187 12 /a/b [a]b [a.b] [a]b
188 13 /a/b/ [a.b] [a.b] [a]b.dir
189 14 /a/b/c [a.b]c [a.b.c] [a.b]c
190 15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir
193 17 a/ [.a] [.a] a.dir
194 18 a/b [.a]b [.a.b] [.a]b
195 19 a/b/ [.a.b] [.a.b] [.a]b.dir
196 20 a/b/c [.a.b]c [.a.b.c] [.a.b]c
197 21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir
199 22 a.b.c a_b.c [.a_b_c] a_b_c.dir
201 23 [x][y]z [x.y]z [x.y]z [x.y]z
202 24 [x][.y]z [x.y]z [x.y]z [x.y]z
204 25 filenames with '$' are left unchanged if they contain no '/'
205 25 filenames with ':' are left unchanged
206 26 filenames with a single pair of '[' ']' are left unchanged
208 The input string is not written to. The result is also const because
209 it's a static buffer; we don't want to change it.
213 vmsify (const char *name
, int type
)
221 #define MAXPATHLEN 512
223 enum namestate nstate
;
224 static char vmsname
[MAXPATHLEN
+1];
238 t
= strpbrk (name
, "$:");
247 s1
= strchr (t
+1, '[');
248 s2
= strchr (t
+1, ']');
253 if (strchr (name
, '/') == 0)
255 strcpy (vmsname
, name
);
256 if ((type
== 1) && (s1
!= 0) && (s2
== 0))
257 strcat (vmsname
, "]");
263 strcpy (vmsname
, name
);
264 if ((type
== 1) && (s1
!= 0) && (s2
== 0))
265 strcat (vmsname
, "]");
271 t
= strchr (name
, '[');
276 const char *s1
= strchr (t
+1, '[');
279 strcpy (vmsname
, name
);
280 if ((type
== 1) && (strchr (t
+1, ']') == 0))
281 strcat (vmsname
, "]");
287 strcpy (vmsname
, name
);
288 return vmsname
; /* not ][, keep unchanged */
295 /* s -> starting char
299 strncpy (vptr
, s
, s1
-s
); /* copy up to but not including ']' */
303 s
= s1
+ 1; /* s -> char behind ']' */
304 if (*s
!= '[') /* was '][' ? */
305 break; /* no, last ] found, exit */
309 s1
= strchr (s
, ']');
310 if (s1
== 0) /* no closing ] */
320 else /* no [ in name */
323 int rooted
= 1; /* flag if logical is rooted, else insert [000000] */
329 case 0: /* start of loop */
335 else if (*fptr
== '.')
344 case 1: /* '/' at start */
354 case 2: /* no '/' at start */
356 const char *s
= strchr (fptr
, '/');
357 if (s
== 0) /* no '/' (16) */
364 copyto (&vptr
, &fptr
, 0, (type
==1));
369 else /* found '/' (17..21) */
372 && (*(s
+1) == 0)) /* 17(2) */
374 copyto (&vptr
, &fptr
, '/', 1);
381 copyto (&vptr
, &fptr
, '/', 1);
389 case 3: /* '//' at start */
394 while (*fptr
== '/') /* collapse all '/' */
396 if (*fptr
== 0) /* just // */
398 char cwdbuf
[MAXPATHLEN
+1];
400 s1
= getcwd(cwdbuf
, MAXPATHLEN
);
404 return vmsname
; /* FIXME, err getcwd */
406 s
= strchr (s1
, ':');
410 return vmsname
; /* FIXME, err no device */
412 strncpy (vptr
, s1
, s
-s1
+1);
420 if (copyto (&vptr
, &fptr
, '/', 1) == 0) /* copy device part */
428 if (*fptr
== 0) /* just '//a/' */
430 strcpy (vptr
+1, "[000000]");
436 /* check logical for [000000] insertion */
439 { /* found translation */
440 for (;;) /* loop over all nested logicals */
442 char *vp2
= vp
+ strlen (vp
) - 1;
443 if (*vp2
== ':') /* translation ends in ':' */
453 continue; /* next iteration */
455 if (*vp2
== ']') /* translation ends in ']' */
457 if (*(vp2
-1) == '.') /* ends in '.]' */
459 if (strncmp (fptr
, "000000", 6) != 0)
464 strcpy (vmsname
, s1
);
465 vp
= strchr (vmsname
, ']');
489 strcpy (vptr
, "[000000.");
496 /* vp-> '.' after 000000 or NULL */
498 s
= strchr (fptr
, '/');
501 if (*(vptr
-1) == '.')
503 else if (rooted
== 0)
505 copyto (&vptr
, &fptr
, 0, (type
== 1));
511 while (*(s
+1) == '/') /* skip multiple '/' */
516 && (*(vptr
-1) != '.'))
522 if ((nstate
== N_DOT
)
535 case 4: /* single '/' at start (9..15) */
542 case 5: /* just '/' at start (9) */
548 strcpy (vptr
, "000000");
556 case 6: /* chars following '/' at start 10..15 */
561 s
= strchr (fptr
, '/');
566 strcpy (vptr
, "000000]");
569 copyto (&vptr
, &fptr
, 0, (type
== 1));
579 && (*(s
+1) == 0)) /* 11(2) */
581 strcpy (vptr
, "000000]");
585 copyto (&vptr
, &fptr
, '/', (*(vptr
-1) != ']'));
591 case 7: /* add '.dir' and exit */
592 if ((nstate
== N_OPEN
)
593 || (nstate
== N_DOT
))
610 strcpy (vptr
, ".dir");
615 case 8: /* add ']' and exit */
620 case 9: /* 17..21, fptr -> 1st '/' + 1 */
633 s
= strchr (fptr
, '/');
638 if (nstate
== N_OPEN
)
647 if (nstate
== N_OPEN
)
657 while (*(s
+1) == '/')
660 && (*(s
+1) == 0)) /* 19(2), 21(2)*/
662 if (nstate
!= N_CLOSED
)
671 if (nstate
== N_OPEN
)
679 if ( (*fptr
== '.') /* check for '..' or '../' */
680 && (*(fptr
+1) == '.')
681 && ((*(fptr
+2) == '/')
682 || (*(fptr
+2) == 0)) )
692 while (*fptr
== '/');
696 vptr
--; /* vptr -> '.' or ']' */
701 if (*vp
== '.') /* one back */
707 if (*vp
== '[') /* top level reached */
711 strcpy (vp
, "[000000]");
728 copyto (&vptr
, &fptr
, '/', as_dir
);
742 if (type
== 2) /* 19,21 */
756 case 10: /* 1,2 first is '.' */
766 case 11: /* 2, '..' at start */
770 if (*fptr
!= '/') /* got ..xxx */
772 strcpy (vmsname
, name
);
778 while (*fptr
== '/') fptr
++;
781 if (*(fptr
+1) != '.')
788 while (*fptr
== '/');
790 { /* got '..' or '../' */
792 char cwdbuf
[MAXPATHLEN
+1];
794 vp
= getcwd(cwdbuf
, MAXPATHLEN
);
798 return vmsname
; /* FIXME, err getcwd */
801 vp
= strchr (vptr
, ']');
811 strcpy (vp
, "000000]");
819 if (*fptr
== 0) /* had '..' or '../' */
824 else /* had '../xxx' */
834 vptr
+= strlen (vptr
);
838 case 12: /* 1, '.' at start */
843 strcpy (vmsname
, name
);
852 char cwdbuf
[MAXPATHLEN
+1];
854 vp
= getcwd(cwdbuf
, MAXPATHLEN
);
858 return vmsname
; /*FIXME, err getcwd */
869 char *vp
= strchr (vptr
, ']');
877 vptr
+= strlen (vptr
);
890 /* directory conversion done
891 fptr -> filename part of input string
892 vptr -> free space in vmsname
903 convert from vms-style to unix-style
905 dev:[dir1.dir2] //dev/dir1/dir2/
909 unixify (const char *name
)
911 static char piece
[512];
915 if (strchr (name
, '/') != 0) /* already in unix style */
917 strcpy (piece
, name
);
926 s
= strchr (name
, ':');
933 strncpy (p
, name
, l
);
940 s
= strchr (name
, '[');
954 strcat (p
, "./"); /* [. */
974 if (*s
!= 0) /* more after ']' ?? */
978 strcpy (p
, s
); /* copy it anyway */
982 else /* no '[' anywhere */
988 /* force end with '/' */