* Oops. Fix a problem running submakes like $(MAKE) $(MFLAGS).
[make.git] / vmsify.c
blobb8b86a665315a1ed577ff05901c28a0cc0a5e014
1 /*
2 vmsify.c
4 Module for vms <-> unix file name conversion
6 Written by Klaus Kämpf (kkaempf@progis.de)
7 of proGIS Software, Aachen, Germany
9 */
11 #include <string.h>
12 #include <ctype.h>
14 #if VMS
15 #include <unixlib.h>
16 #include <stdlib.h>
17 #include <jpidef.h>
18 #include <descrip.h>
19 #include <uaidef.h>
20 #include <ssdef.h>
21 #include <starlet.h>
22 #include <lib$routines.h>
23 /* Initialize a string descriptor (struct dsc$descriptor_s) for an
24 arbitrary string. ADDR is a pointer to the first character
25 of the string, and LEN is the length of the string. */
27 #define INIT_DSC_S(dsc, addr, len) do { \
28 (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \
29 (dsc).dsc$b_class = DSC$K_CLASS_S; \
30 (dsc).dsc$w_length = (len); \
31 (dsc).dsc$a_pointer = (addr); \
32 } while (0)
34 /* Initialize a string descriptor (struct dsc$descriptor_s) for a
35 NUL-terminated string. S is a pointer to the string; the length
36 is determined by calling strlen(). */
38 #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
39 #endif
42 copy 'from' to 'to' up to but not including 'upto'
43 return 0 if eos on from
44 return 1 if upto found
46 return 'to' at last char + 1
47 return 'from' at match + 1 or eos if no match
49 if as_dir == 1, change all '.' to '_'
50 else change all '.' but the last to '_'
53 static int
54 copyto (char **to, char **from, char upto, int as_dir)
56 char *s;
58 s = strrchr (*from, '.');
60 while (**from)
62 if (**from == upto)
66 (*from)++;
68 while (**from == upto);
69 return 1;
71 if (**from == '.')
73 if ((as_dir == 1)
74 || (*from != s))
75 **to = '_';
76 else
77 **to = '.';
79 else
81 if (islower (**from))
82 **to = toupper (**from);
83 else
84 **to = **from;
86 (*to)++;
87 (*from)++;
90 return 0;
95 get translation of logical name
99 static char *
100 trnlog (char *name)
102 int stat;
103 static char reslt[1024];
104 $DESCRIPTOR (reslt_dsc, reslt);
105 short resltlen;
106 struct dsc$descriptor_s name_dsc;
107 char *s;
109 INIT_DSC_CSTRING (name_dsc, name);
111 stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
113 if ((stat&1) == 0)
115 return "";
117 if (stat == SS$_NOTRAN)
119 return "";
121 reslt[resltlen] = '\0';
123 s = (char *)malloc (resltlen+1);
124 if (s == 0)
125 return "";
126 strcpy (s, reslt);
127 return s;
130 enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
133 convert unix style name to vms style
134 type = 0 -> name is a full name (directory and filename part)
135 type = 1 -> name is a directory
136 type = 2 -> name is a filename without directory
138 The following conversions are applied
139 (0) (1) (2)
140 input full name dir name file name
142 1 ./ <cwd> [] <current directory>.dir
143 2 ../ <home of cwd> <home of cwd> <home of cwd>.dir
145 3 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir
146 4 //a a: a: a:
147 5 //a/ a: a: a:000000.dir
149 9 / [000000] [000000] 000000.dir
150 10 /a [000000]a [a] [000000]a
151 11 /a/ [a] [a] [000000]a.dir
152 12 /a/b [a]b [a.b] [a]b
153 13 /a/b/ [a.b] [a.b] [a]b.dir
154 14 /a/b/c [a.b]c [a.b.c] [a.b]c
155 15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir
157 16 a a [.a] a
158 17 a/ [.a] [.a] a.dir
159 18 a/b [.a]b [.a.b] [.a]b
160 19 a/b/ [.a.b] [.a.b] [.a]b.dir
161 20 a/b/c [.a.b]c [.a.b.c] [.a.b]c
162 21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir
164 22 a.b.c a_b.c [.a_b_c] a_b_c.dir
166 23 [x][y]z [x.y]z [x.y]z [x.y]z
167 24 [x][.y]z [x.y]z [x.y]z [x.y]z
169 25 filenames with '$' are left unchanged if they contain no '/'
170 25 filenames with ':' are left unchanged
171 26 filenames with a single pair of '[' ']' are left unchanged
173 the input string is not written to
176 char *
177 vmsify (name, type)
178 char *name;
179 int type;
181 /* max 255 device
182 max 39 directory
183 max 39 filename
184 max 39 filetype
185 max 5 version
187 #define MAXPATHLEN 512
189 enum namestate nstate;
190 static char vmsname[MAXPATHLEN+1];
191 char *fptr;
192 char *vptr;
193 char *s,*s1;
194 int as_dir;
195 int count;
197 if (name == 0)
198 return 0;
199 fptr = name;
200 vptr = vmsname;
201 nstate = N_START;
203 /* case 25a */
205 s = strpbrk (name, "$:");
206 if (s != 0)
208 if (*s == '$')
210 if (strchr (name, '/') == 0)
212 return name;
215 else
217 return name;
221 /* case 26 */
223 s = strchr (name, '[');
225 if (s != 0)
227 s1 = strchr (s+1, '[');
228 if (s1 == 0)
230 return name; /* single [, keep unchanged */
232 s1--;
233 if (*s1 != ']')
235 return name; /* not ][, keep unchanged */
238 /* we have ][ */
240 s = name;
242 /* s -> starting char
243 s1 -> ending ']' */
247 strncpy (vptr, s, s1-s); /* copy up to but not including ']' */
248 vptr += s1-s;
249 if (*s1 == 0)
250 break;
251 s = s1 + 1; /* s -> char behind ']' */
252 if (*s != '[') /* was '][' ? */
253 break; /* no, last ] found, exit */
254 s++;
255 if (*s != '.')
256 *vptr++ = '.';
257 s1 = strchr (s, ']');
258 if (s1 == 0) /* no closing ] */
259 s1 = s + strlen (s);
261 while (1);
263 *vptr++ = ']';
265 fptr = s;
269 else /* no [ in name */
273 int state;
274 int rooted = 1; /* flag if logical is rooted, else insert [000000] */
276 state = 0;
281 switch (state)
283 case 0: /* start of loop */
284 if (*fptr == '/')
286 fptr++;
287 state = 1;
289 else if (*fptr == '.')
291 fptr++;
292 state = 10;
294 else
295 state = 2;
296 break;
298 case 1: /* '/' at start */
299 if (*fptr == '/')
301 fptr++;
302 state = 3;
304 else
305 state = 4;
306 break;
308 case 2: /* no '/' at start */
309 s = strchr (fptr, '/');
310 if (s == 0) /* no '/' (16) */
312 if (type == 1)
314 strcpy (vptr, "[.");
315 vptr += 2;
317 copyto (&vptr, &fptr, 0, (type==1));
318 if (type == 1)
319 *vptr++ = ']';
320 state = -1;
322 else /* found '/' (17..21) */
324 if ((type == 2)
325 && (*(s+1) == 0)) /* 17(2) */
327 copyto (&vptr, &fptr, '/', 1);
328 state = 7;
330 else
332 strcpy (vptr, "[.");
333 vptr += 2;
334 copyto (&vptr, &fptr, '/', 1);
335 nstate = N_OPEN;
336 state = 9;
339 break;
341 case 3: /* '//' at start */
342 while (*fptr == '/') /* collapse all '/' */
343 fptr++;
344 if (*fptr == 0) /* just // */
346 char cwdbuf[MAXPATHLEN+1];
348 s1 = getcwd(cwdbuf, MAXPATHLEN);
349 if (s1 == 0)
351 return ""; /* FIXME, err getcwd */
353 s = strchr (s1, ':');
354 if (s == 0)
356 return ""; /* FIXME, err no device */
358 strncpy (vptr, s1, s-s1+1);
359 vptr += s-s1+1;
360 state = -1;
361 break;
364 s = vptr;
366 if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
368 *vptr++ = ':';
369 state = -1;
370 break;
372 *vptr = ':';
373 nstate = N_DEVICE;
374 if (*fptr == 0) /* just '//a/' */
376 strcpy (vptr+1, "[000000]");
377 vptr += 9;
378 state = -1;
379 break;
381 *vptr = 0;
382 /* check logical for [000000] insertion */
383 s1 = trnlog (s);
384 if (*s1 != 0)
385 { /* found translation */
386 char *s2;
387 for (;;) /* loop over all nested logicals */
389 s2 = s1 + strlen (s1) - 1;
390 if (*s2 == ':') /* translation ends in ':' */
392 s2 = trnlog (s1);
393 free (s1);
394 if (*s2 == 0)
396 rooted = 0;
397 break;
399 s1 = s2;
400 continue; /* next iteration */
402 if (*s2 == ']') /* translation ends in ']' */
404 if (*(s2-1) == '.') /* ends in '.]' */
406 if (!strneq (fptr, "000000", 6))
407 rooted = 0;
409 else
411 strcpy (vmsname, s1);
412 s = strchr (vmsname, ']');
413 *s = '.';
414 nstate = N_DOT;
415 vptr = s;
418 break;
420 free (s1);
422 else
423 rooted = 0;
425 if (*vptr == 0)
427 nstate = N_DEVICE;
428 *vptr++ = ':';
430 else
431 vptr++;
433 if (rooted == 0)
435 strcpy (vptr, "[000000.");
436 vptr += 8;
437 s1 = vptr-1;
438 nstate = N_DOT;
440 else
441 s1 = 0;
443 /* s1-> '.' after 000000 or NULL */
445 s = strchr (fptr, '/');
446 if (s == 0)
447 { /* no next '/' */
448 if (*(vptr-1) == '.')
449 *(vptr-1) = ']';
450 else if (rooted == 0)
451 *vptr++ = ']';
452 copyto (&vptr, &fptr, 0, (type == 1));
453 state = -1;
454 break;
456 else
458 while (*(s+1) == '/') /* skip multiple '/' */
459 s++;
462 if ((rooted != 0)
463 && (*(vptr-1) != '.'))
465 *vptr++ = '[';
466 nstate = N_DOT;
468 else
469 if ((nstate == N_DOT)
470 && (s1 != 0)
471 && (*(s+1) == 0))
473 if (type == 2)
475 *s1 = ']';
476 nstate = N_CLOSED;
479 state = 9;
480 break;
482 case 4: /* single '/' at start (9..15) */
483 if (*fptr == 0)
484 state = 5;
485 else
486 state = 6;
487 break;
489 case 5: /* just '/' at start (9) */
490 if (type != 2)
492 *vptr++ = '[';
493 nstate = N_OPEN;
495 strcpy (vptr, "000000");
496 vptr += 6;
497 if (type == 2)
498 state = 7;
499 else
500 state = 8;
501 break;
503 case 6: /* chars following '/' at start 10..15 */
504 *vptr++ = '[';
505 nstate = N_OPEN;
506 s = strchr (fptr, '/');
507 if (s == 0) /* 10 */
509 if (type != 1)
511 strcpy (vptr, "000000]");
512 vptr += 7;
514 copyto (&vptr, &fptr, 0, (type == 1));
515 if (type == 1)
517 *vptr++ = ']';
519 state = -1;
521 else /* 11..15 */
523 if ( (type == 2)
524 && (*(s+1) == 0)) /* 11(2) */
526 strcpy (vptr, "000000]");
527 nstate = N_CLOSED;
528 vptr += 7;
530 copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
531 state = 9;
533 break;
535 case 7: /* add '.dir' and exit */
536 if ((nstate == N_OPEN)
537 || (nstate == N_DOT))
539 s = vptr-1;
540 while (s > vmsname)
542 if (*s == ']')
544 break;
546 if (*s == '.')
548 *s = ']';
549 break;
551 s--;
554 strcpy (vptr, ".dir");
555 vptr += 4;
556 state = -1;
557 break;
559 case 8: /* add ']' and exit */
560 *vptr++ = ']';
561 state = -1;
562 break;
564 case 9: /* 17..21, fptr -> 1st '/' + 1 */
565 if (*fptr == 0)
567 if (type == 2)
569 state = 7;
571 else
572 state = 8;
573 break;
575 s = strchr (fptr, '/');
576 if (s == 0)
578 if (type != 1)
580 if (nstate == N_OPEN)
582 *vptr++ = ']';
583 nstate = N_CLOSED;
585 as_dir = 0;
587 else
589 if (nstate == N_OPEN)
591 *vptr++ = '.';
592 nstate = N_DOT;
594 as_dir = 1;
597 else
599 while (*(s+1) == '/')
600 s++;
601 if ( (type == 2)
602 && (*(s+1) == 0)) /* 19(2), 21(2)*/
604 if (nstate != N_CLOSED)
606 *vptr++ = ']';
607 nstate = N_CLOSED;
609 as_dir = 1;
611 else
613 if (nstate == N_OPEN)
615 *vptr++ = '.';
616 nstate = N_DOT;
618 as_dir = 1;
621 if ( (*fptr == '.') /* check for '..' or '../' */
622 && (*(fptr+1) == '.')
623 && ((*(fptr+2) == '/')
624 || (*(fptr+2) == 0)) )
626 fptr += 2;
627 if (*fptr == '/')
631 fptr++;
633 while (*fptr == '/');
635 else if (*fptr == 0)
636 type = 1;
637 vptr--; /* vptr -> '.' or ']' */
638 s1 = vptr;
639 for (;;)
641 s1--;
642 if (*s1 == '.') /* one back */
644 vptr = s1;
645 nstate = N_OPEN;
646 break;
648 if (*s1 == '[') /* top level reached */
650 if (*fptr == 0)
652 strcpy (s1, "[000000]");
653 vptr = s1 + 8;
654 nstate = N_CLOSED;
655 s = 0;
656 break;
658 else
660 vptr = s1+1;
661 nstate = N_OPEN;
662 break;
667 else
669 copyto (&vptr, &fptr, '/', as_dir);
670 if (nstate == N_DOT)
671 nstate = N_OPEN;
673 if (s == 0)
674 { /* 18,20 */
675 if (type == 1)
676 *vptr++ = ']';
677 state = -1;
679 else
681 if (*(s+1) == 0)
683 if (type == 2) /* 19,21 */
685 state = 7;
687 else
689 *vptr++ = ']';
690 state = -1;
694 break;
696 case 10: /* 1,2 first is '.' */
697 if (*fptr == '.')
699 fptr++;
700 state = 11;
702 else
703 state = 12;
704 break;
706 case 11: /* 2, '..' at start */
707 count = 1;
708 if (*fptr != 0)
710 if (*fptr != '/') /* got ..xxx */
712 return name;
714 do /* got ../ */
716 fptr++;
717 while (*fptr == '/') fptr++;
718 if (*fptr != '.')
719 break;
720 if (*(fptr+1) != '.')
721 break;
722 fptr += 2;
723 if ((*fptr == 0)
724 || (*fptr == '/'))
725 count++;
727 while (*fptr == '/');
729 { /* got '..' or '../' */
730 nstate = N_OPEN;
731 *vptr++ = '[';
732 while (count--)
733 *vptr++ = '-';
735 if (*fptr == 0) /* had '..' or '../' */
737 *vptr++ = ']';
738 state = -1;
740 else /* had '../xxx' */
742 state = 9;
744 *vptr = 0;
746 break;
748 case 12: /* 1, '.' at start */
749 if (*fptr != 0)
751 if (*fptr != '/')
753 return name;
755 fptr++;
758 if (*fptr)
760 state = 9;
762 switch (type)
764 case 0:
765 nstate = N_CLOSED;
766 *vptr++ = '[';
767 *vptr++ = ']';
768 break;
770 case 1:
771 nstate = N_OPEN;
772 *vptr++ = '[';
773 break;
775 case 2:
776 nstate = N_CLOSED;
777 break;
780 else
782 if (type == 1)
784 *vptr++ = '[';
785 *vptr++ = ']';
786 state = -1;
788 else
790 char cwdbuf[MAXPATHLEN+1];
792 s1 = getcwd(cwdbuf, MAXPATHLEN);
793 if (s1 == 0)
795 return "foo"; /*FIXME, err getcwd */
797 strcpy (vptr, s1);
798 vptr += strlen (vptr);
800 if (type == 2)
802 s = vptr;
803 while (s > vmsname)
805 if (*s == '.')
807 *s = ']';
808 vptr--;
809 break;
812 if (*s == '[')
814 int i;
815 char *t = vptr - 2;
816 while (t > s)
818 *(t+7) = *t;
819 t--;
821 s++;
822 for (i = 0; i < 6; i++)
823 *s++ = '0';
824 *s = ']';
825 vptr += 6;
826 break;
828 s--;
831 strcpy (vptr, ".dir");
832 vptr += 4;
835 state = -1;
838 break;
842 while (state > 0);
848 /* directory conversion done
849 fptr -> filename part of input string
850 vptr -> free space in vmsname
853 *vptr++ = 0;
855 return vmsname;
861 convert from vms-style to unix-style
863 dev:[dir1.dir2] //dev/dir1/dir2/
866 char *
867 unixify (char *name)
869 static char piece[512];
870 char *s, *p;
872 if (strchr (name, '/') != 0) /* already in unix style */
873 return name;
875 p = piece;
876 *p = 0;
878 /* device part */
880 s = strchr (name, ':');
882 if (s != 0)
884 *s = 0;
885 *p++ = '/';
886 *p++ = '/';
887 strcpy (p, name);
888 p += strlen (p);
889 *s = ':';
892 /* directory part */
894 *p++ = '/';
895 s = strchr (name, '[');
897 if (s != 0)
899 s++;
900 switch (*s)
902 case ']': /* [] */
903 strcat (p, "./");
904 break;
905 case '-': /* [- */
906 strcat (p, "../");
907 break;
908 case '.':
909 strcat (p, "./"); /* [. */
910 break;
911 default:
912 s--;
913 break;
915 s++;
916 while (*s)
918 if (*s == '.')
919 *p++ = '/';
920 else
921 *p++ = *s;
922 s++;
923 if (*s == ']')
925 s++;
926 break;
929 if (*s != 0) /* more after ']' ?? */
931 if (*(p-1) != '/')
932 *p++ = '/';
933 strcpy (p, s); /* copy it anyway */
937 else /* no '[' anywhere */
940 *p++ = 0;
943 /* force end with '/' */
945 if (*(p-1) != '/')
946 *p++ = '/';
947 *p = 0;
949 return piece;
952 /* EOF */