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.
5
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.
9
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.
13
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. */
17
18 /* Written by Klaus K�mpf (kkaempf@progis.de)
19 of proGIS Software, Aachen, Germany */
20
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25
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. */
38
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)
45
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(). */
49
50 #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
51 #endif
52
53 /*
54 copy 'from' to 'to' up to but not including 'upto'
55 return 0 if eos on from
56 return 1 if upto found
57
58 return 'to' at last char + 1
59 return 'from' at match + 1 or eos if no match
60
61 if as_dir == 1, change all '.' to '_'
62 else change all '.' but the last to '_'
63 */
64
65 static int
copyto(char ** to,char ** from,char upto,int as_dir)66 copyto (char **to, char **from, char upto, int as_dir)
67 {
68 char *s;
69
70 s = strrchr (*from, '.');
71
72 while (**from)
73 {
74 if (**from == upto)
75 {
76 do
77 {
78 (*from)++;
79 }
80 while (**from == upto);
81 return 1;
82 }
83 if (**from == '.')
84 {
85 if ((as_dir == 1)
86 || (*from != s))
87 **to = '_';
88 else
89 **to = '.';
90 }
91 else
92 {
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;
99 }
100 (*to)++;
101 (*from)++;
102 }
103
104 return 0;
105 }
106
107
108 /*
109 get translation of logical name
110
111 */
112
113 static char *
trnlog(char * name)114 trnlog (char *name)
115 {
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;
122
123 INIT_DSC_CSTRING (name_dsc, name);
124
125 stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
126
127 if ((stat&1) == 0)
128 {
129 return "";
130 }
131 if (stat == SS$_NOTRAN)
132 {
133 return "";
134 }
135 reslt[resltlen] = '\0';
136
137 s = (char *)malloc (resltlen+1);
138 if (s == 0)
139 return "";
140 strcpy (s, reslt);
141 return s;
142 }
143
144 static char *
showall(char * s)145 showall (char *s)
146 {
147 static char t[512];
148 char *pt;
149
150 pt = t;
151 if (strchr (s, '\\') == 0)
152 return s;
153 while (*s)
154 {
155 if (*s == '\\')
156 {
157 *pt++ = *s;
158 }
159 *pt++ = *s++;
160 }
161 return pt;
162 }
163
164
165 enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
166
167 /*
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
172
173 The following conversions are applied
174 (0) (1) (2)
175 input full name dir name file name
176
177 1 ./ <cwd> [] <current directory>.dir
178 2 ../ <home of cwd> <home of cwd> <home of cwd>.dir
179
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
183
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
191
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
198
199 22 a.b.c a_b.c [.a_b_c] a_b_c.dir
200
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
203
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
207
208 the input string is not written to
209 */
210
211 char *
vmsify(char * name,int type)212 vmsify (char *name, int type)
213 {
214 /* max 255 device
215 max 39 directory
216 max 39 filename
217 max 39 filetype
218 max 5 version
219 */
220 #define MAXPATHLEN 512
221
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;
229
230 if (name == 0)
231 return 0;
232 fptr = name;
233 vptr = vmsname;
234 nstate = N_START;
235
236 /* case 25a */
237
238 s = strpbrk (name, "$:");
239 if (s != 0)
240 {
241 char *s1;
242 char *s2;
243
244 if (type == 1)
245 {
246 s1 = strchr (s+1, '[');
247 s2 = strchr (s+1, ']');
248 }
249
250 if (*s == '$')
251 {
252 if (strchr (name, '/') == 0)
253 {
254 if ((type == 1) && (s1 != 0) && (s2 == 0))
255 {
256 strcpy (vmsname, name);
257 strcat (vmsname, "]");
258 return vmsname;
259 }
260 else
261 return name;
262 }
263 }
264 else
265 {
266 if ((type == 1) && (s1 != 0) && (s2 == 0))
267 {
268 strcpy (vmsname, name);
269 strcat (vmsname, "]");
270 return vmsname;
271 }
272 else
273 return name;
274 }
275 }
276
277 /* case 26 */
278
279 s = strchr (name, '[');
280
281 if (s != 0)
282 {
283 s1 = strchr (s+1, '[');
284 if (s1 == 0)
285 {
286 if ((type == 1)
287 && (strchr (s+1, ']') == 0))
288 {
289 strcpy (vmsname, name);
290 strcat (vmsname, "]");
291 return vmsname;
292 }
293 else
294 return name; /* single [, keep unchanged */
295 }
296 s1--;
297 if (*s1 != ']')
298 {
299 return name; /* not ][, keep unchanged */
300 }
301
302 /* we have ][ */
303
304 s = name;
305
306 /* s -> starting char
307 s1 -> ending ']' */
308
309 do
310 {
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);
324 }
325 while (1);
326
327 *vptr++ = ']';
328
329 fptr = s;
330
331 }
332
333 else /* no [ in name */
334
335 {
336
337 int state;
338 int rooted = 1; /* flag if logical is rooted, else insert [000000] */
339
340 state = 0;
341
342 do
343 {
344
345 switch (state)
346 {
347 case 0: /* start of loop */
348 if (*fptr == '/')
349 {
350 fptr++;
351 state = 1;
352 }
353 else if (*fptr == '.')
354 {
355 fptr++;
356 state = 10;
357 }
358 else
359 state = 2;
360 break;
361
362 case 1: /* '/' at start */
363 if (*fptr == '/')
364 {
365 fptr++;
366 state = 3;
367 }
368 else
369 state = 4;
370 break;
371
372 case 2: /* no '/' at start */
373 s = strchr (fptr, '/');
374 if (s == 0) /* no '/' (16) */
375 {
376 if (type == 1)
377 {
378 strcpy (vptr, "[.");
379 vptr += 2;
380 }
381 copyto (&vptr, &fptr, 0, (type==1));
382 if (type == 1)
383 *vptr++ = ']';
384 state = -1;
385 }
386 else /* found '/' (17..21) */
387 {
388 if ((type == 2)
389 && (*(s+1) == 0)) /* 17(2) */
390 {
391 copyto (&vptr, &fptr, '/', 1);
392 state = 7;
393 }
394 else
395 {
396 strcpy (vptr, "[.");
397 vptr += 2;
398 copyto (&vptr, &fptr, '/', 1);
399 nstate = N_OPEN;
400 state = 9;
401 }
402 }
403 break;
404
405 case 3: /* '//' at start */
406 while (*fptr == '/') /* collapse all '/' */
407 fptr++;
408 if (*fptr == 0) /* just // */
409 {
410 char cwdbuf[MAXPATHLEN+1];
411
412 s1 = getcwd(cwdbuf, MAXPATHLEN);
413 if (s1 == 0)
414 {
415 return ""; /* FIXME, err getcwd */
416 }
417 s = strchr (s1, ':');
418 if (s == 0)
419 {
420 return ""; /* FIXME, err no device */
421 }
422 strncpy (vptr, s1, s-s1+1);
423 vptr += s-s1+1;
424 state = -1;
425 break;
426 }
427
428 s = vptr;
429
430 if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
431 {
432 *vptr++ = ':';
433 state = -1;
434 break;
435 }
436 *vptr = ':';
437 nstate = N_DEVICE;
438 if (*fptr == 0) /* just '//a/' */
439 {
440 strcpy (vptr+1, "[000000]");
441 vptr += 9;
442 state = -1;
443 break;
444 }
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 */
452 {
453 s2 = s1 + strlen (s1) - 1;
454 if (*s2 == ':') /* translation ends in ':' */
455 {
456 s2 = trnlog (s1);
457 free (s1);
458 if (*s2 == 0)
459 {
460 rooted = 0;
461 break;
462 }
463 s1 = s2;
464 continue; /* next iteration */
465 }
466 if (*s2 == ']') /* translation ends in ']' */
467 {
468 if (*(s2-1) == '.') /* ends in '.]' */
469 {
470 if (strncmp (fptr, "000000", 6) != 0)
471 rooted = 0;
472 }
473 else
474 {
475 strcpy (vmsname, s1);
476 s = strchr (vmsname, ']');
477 *s = '.';
478 nstate = N_DOT;
479 vptr = s;
480 }
481 }
482 break;
483 }
484 free (s1);
485 }
486 else
487 rooted = 0;
488
489 if (*vptr == 0)
490 {
491 nstate = N_DEVICE;
492 *vptr++ = ':';
493 }
494 else
495 vptr++;
496
497 if (rooted == 0)
498 {
499 strcpy (vptr, "[000000.");
500 vptr += 8;
501 s1 = vptr-1;
502 nstate = N_DOT;
503 }
504 else
505 s1 = 0;
506
507 /* s1-> '.' after 000000 or NULL */
508
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;
519 }
520 else
521 {
522 while (*(s+1) == '/') /* skip multiple '/' */
523 s++;
524 }
525
526 if ((rooted != 0)
527 && (*(vptr-1) != '.'))
528 {
529 *vptr++ = '[';
530 nstate = N_DOT;
531 }
532 else
533 if ((nstate == N_DOT)
534 && (s1 != 0)
535 && (*(s+1) == 0))
536 {
537 if (type == 2)
538 {
539 *s1 = ']';
540 nstate = N_CLOSED;
541 }
542 }
543 state = 9;
544 break;
545
546 case 4: /* single '/' at start (9..15) */
547 if (*fptr == 0)
548 state = 5;
549 else
550 state = 6;
551 break;
552
553 case 5: /* just '/' at start (9) */
554 if (type != 2)
555 {
556 *vptr++ = '[';
557 nstate = N_OPEN;
558 }
559 strcpy (vptr, "000000");
560 vptr += 6;
561 if (type == 2)
562 state = 7;
563 else
564 state = 8;
565 break;
566
567 case 6: /* chars following '/' at start 10..15 */
568 *vptr++ = '[';
569 nstate = N_OPEN;
570 s = strchr (fptr, '/');
571 if (s == 0) /* 10 */
572 {
573 if (type != 1)
574 {
575 strcpy (vptr, "000000]");
576 vptr += 7;
577 }
578 copyto (&vptr, &fptr, 0, (type == 1));
579 if (type == 1)
580 {
581 *vptr++ = ']';
582 }
583 state = -1;
584 }
585 else /* 11..15 */
586 {
587 if ( (type == 2)
588 && (*(s+1) == 0)) /* 11(2) */
589 {
590 strcpy (vptr, "000000]");
591 nstate = N_CLOSED;
592 vptr += 7;
593 }
594 copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
595 state = 9;
596 }
597 break;
598
599 case 7: /* add '.dir' and exit */
600 if ((nstate == N_OPEN)
601 || (nstate == N_DOT))
602 {
603 s = vptr-1;
604 while (s > vmsname)
605 {
606 if (*s == ']')
607 {
608 break;
609 }
610 if (*s == '.')
611 {
612 *s = ']';
613 break;
614 }
615 s--;
616 }
617 }
618 strcpy (vptr, ".dir");
619 vptr += 4;
620 state = -1;
621 break;
622
623 case 8: /* add ']' and exit */
624 *vptr++ = ']';
625 state = -1;
626 break;
627
628 case 9: /* 17..21, fptr -> 1st '/' + 1 */
629 if (*fptr == 0)
630 {
631 if (type == 2)
632 {
633 state = 7;
634 }
635 else
636 state = 8;
637 break;
638 }
639 s = strchr (fptr, '/');
640 if (s == 0)
641 {
642 if (type != 1)
643 {
644 if (nstate == N_OPEN)
645 {
646 *vptr++ = ']';
647 nstate = N_CLOSED;
648 }
649 as_dir = 0;
650 }
651 else
652 {
653 if (nstate == N_OPEN)
654 {
655 *vptr++ = '.';
656 nstate = N_DOT;
657 }
658 as_dir = 1;
659 }
660 }
661 else
662 {
663 while (*(s+1) == '/')
664 s++;
665 if ( (type == 2)
666 && (*(s+1) == 0)) /* 19(2), 21(2)*/
667 {
668 if (nstate != N_CLOSED)
669 {
670 *vptr++ = ']';
671 nstate = N_CLOSED;
672 }
673 as_dir = 1;
674 }
675 else
676 {
677 if (nstate == N_OPEN)
678 {
679 *vptr++ = '.';
680 nstate = N_DOT;
681 }
682 as_dir = 1;
683 }
684 }
685 if ( (*fptr == '.') /* check for '..' or '../' */
686 && (*(fptr+1) == '.')
687 && ((*(fptr+2) == '/')
688 || (*(fptr+2) == 0)) )
689 {
690 fptr += 2;
691 if (*fptr == '/')
692 {
693 do
694 {
695 fptr++;
696 }
697 while (*fptr == '/');
698 }
699 else if (*fptr == 0)
700 type = 1;
701 vptr--; /* vptr -> '.' or ']' */
702 s1 = vptr;
703 for (;;)
704 {
705 s1--;
706 if (*s1 == '.') /* one back */
707 {
708 vptr = s1;
709 nstate = N_OPEN;
710 break;
711 }
712 if (*s1 == '[') /* top level reached */
713 {
714 if (*fptr == 0)
715 {
716 strcpy (s1, "[000000]");
717 vptr = s1 + 8;
718 nstate = N_CLOSED;
719 s = 0;
720 break;
721 }
722 else
723 {
724 vptr = s1+1;
725 nstate = N_OPEN;
726 break;
727 }
728 }
729 }
730 }
731 else
732 {
733 copyto (&vptr, &fptr, '/', as_dir);
734 if (nstate == N_DOT)
735 nstate = N_OPEN;
736 }
737 if (s == 0)
738 { /* 18,20 */
739 if (type == 1)
740 *vptr++ = ']';
741 state = -1;
742 }
743 else
744 {
745 if (*(s+1) == 0)
746 {
747 if (type == 2) /* 19,21 */
748 {
749 state = 7;
750 }
751 else
752 {
753 *vptr++ = ']';
754 state = -1;
755 }
756 }
757 }
758 break;
759
760 case 10: /* 1,2 first is '.' */
761 if (*fptr == '.')
762 {
763 fptr++;
764 state = 11;
765 }
766 else
767 state = 12;
768 break;
769
770 case 11: /* 2, '..' at start */
771 count = 1;
772 if (*fptr != 0)
773 {
774 if (*fptr != '/') /* got ..xxx */
775 {
776 return name;
777 }
778 do /* got ../ */
779 {
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++;
790 }
791 while (*fptr == '/');
792 }
793 { /* got '..' or '../' */
794 char cwdbuf[MAXPATHLEN+1];
795
796 s1 = getcwd(cwdbuf, MAXPATHLEN);
797 if (s1 == 0)
798 {
799 return ""; /* FIXME, err getcwd */
800 }
801 strcpy (vptr, s1);
802 s = strchr (vptr, ']');
803 if (s != 0)
804 {
805 nstate = N_OPEN;
806 while (s > vptr)
807 {
808 s--;
809 if (*s == '[')
810 {
811 s++;
812 strcpy (s, "000000]");
813 state = -1;
814 break;
815 }
816 else if (*s == '.')
817 {
818 if (--count == 0)
819 {
820 if (*fptr == 0) /* had '..' or '../' */
821 {
822 *s++ = ']';
823 state = -1;
824 }
825 else /* had '../xxx' */
826 {
827 state = 9;
828 }
829 *s = 0;
830 break;
831 }
832 }
833 }
834 }
835 vptr += strlen (vptr);
836 }
837 break;
838
839 case 12: /* 1, '.' at start */
840 if (*fptr != 0)
841 {
842 if (*fptr != '/')
843 {
844 return name;
845 }
846 while (*fptr == '/')
847 fptr++;
848 }
849
850 {
851 char cwdbuf[MAXPATHLEN+1];
852
853 s1 = getcwd(cwdbuf, MAXPATHLEN);
854 if (s1 == 0)
855 {
856 return ""; /*FIXME, err getcwd */
857 }
858 strcpy (vptr, s1);
859 if (*fptr == 0)
860 {
861 state = -1;
862 break;
863 }
864 else
865 {
866 s = strchr (vptr, ']');
867 if (s == 0)
868 {
869 state = -1;
870 break;
871 }
872 *s = 0;
873 nstate = N_OPEN;
874 vptr += strlen (vptr);
875 state = 9;
876 }
877 }
878 break;
879 }
880
881 }
882 while (state > 0);
883
884
885 }
886
887
888 /* directory conversion done
889 fptr -> filename part of input string
890 vptr -> free space in vmsname
891 */
892
893 *vptr++ = 0;
894
895 return vmsname;
896 }
897
898
899
900 /*
901 convert from vms-style to unix-style
902
903 dev:[dir1.dir2] //dev/dir1/dir2/
904 */
905
906 char *
unixify(char * name)907 unixify (char *name)
908 {
909 static char piece[512];
910 char *s, *p;
911
912 if (strchr (name, '/') != 0) /* already in unix style */
913 return name;
914
915 p = piece;
916 *p = 0;
917
918 /* device part */
919
920 s = strchr (name, ':');
921
922 if (s != 0)
923 {
924 *s = 0;
925 *p++ = '/';
926 *p++ = '/';
927 strcpy (p, name);
928 p += strlen (p);
929 *s = ':';
930 }
931
932 /* directory part */
933
934 *p++ = '/';
935 s = strchr (name, '[');
936
937 if (s != 0)
938 {
939 s++;
940 switch (*s)
941 {
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;
954 }
955 s++;
956 while (*s)
957 {
958 if (*s == '.')
959 *p++ = '/';
960 else
961 *p++ = *s;
962 s++;
963 if (*s == ']')
964 {
965 s++;
966 break;
967 }
968 }
969 if (*s != 0) /* more after ']' ?? */
970 {
971 if (*(p-1) != '/')
972 *p++ = '/';
973 strcpy (p, s); /* copy it anyway */
974 }
975 }
976
977 else /* no '[' anywhere */
978
979 {
980 *p++ = 0;
981 }
982
983 /* force end with '/' */
984
985 if (*(p-1) != '/')
986 *p++ = '/';
987 *p = 0;
988
989 return piece;
990 }
991
992 /* EOF */
993