Save the variable buffer content, not a potentially old pointer to it.
[make.git] / vmsify.c
blob237ee86d7a8b18b1b523cb8fa1221918f96b4fb4
1 /* vmsify.c -- Module for vms <-> unix file name conversion
2 Copyright (C) 1996-2012 Free Software Foundation, Inc.
3 This file is part of GNU Make.
5 GNU Make is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3 of the License, or (at your option) any later
8 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 this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Written by Klaus Kämpf (kkaempf@progis.de)
18 of proGIS Software, Aachen, Germany */
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
25 #if VMS
26 #include <unixlib.h>
27 #include <stdlib.h>
28 #include <jpidef.h>
29 #include <descrip.h>
30 #include <uaidef.h>
31 #include <ssdef.h>
32 #include <starlet.h>
33 #include <lib$routines.h>
34 /* Initialize a string descriptor (struct dsc$descriptor_s) for an
35 arbitrary string. ADDR is a pointer to the first character
36 of the string, and LEN is the length of the string. */
38 #define INIT_DSC_S(dsc, addr, len) do { \
39 (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \
40 (dsc).dsc$b_class = DSC$K_CLASS_S; \
41 (dsc).dsc$w_length = (len); \
42 (dsc).dsc$a_pointer = (addr); \
43 } while (0)
45 /* Initialize a string descriptor (struct dsc$descriptor_s) for a
46 NUL-terminated string. S is a pointer to the string; the length
47 is determined by calling strlen(). */
49 #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
50 #endif
53 copy 'from' to 'to' up to but not including 'upto'
54 return 0 if eos on from
55 return 1 if upto found
57 return 'to' at last char + 1
58 return 'from' at match + 1 or eos if no match
60 if as_dir == 1, change all '.' to '_'
61 else change all '.' but the last to '_'
64 static int
65 copyto (char **to, const char **from, char upto, int as_dir)
67 const char *s;
69 s = strrchr (*from, '.');
71 while (**from)
73 if (**from == upto)
77 (*from)++;
79 while (**from == upto);
80 return 1;
82 if (**from == '.')
84 if ((as_dir == 1)
85 || (*from != s))
86 **to = '_';
87 else
88 **to = '.';
90 else
92 #ifdef HAVE_CASE_INSENSITIVE_FS
93 if (isupper ((unsigned char)**from))
94 **to = tolower ((unsigned char)**from);
95 else
96 #endif
97 **to = **from;
99 (*to)++;
100 (*from)++;
103 return 0;
108 get translation of logical name
112 static char *
113 trnlog (const char *name)
115 int stat;
116 static char reslt[1024];
117 $DESCRIPTOR (reslt_dsc, reslt);
118 short resltlen;
119 struct dsc$descriptor_s name_dsc;
120 char *s;
123 * the string isn't changed, but there is no string descriptor with
124 * "const char *dsc$a_pointer"
126 INIT_DSC_CSTRING (name_dsc, (char *)name);
128 stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
130 if ((stat&1) == 0)
132 return "";
134 if (stat == SS$_NOTRAN)
136 return "";
138 reslt[resltlen] = '\0';
140 s = malloc (resltlen+1);
141 if (s == 0)
142 return "";
143 strcpy (s, reslt);
144 return s;
147 static char *
148 showall (char *s)
150 static char t[512];
151 char *pt;
153 pt = t;
154 if (strchr (s, '\\') == 0)
155 return s;
156 while (*s)
158 if (*s == '\\')
160 *pt++ = *s;
162 *pt++ = *s++;
164 return pt;
168 enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
171 convert unix style name to vms style
172 type = 0 -> name is a full name (directory and filename part)
173 type = 1 -> name is a directory
174 type = 2 -> name is a filename without directory
176 The following conversions are applied
177 (0) (1) (2)
178 input full name dir name file name
180 1 ./ <cwd> [] <current directory>.dir
181 2 ../ <home of cwd> <home of cwd> <home of cwd>.dir
183 3 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir
184 4 //a a: a: a:
185 5 //a/ a: a: a:000000.dir
187 9 / [000000] [000000] 000000.dir
188 10 /a [000000]a [a] [000000]a
189 11 /a/ [a] [a] [000000]a.dir
190 12 /a/b [a]b [a.b] [a]b
191 13 /a/b/ [a.b] [a.b] [a]b.dir
192 14 /a/b/c [a.b]c [a.b.c] [a.b]c
193 15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir
195 16 a a [.a] a
196 17 a/ [.a] [.a] a.dir
197 18 a/b [.a]b [.a.b] [.a]b
198 19 a/b/ [.a.b] [.a.b] [.a]b.dir
199 20 a/b/c [.a.b]c [.a.b.c] [.a.b]c
200 21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir
202 22 a.b.c a_b.c [.a_b_c] a_b_c.dir
204 23 [x][y]z [x.y]z [x.y]z [x.y]z
205 24 [x][.y]z [x.y]z [x.y]z [x.y]z
207 25 filenames with '$' are left unchanged if they contain no '/'
208 25 filenames with ':' are left unchanged
209 26 filenames with a single pair of '[' ']' are left unchanged
211 The input string is not written to. The result is also const because
212 it's a static buffer; we don't want to change it.
215 const char *
216 vmsify (const char *name, int type)
218 /* max 255 device
219 max 39 directory
220 max 39 filename
221 max 39 filetype
222 max 5 version
224 #define MAXPATHLEN 512
226 enum namestate nstate;
227 static char vmsname[MAXPATHLEN+1];
228 const char *fptr;
229 const char *t;
230 char *vptr;
231 int as_dir;
232 int count;
233 const char *s;
234 const char *s1;
235 const char *s2;
237 if (name == 0)
238 return 0;
239 fptr = name;
240 vptr = vmsname;
241 nstate = N_START;
243 /* case 25a */
244 t = strpbrk (name, "$:");
246 if (t != 0)
248 // const char *s1;
249 // const char *s2;
251 if (type == 1)
253 s1 = strchr (t+1, '[');
254 s2 = strchr (t+1, ']');
257 if (*t == '$')
259 if (strchr (name, '/') == 0)
261 strcpy (vmsname, name);
262 if ((type == 1) && (s1 != 0) && (s2 == 0))
263 strcat (vmsname, "]");
264 return vmsname;
267 else
269 strcpy (vmsname, name);
270 if ((type == 1) && (s1 != 0) && (s2 == 0))
271 strcat (vmsname, "]");
272 return vmsname;
276 /* case 26 */
277 t = strchr (name, '[');
279 if (t != 0)
281 // const char *s;
282 // const char *s1 = strchr (t+1, '[');
283 s1 = strchr (t+1, '[');
284 if (s1 == 0)
286 strcpy (vmsname, name);
287 if ((type == 1) && (strchr (t+1, ']') == 0))
288 strcat (vmsname, "]");
289 return vmsname;
291 s1--;
292 if (*s1 != ']')
294 strcpy (vmsname, name);
295 return vmsname; /* not ][, keep unchanged */
298 /* we have ][ */
300 s = name;
302 /* s -> starting char
303 s1 -> ending ']' */
306 strncpy (vptr, s, s1-s); /* copy up to but not including ']' */
307 vptr += s1-s;
308 if (*s1 == 0)
309 break;
310 s = s1 + 1; /* s -> char behind ']' */
311 if (*s != '[') /* was '][' ? */
312 break; /* no, last ] found, exit */
313 s++;
314 if (*s != '.')
315 *vptr++ = '.';
316 s1 = strchr (s, ']');
317 if (s1 == 0) /* no closing ] */
318 s1 = s + strlen (s);
320 while (1);
322 *vptr++ = ']';
324 fptr = s;
327 else /* no [ in name */
329 int state = 0;
330 int rooted = 1; /* flag if logical is rooted, else insert [000000] */
334 switch (state)
336 case 0: /* start of loop */
337 if (*fptr == '/')
339 fptr++;
340 state = 1;
342 else if (*fptr == '.')
344 fptr++;
345 state = 10;
347 else
348 state = 2;
349 break;
351 case 1: /* '/' at start */
352 if (*fptr == '/')
354 fptr++;
355 state = 3;
357 else
358 state = 4;
359 break;
361 case 2: /* no '/' at start */
363 const char *s = strchr (fptr, '/');
364 if (s == 0) /* no '/' (16) */
366 if (type == 1)
368 strcpy (vptr, "[.");
369 vptr += 2;
371 copyto (&vptr, &fptr, 0, (type==1));
372 if (type == 1)
373 *vptr++ = ']';
374 state = -1;
376 else /* found '/' (17..21) */
378 if ((type == 2)
379 && (*(s+1) == 0)) /* 17(2) */
381 copyto (&vptr, &fptr, '/', 1);
382 state = 7;
384 else
386 strcpy (vptr, "[.");
387 vptr += 2;
388 copyto (&vptr, &fptr, '/', 1);
389 nstate = N_OPEN;
390 state = 9;
393 break;
396 case 3: /* '//' at start */
398 // const char *s;
399 // const char *s1;
400 char *vp;
401 while (*fptr == '/') /* collapse all '/' */
402 fptr++;
403 if (*fptr == 0) /* just // */
405 char cwdbuf[MAXPATHLEN+1];
407 s1 = getcwd(cwdbuf, MAXPATHLEN);
408 if (s1 == 0)
410 vmsname[0] = '\0';
411 return vmsname; /* FIXME, err getcwd */
413 s = strchr (s1, ':');
414 if (s == 0)
416 vmsname[0] = '\0';
417 return vmsname; /* FIXME, err no device */
419 strncpy (vptr, s1, s-s1+1);
420 vptr += s-s1+1;
421 state = -1;
422 break;
425 s = vptr;
427 if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
429 *vptr++ = ':';
430 state = -1;
431 break;
433 *vptr = ':';
434 nstate = N_DEVICE;
435 if (*fptr == 0) /* just '//a/' */
437 strcpy (vptr+1, "[000000]");
438 vptr += 9;
439 state = -1;
440 break;
442 *vptr = 0;
443 /* check logical for [000000] insertion */
444 vp = trnlog (s);
445 if (*vp != '\0')
446 { /* found translation */
447 for (;;) /* loop over all nested logicals */
449 char *vp2 = vp + strlen (vp) - 1;
450 if (*vp2 == ':') /* translation ends in ':' */
452 vp2 = trnlog (vp);
453 free (vp);
454 if (*vp2 == 0)
456 rooted = 0;
457 break;
459 vp = vp2;
460 continue; /* next iteration */
462 if (*vp2 == ']') /* translation ends in ']' */
464 if (*(vp2-1) == '.') /* ends in '.]' */
466 if (strncmp (fptr, "000000", 6) != 0)
467 rooted = 0;
469 else
471 strcpy (vmsname, s1);
472 vp = strchr (vmsname, ']');
473 *vp = '.';
474 nstate = N_DOT;
475 vptr = vp;
478 break;
480 free (vp);
482 else
483 rooted = 0;
485 if (*vptr == 0)
487 nstate = N_DEVICE;
488 *vptr++ = ':';
490 else
491 vptr++;
493 if (rooted == 0)
495 nstate = N_DOT;
496 strcpy (vptr, "[000000.");
497 vptr += 8;
498 vp = vptr-1;
500 else
501 vp = 0;
503 /* vp-> '.' after 000000 or NULL */
505 s = strchr (fptr, '/');
506 if (s == 0)
507 { /* no next '/' */
508 if (*(vptr-1) == '.')
509 *(vptr-1) = ']';
510 else if (rooted == 0)
511 *vptr++ = ']';
512 copyto (&vptr, &fptr, 0, (type == 1));
513 state = -1;
514 break;
516 else
518 while (*(s+1) == '/') /* skip multiple '/' */
519 s++;
522 if ((rooted != 0)
523 && (*(vptr-1) != '.'))
525 *vptr++ = '[';
526 nstate = N_DOT;
528 else
529 if ((nstate == N_DOT)
530 && (vp != 0)
531 && (*(s+1) == 0))
533 if (type == 2)
535 *vp = ']';
536 nstate = N_CLOSED;
539 state = 9;
540 break;
542 case 4: /* single '/' at start (9..15) */
543 if (*fptr == 0)
544 state = 5;
545 else
546 state = 6;
547 break;
549 case 5: /* just '/' at start (9) */
550 if (type != 2)
552 *vptr++ = '[';
553 nstate = N_OPEN;
555 strcpy (vptr, "000000");
556 vptr += 6;
557 if (type == 2)
558 state = 7;
559 else
560 state = 8;
561 break;
563 case 6: /* chars following '/' at start 10..15 */
565 const char *s;
566 *vptr++ = '[';
567 nstate = N_OPEN;
568 s = strchr (fptr, '/');
569 if (s == 0) /* 10 */
571 if (type != 1)
573 strcpy (vptr, "000000]");
574 vptr += 7;
576 copyto (&vptr, &fptr, 0, (type == 1));
577 if (type == 1)
579 *vptr++ = ']';
581 state = -1;
583 else /* 11..15 */
585 if ( (type == 2)
586 && (*(s+1) == 0)) /* 11(2) */
588 strcpy (vptr, "000000]");
589 nstate = N_CLOSED;
590 vptr += 7;
592 copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
593 state = 9;
595 break;
598 case 7: /* add '.dir' and exit */
599 if ((nstate == N_OPEN)
600 || (nstate == N_DOT))
602 char *vp = vptr-1;
603 while (vp > vmsname)
605 if (*vp == ']')
607 break;
609 if (*vp == '.')
611 *vp = ']';
612 break;
614 vp--;
617 strcpy (vptr, ".dir");
618 vptr += 4;
619 state = -1;
620 break;
622 case 8: /* add ']' and exit */
623 *vptr++ = ']';
624 state = -1;
625 break;
627 case 9: /* 17..21, fptr -> 1st '/' + 1 */
629 const char *s;
630 if (*fptr == 0)
632 if (type == 2)
634 state = 7;
636 else
637 state = 8;
638 break;
640 s = strchr (fptr, '/');
641 if (s == 0)
643 if (type != 1)
645 if (nstate == N_OPEN)
647 *vptr++ = ']';
648 nstate = N_CLOSED;
650 as_dir = 0;
652 else
654 if (nstate == N_OPEN)
656 *vptr++ = '.';
657 nstate = N_DOT;
659 as_dir = 1;
662 else
664 while (*(s+1) == '/')
665 s++;
666 if ( (type == 2)
667 && (*(s+1) == 0)) /* 19(2), 21(2)*/
669 if (nstate != N_CLOSED)
671 *vptr++ = ']';
672 nstate = N_CLOSED;
674 as_dir = 1;
676 else
678 if (nstate == N_OPEN)
680 *vptr++ = '.';
681 nstate = N_DOT;
683 as_dir = 1;
686 if ( (*fptr == '.') /* check for '..' or '../' */
687 && (*(fptr+1) == '.')
688 && ((*(fptr+2) == '/')
689 || (*(fptr+2) == 0)) )
691 char *vp;
692 fptr += 2;
693 if (*fptr == '/')
697 fptr++;
699 while (*fptr == '/');
701 else if (*fptr == 0)
702 type = 1;
703 vptr--; /* vptr -> '.' or ']' */
704 vp = vptr;
705 for (;;)
707 vp--;
708 if (*vp == '.') /* one back */
710 vptr = vp;
711 nstate = N_OPEN;
712 break;
714 if (*vp == '[') /* top level reached */
716 if (*fptr == 0)
718 strcpy (vp, "[000000]");
719 vptr = vp + 8;
720 nstate = N_CLOSED;
721 s = 0;
722 break;
724 else
726 vptr = vp+1;
727 nstate = N_OPEN;
728 break;
733 else
735 copyto (&vptr, &fptr, '/', as_dir);
736 if (nstate == N_DOT)
737 nstate = N_OPEN;
739 if (s == 0)
740 { /* 18,20 */
741 if (type == 1)
742 *vptr++ = ']';
743 state = -1;
745 else
747 if (*(s+1) == 0)
749 if (type == 2) /* 19,21 */
751 state = 7;
753 else
755 *vptr++ = ']';
756 state = -1;
760 break;
763 case 10: /* 1,2 first is '.' */
764 if (*fptr == '.')
766 fptr++;
767 state = 11;
769 else
770 state = 12;
771 break;
773 case 11: /* 2, '..' at start */
774 count = 1;
775 if (*fptr != 0)
777 if (*fptr != '/') /* got ..xxx */
779 strcpy (vmsname, name);
780 return vmsname;
782 do /* got ../ */
784 fptr++;
785 while (*fptr == '/') fptr++;
786 if (*fptr != '.')
787 break;
788 if (*(fptr+1) != '.')
789 break;
790 fptr += 2;
791 if ((*fptr == 0)
792 || (*fptr == '/'))
793 count++;
795 while (*fptr == '/');
797 { /* got '..' or '../' */
798 char *vp;
799 char cwdbuf[MAXPATHLEN+1];
801 vp = getcwd(cwdbuf, MAXPATHLEN);
802 if (vp == 0)
804 vmsname[0] = '\0';
805 return vmsname; /* FIXME, err getcwd */
807 strcpy (vptr, vp);
808 vp = strchr (vptr, ']');
809 if (vp != 0)
811 nstate = N_OPEN;
812 while (vp > vptr)
814 vp--;
815 if (*vp == '[')
817 vp++;
818 strcpy (vp, "000000]");
819 state = -1;
820 break;
822 else if (*vp == '.')
824 if (--count == 0)
826 if (*fptr == 0) /* had '..' or '../' */
828 *vp++ = ']';
829 state = -1;
831 else /* had '../xxx' */
833 state = 9;
835 *vp = '\0';
836 break;
841 vptr += strlen (vptr);
843 break;
845 case 12: /* 1, '.' at start */
846 if (*fptr != 0)
848 if (*fptr != '/')
850 strcpy (vmsname, name);
851 return vmsname;
853 while (*fptr == '/')
854 fptr++;
858 char *vp;
859 char cwdbuf[MAXPATHLEN+1];
861 vp = getcwd(cwdbuf, MAXPATHLEN);
862 if (vp == 0)
864 vmsname[0] = '\0';
865 return vmsname; /*FIXME, err getcwd */
867 strcpy (vptr, vp);
869 if (*fptr == 0)
871 state = -1;
872 break;
874 else
876 char *vp = strchr (vptr, ']');
877 if (vp == 0)
879 state = -1;
880 break;
882 *vp = '\0';
883 nstate = N_OPEN;
884 vptr += strlen (vptr);
885 state = 9;
887 break;
891 while (state > 0);
897 /* directory conversion done
898 fptr -> filename part of input string
899 vptr -> free space in vmsname
902 *vptr++ = 0;
904 return vmsname;
910 convert from vms-style to unix-style
912 dev:[dir1.dir2] //dev/dir1/dir2/
915 const char *
916 unixify (const char *name)
918 static char piece[512];
919 const char *s;
920 char *p;
922 if (strchr (name, '/') != 0) /* already in unix style */
924 strcpy (piece, name);
925 return piece;
928 p = piece;
929 *p = 0;
931 /* device part */
933 s = strchr (name, ':');
935 if (s != 0)
937 int l = s - name;
938 *p++ = '/';
939 *p++ = '/';
940 strncpy (p, name, l);
941 p += l;
944 /* directory part */
946 *p++ = '/';
947 s = strchr (name, '[');
949 if (s != 0)
951 s++;
952 switch (*s)
954 case ']': /* [] */
955 strcat (p, "./");
956 break;
957 case '-': /* [- */
958 strcat (p, "../");
959 break;
960 case '.':
961 strcat (p, "./"); /* [. */
962 break;
963 default:
964 s--;
965 break;
967 s++;
968 while (*s)
970 if (*s == '.')
971 *p++ = '/';
972 else
973 *p++ = *s;
974 s++;
975 if (*s == ']')
977 s++;
978 break;
981 if (*s != 0) /* more after ']' ?? */
983 if (*(p-1) != '/')
984 *p++ = '/';
985 strcpy (p, s); /* copy it anyway */
989 else /* no '[' anywhere */
992 *p++ = 0;
995 /* force end with '/' */
997 if (*(p-1) != '/')
998 *p++ = '/';
999 *p = 0;
1001 return piece;
1004 /* EOF */