Release GNU make 3.81.
[make.git] / vmsify.c
blobac82942c9ef584321060948aebdcff769d1f0a76
1 /* vmsify.c -- Module for vms <-> unix file name conversion
2 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006 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 2, or (at your option) any later version.
10 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along with
15 GNU Make; see the file COPYING. If not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
18 /* Written by Klaus Kämpf (kkaempf@progis.de)
19 of proGIS Software, Aachen, Germany */
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
26 #if VMS
27 #include <unixlib.h>
28 #include <stdlib.h>
29 #include <jpidef.h>
30 #include <descrip.h>
31 #include <uaidef.h>
32 #include <ssdef.h>
33 #include <starlet.h>
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); \
44 } while (0)
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))
51 #endif
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 '_'
65 static int
66 copyto (char **to, char **from, char upto, int as_dir)
68 char *s;
70 s = strrchr (*from, '.');
72 while (**from)
74 if (**from == upto)
78 (*from)++;
80 while (**from == upto);
81 return 1;
83 if (**from == '.')
85 if ((as_dir == 1)
86 || (*from != s))
87 **to = '_';
88 else
89 **to = '.';
91 else
93 #ifdef HAVE_CASE_INSENSITIVE_FS
94 if (isupper ((unsigned char)**from))
95 **to = tolower ((unsigned char)**from);
96 else
97 #endif
98 **to = **from;
100 (*to)++;
101 (*from)++;
104 return 0;
109 get translation of logical name
113 static char *
114 trnlog (char *name)
116 int stat;
117 static char reslt[1024];
118 $DESCRIPTOR (reslt_dsc, reslt);
119 short resltlen;
120 struct dsc$descriptor_s name_dsc;
121 char *s;
123 INIT_DSC_CSTRING (name_dsc, name);
125 stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
127 if ((stat&1) == 0)
129 return "";
131 if (stat == SS$_NOTRAN)
133 return "";
135 reslt[resltlen] = '\0';
137 s = (char *)malloc (resltlen+1);
138 if (s == 0)
139 return "";
140 strcpy (s, reslt);
141 return s;
144 static char *
145 showall (char *s)
147 static char t[512];
148 char *pt;
150 pt = t;
151 if (strchr (s, '\\') == 0)
152 return s;
153 while (*s)
155 if (*s == '\\')
157 *pt++ = *s;
159 *pt++ = *s++;
161 return pt;
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
174 (0) (1) (2)
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
181 4 //a a: a: a:
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
192 16 a a [.a] a
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
211 char *
212 vmsify (char *name, int type)
214 /* max 255 device
215 max 39 directory
216 max 39 filename
217 max 39 filetype
218 max 5 version
220 #define MAXPATHLEN 512
222 enum namestate nstate;
223 static char vmsname[MAXPATHLEN+1];
224 char *fptr;
225 char *vptr;
226 char *s,*s1;
227 int as_dir;
228 int count;
230 if (name == 0)
231 return 0;
232 fptr = name;
233 vptr = vmsname;
234 nstate = N_START;
236 /* case 25a */
238 s = strpbrk (name, "$:");
239 if (s != 0)
241 char *s1;
242 char *s2;
244 if (type == 1)
246 s1 = strchr (s+1, '[');
247 s2 = strchr (s+1, ']');
250 if (*s == '$')
252 if (strchr (name, '/') == 0)
254 if ((type == 1) && (s1 != 0) && (s2 == 0))
256 strcpy (vmsname, name);
257 strcat (vmsname, "]");
258 return vmsname;
260 else
261 return name;
264 else
266 if ((type == 1) && (s1 != 0) && (s2 == 0))
268 strcpy (vmsname, name);
269 strcat (vmsname, "]");
270 return vmsname;
272 else
273 return name;
277 /* case 26 */
279 s = strchr (name, '[');
281 if (s != 0)
283 s1 = strchr (s+1, '[');
284 if (s1 == 0)
286 if ((type == 1)
287 && (strchr (s+1, ']') == 0))
289 strcpy (vmsname, name);
290 strcat (vmsname, "]");
291 return vmsname;
293 else
294 return name; /* single [, keep unchanged */
296 s1--;
297 if (*s1 != ']')
299 return name; /* not ][, keep unchanged */
302 /* we have ][ */
304 s = name;
306 /* s -> starting char
307 s1 -> ending ']' */
311 strncpy (vptr, s, s1-s); /* copy up to but not including ']' */
312 vptr += s1-s;
313 if (*s1 == 0)
314 break;
315 s = s1 + 1; /* s -> char behind ']' */
316 if (*s != '[') /* was '][' ? */
317 break; /* no, last ] found, exit */
318 s++;
319 if (*s != '.')
320 *vptr++ = '.';
321 s1 = strchr (s, ']');
322 if (s1 == 0) /* no closing ] */
323 s1 = s + strlen (s);
325 while (1);
327 *vptr++ = ']';
329 fptr = s;
333 else /* no [ in name */
337 int state;
338 int rooted = 1; /* flag if logical is rooted, else insert [000000] */
340 state = 0;
345 switch (state)
347 case 0: /* start of loop */
348 if (*fptr == '/')
350 fptr++;
351 state = 1;
353 else if (*fptr == '.')
355 fptr++;
356 state = 10;
358 else
359 state = 2;
360 break;
362 case 1: /* '/' at start */
363 if (*fptr == '/')
365 fptr++;
366 state = 3;
368 else
369 state = 4;
370 break;
372 case 2: /* no '/' at start */
373 s = strchr (fptr, '/');
374 if (s == 0) /* no '/' (16) */
376 if (type == 1)
378 strcpy (vptr, "[.");
379 vptr += 2;
381 copyto (&vptr, &fptr, 0, (type==1));
382 if (type == 1)
383 *vptr++ = ']';
384 state = -1;
386 else /* found '/' (17..21) */
388 if ((type == 2)
389 && (*(s+1) == 0)) /* 17(2) */
391 copyto (&vptr, &fptr, '/', 1);
392 state = 7;
394 else
396 strcpy (vptr, "[.");
397 vptr += 2;
398 copyto (&vptr, &fptr, '/', 1);
399 nstate = N_OPEN;
400 state = 9;
403 break;
405 case 3: /* '//' at start */
406 while (*fptr == '/') /* collapse all '/' */
407 fptr++;
408 if (*fptr == 0) /* just // */
410 char cwdbuf[MAXPATHLEN+1];
412 s1 = getcwd(cwdbuf, MAXPATHLEN);
413 if (s1 == 0)
415 return ""; /* FIXME, err getcwd */
417 s = strchr (s1, ':');
418 if (s == 0)
420 return ""; /* FIXME, err no device */
422 strncpy (vptr, s1, s-s1+1);
423 vptr += s-s1+1;
424 state = -1;
425 break;
428 s = vptr;
430 if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
432 *vptr++ = ':';
433 state = -1;
434 break;
436 *vptr = ':';
437 nstate = N_DEVICE;
438 if (*fptr == 0) /* just '//a/' */
440 strcpy (vptr+1, "[000000]");
441 vptr += 9;
442 state = -1;
443 break;
445 *vptr = 0;
446 /* check logical for [000000] insertion */
447 s1 = trnlog (s);
448 if (*s1 != 0)
449 { /* found translation */
450 char *s2;
451 for (;;) /* loop over all nested logicals */
453 s2 = s1 + strlen (s1) - 1;
454 if (*s2 == ':') /* translation ends in ':' */
456 s2 = trnlog (s1);
457 free (s1);
458 if (*s2 == 0)
460 rooted = 0;
461 break;
463 s1 = s2;
464 continue; /* next iteration */
466 if (*s2 == ']') /* translation ends in ']' */
468 if (*(s2-1) == '.') /* ends in '.]' */
470 if (strncmp (fptr, "000000", 6) != 0)
471 rooted = 0;
473 else
475 strcpy (vmsname, s1);
476 s = strchr (vmsname, ']');
477 *s = '.';
478 nstate = N_DOT;
479 vptr = s;
482 break;
484 free (s1);
486 else
487 rooted = 0;
489 if (*vptr == 0)
491 nstate = N_DEVICE;
492 *vptr++ = ':';
494 else
495 vptr++;
497 if (rooted == 0)
499 strcpy (vptr, "[000000.");
500 vptr += 8;
501 s1 = vptr-1;
502 nstate = N_DOT;
504 else
505 s1 = 0;
507 /* s1-> '.' after 000000 or NULL */
509 s = strchr (fptr, '/');
510 if (s == 0)
511 { /* no next '/' */
512 if (*(vptr-1) == '.')
513 *(vptr-1) = ']';
514 else if (rooted == 0)
515 *vptr++ = ']';
516 copyto (&vptr, &fptr, 0, (type == 1));
517 state = -1;
518 break;
520 else
522 while (*(s+1) == '/') /* skip multiple '/' */
523 s++;
526 if ((rooted != 0)
527 && (*(vptr-1) != '.'))
529 *vptr++ = '[';
530 nstate = N_DOT;
532 else
533 if ((nstate == N_DOT)
534 && (s1 != 0)
535 && (*(s+1) == 0))
537 if (type == 2)
539 *s1 = ']';
540 nstate = N_CLOSED;
543 state = 9;
544 break;
546 case 4: /* single '/' at start (9..15) */
547 if (*fptr == 0)
548 state = 5;
549 else
550 state = 6;
551 break;
553 case 5: /* just '/' at start (9) */
554 if (type != 2)
556 *vptr++ = '[';
557 nstate = N_OPEN;
559 strcpy (vptr, "000000");
560 vptr += 6;
561 if (type == 2)
562 state = 7;
563 else
564 state = 8;
565 break;
567 case 6: /* chars following '/' at start 10..15 */
568 *vptr++ = '[';
569 nstate = N_OPEN;
570 s = strchr (fptr, '/');
571 if (s == 0) /* 10 */
573 if (type != 1)
575 strcpy (vptr, "000000]");
576 vptr += 7;
578 copyto (&vptr, &fptr, 0, (type == 1));
579 if (type == 1)
581 *vptr++ = ']';
583 state = -1;
585 else /* 11..15 */
587 if ( (type == 2)
588 && (*(s+1) == 0)) /* 11(2) */
590 strcpy (vptr, "000000]");
591 nstate = N_CLOSED;
592 vptr += 7;
594 copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
595 state = 9;
597 break;
599 case 7: /* add '.dir' and exit */
600 if ((nstate == N_OPEN)
601 || (nstate == N_DOT))
603 s = vptr-1;
604 while (s > vmsname)
606 if (*s == ']')
608 break;
610 if (*s == '.')
612 *s = ']';
613 break;
615 s--;
618 strcpy (vptr, ".dir");
619 vptr += 4;
620 state = -1;
621 break;
623 case 8: /* add ']' and exit */
624 *vptr++ = ']';
625 state = -1;
626 break;
628 case 9: /* 17..21, fptr -> 1st '/' + 1 */
629 if (*fptr == 0)
631 if (type == 2)
633 state = 7;
635 else
636 state = 8;
637 break;
639 s = strchr (fptr, '/');
640 if (s == 0)
642 if (type != 1)
644 if (nstate == N_OPEN)
646 *vptr++ = ']';
647 nstate = N_CLOSED;
649 as_dir = 0;
651 else
653 if (nstate == N_OPEN)
655 *vptr++ = '.';
656 nstate = N_DOT;
658 as_dir = 1;
661 else
663 while (*(s+1) == '/')
664 s++;
665 if ( (type == 2)
666 && (*(s+1) == 0)) /* 19(2), 21(2)*/
668 if (nstate != N_CLOSED)
670 *vptr++ = ']';
671 nstate = N_CLOSED;
673 as_dir = 1;
675 else
677 if (nstate == N_OPEN)
679 *vptr++ = '.';
680 nstate = N_DOT;
682 as_dir = 1;
685 if ( (*fptr == '.') /* check for '..' or '../' */
686 && (*(fptr+1) == '.')
687 && ((*(fptr+2) == '/')
688 || (*(fptr+2) == 0)) )
690 fptr += 2;
691 if (*fptr == '/')
695 fptr++;
697 while (*fptr == '/');
699 else if (*fptr == 0)
700 type = 1;
701 vptr--; /* vptr -> '.' or ']' */
702 s1 = vptr;
703 for (;;)
705 s1--;
706 if (*s1 == '.') /* one back */
708 vptr = s1;
709 nstate = N_OPEN;
710 break;
712 if (*s1 == '[') /* top level reached */
714 if (*fptr == 0)
716 strcpy (s1, "[000000]");
717 vptr = s1 + 8;
718 nstate = N_CLOSED;
719 s = 0;
720 break;
722 else
724 vptr = s1+1;
725 nstate = N_OPEN;
726 break;
731 else
733 copyto (&vptr, &fptr, '/', as_dir);
734 if (nstate == N_DOT)
735 nstate = N_OPEN;
737 if (s == 0)
738 { /* 18,20 */
739 if (type == 1)
740 *vptr++ = ']';
741 state = -1;
743 else
745 if (*(s+1) == 0)
747 if (type == 2) /* 19,21 */
749 state = 7;
751 else
753 *vptr++ = ']';
754 state = -1;
758 break;
760 case 10: /* 1,2 first is '.' */
761 if (*fptr == '.')
763 fptr++;
764 state = 11;
766 else
767 state = 12;
768 break;
770 case 11: /* 2, '..' at start */
771 count = 1;
772 if (*fptr != 0)
774 if (*fptr != '/') /* got ..xxx */
776 return name;
778 do /* got ../ */
780 fptr++;
781 while (*fptr == '/') fptr++;
782 if (*fptr != '.')
783 break;
784 if (*(fptr+1) != '.')
785 break;
786 fptr += 2;
787 if ((*fptr == 0)
788 || (*fptr == '/'))
789 count++;
791 while (*fptr == '/');
793 { /* got '..' or '../' */
794 char cwdbuf[MAXPATHLEN+1];
796 s1 = getcwd(cwdbuf, MAXPATHLEN);
797 if (s1 == 0)
799 return ""; /* FIXME, err getcwd */
801 strcpy (vptr, s1);
802 s = strchr (vptr, ']');
803 if (s != 0)
805 nstate = N_OPEN;
806 while (s > vptr)
808 s--;
809 if (*s == '[')
811 s++;
812 strcpy (s, "000000]");
813 state = -1;
814 break;
816 else if (*s == '.')
818 if (--count == 0)
820 if (*fptr == 0) /* had '..' or '../' */
822 *s++ = ']';
823 state = -1;
825 else /* had '../xxx' */
827 state = 9;
829 *s = 0;
830 break;
835 vptr += strlen (vptr);
837 break;
839 case 12: /* 1, '.' at start */
840 if (*fptr != 0)
842 if (*fptr != '/')
844 return name;
846 while (*fptr == '/')
847 fptr++;
851 char cwdbuf[MAXPATHLEN+1];
853 s1 = getcwd(cwdbuf, MAXPATHLEN);
854 if (s1 == 0)
856 return ""; /*FIXME, err getcwd */
858 strcpy (vptr, s1);
859 if (*fptr == 0)
861 state = -1;
862 break;
864 else
866 s = strchr (vptr, ']');
867 if (s == 0)
869 state = -1;
870 break;
872 *s = 0;
873 nstate = N_OPEN;
874 vptr += strlen (vptr);
875 state = 9;
878 break;
882 while (state > 0);
888 /* directory conversion done
889 fptr -> filename part of input string
890 vptr -> free space in vmsname
893 *vptr++ = 0;
895 return vmsname;
901 convert from vms-style to unix-style
903 dev:[dir1.dir2] //dev/dir1/dir2/
906 char *
907 unixify (char *name)
909 static char piece[512];
910 char *s, *p;
912 if (strchr (name, '/') != 0) /* already in unix style */
913 return name;
915 p = piece;
916 *p = 0;
918 /* device part */
920 s = strchr (name, ':');
922 if (s != 0)
924 *s = 0;
925 *p++ = '/';
926 *p++ = '/';
927 strcpy (p, name);
928 p += strlen (p);
929 *s = ':';
932 /* directory part */
934 *p++ = '/';
935 s = strchr (name, '[');
937 if (s != 0)
939 s++;
940 switch (*s)
942 case ']': /* [] */
943 strcat (p, "./");
944 break;
945 case '-': /* [- */
946 strcat (p, "../");
947 break;
948 case '.':
949 strcat (p, "./"); /* [. */
950 break;
951 default:
952 s--;
953 break;
955 s++;
956 while (*s)
958 if (*s == '.')
959 *p++ = '/';
960 else
961 *p++ = *s;
962 s++;
963 if (*s == ']')
965 s++;
966 break;
969 if (*s != 0) /* more after ']' ?? */
971 if (*(p-1) != '/')
972 *p++ = '/';
973 strcpy (p, s); /* copy it anyway */
977 else /* no '[' anywhere */
980 *p++ = 0;
983 /* force end with '/' */
985 if (*(p-1) != '/')
986 *p++ = '/';
987 *p = 0;
989 return piece;
992 /* EOF */