* Lots of bug fixes and cleanup; new i18n files, etc.
[make.git] / vmsify.c
blobf7871bb2fdd0a21da3fe1218c646f08f5ade5a59
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 <stdio.h>
12 #include <string.h>
13 #include <ctype.h>
15 #if VMS
16 #include <unixlib.h>
17 #include <stdlib.h>
18 #include <jpidef.h>
19 #include <descrip.h>
20 #include <uaidef.h>
21 #include <ssdef.h>
22 #include <starlet.h>
23 #include <lib$routines.h>
24 /* Initialize a string descriptor (struct dsc$descriptor_s) for an
25 arbitrary string. ADDR is a pointer to the first character
26 of the string, and LEN is the length of the string. */
28 #define INIT_DSC_S(dsc, addr, len) do { \
29 (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \
30 (dsc).dsc$b_class = DSC$K_CLASS_S; \
31 (dsc).dsc$w_length = (len); \
32 (dsc).dsc$a_pointer = (addr); \
33 } while (0)
35 /* Initialize a string descriptor (struct dsc$descriptor_s) for a
36 NUL-terminated string. S is a pointer to the string; the length
37 is determined by calling strlen(). */
39 #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
40 #endif
43 copy 'from' to 'to' up to but not including 'upto'
44 return 0 if eos on from
45 return 1 if upto found
47 return 'to' at last char + 1
48 return 'from' at match + 1 or eos if no match
50 if as_dir == 1, change all '.' to '_'
51 else change all '.' but the last to '_'
54 static int
55 copyto (char **to, char **from, char upto, int as_dir)
57 char *s;
59 s = strrchr (*from, '.');
61 while (**from)
63 if (**from == upto)
67 (*from)++;
69 while (**from == upto);
70 return 1;
72 if (**from == '.')
74 if ((as_dir == 1)
75 || (*from != s))
76 **to = '_';
77 else
78 **to = '.';
80 else
82 if (isupper ((unsigned char)**from))
83 **to = tolower ((unsigned char)**from);
84 else
85 **to = **from;
87 (*to)++;
88 (*from)++;
91 return 0;
96 get translation of logical name
100 static char *
101 trnlog (char *name)
103 int stat;
104 static char reslt[1024];
105 $DESCRIPTOR (reslt_dsc, reslt);
106 short resltlen;
107 struct dsc$descriptor_s name_dsc;
108 char *s;
110 INIT_DSC_CSTRING (name_dsc, name);
112 stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
114 if ((stat&1) == 0)
116 return "";
118 if (stat == SS$_NOTRAN)
120 return "";
122 reslt[resltlen] = '\0';
124 s = (char *)malloc (resltlen+1);
125 if (s == 0)
126 return "";
127 strcpy (s, reslt);
128 return s;
131 static char *
132 showall (char *s)
134 static char t[512];
135 char *pt;
137 pt = t;
138 if (strchr (s, '\\') == 0)
139 return s;
140 while (*s)
142 if (*s == '\\')
144 *pt++ = *s;
146 *pt++ = *s++;
148 return pt;
152 enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
155 convert unix style name to vms style
156 type = 0 -> name is a full name (directory and filename part)
157 type = 1 -> name is a directory
158 type = 2 -> name is a filename without directory
160 The following conversions are applied
161 (0) (1) (2)
162 input full name dir name file name
164 1 ./ <cwd> [] <current directory>.dir
165 2 ../ <home of cwd> <home of cwd> <home of cwd>.dir
167 3 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir
168 4 //a a: a: a:
169 5 //a/ a: a: a:000000.dir
171 9 / [000000] [000000] 000000.dir
172 10 /a [000000]a [a] [000000]a
173 11 /a/ [a] [a] [000000]a.dir
174 12 /a/b [a]b [a.b] [a]b
175 13 /a/b/ [a.b] [a.b] [a]b.dir
176 14 /a/b/c [a.b]c [a.b.c] [a.b]c
177 15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir
179 16 a a [.a] a
180 17 a/ [.a] [.a] a.dir
181 18 a/b [.a]b [.a.b] [.a]b
182 19 a/b/ [.a.b] [.a.b] [.a]b.dir
183 20 a/b/c [.a.b]c [.a.b.c] [.a.b]c
184 21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir
186 22 a.b.c a_b.c [.a_b_c] a_b_c.dir
188 23 [x][y]z [x.y]z [x.y]z [x.y]z
189 24 [x][.y]z [x.y]z [x.y]z [x.y]z
191 25 filenames with '$' are left unchanged if they contain no '/'
192 25 filenames with ':' are left unchanged
193 26 filenames with a single pair of '[' ']' are left unchanged
195 the input string is not written to
198 char *
199 vmsify (name, type)
200 char *name;
201 int type;
203 /* max 255 device
204 max 39 directory
205 max 39 filename
206 max 39 filetype
207 max 5 version
209 #define MAXPATHLEN 512
211 enum namestate nstate;
212 static char vmsname[MAXPATHLEN+1];
213 char *fptr;
214 char *vptr;
215 char *s,*s1;
216 int as_dir;
217 int count;
219 if (name == 0)
220 return 0;
221 fptr = name;
222 vptr = vmsname;
223 nstate = N_START;
225 /* case 25a */
227 s = strpbrk (name, "$:");
228 if (s != 0)
230 char *s1;
231 char *s2;
233 if (type == 1)
235 s1 = strchr (s+1, '[');
236 s2 = strchr (s+1, ']');
239 if (*s == '$')
241 if (strchr (name, '/') == 0)
243 if ((type == 1) && (s1 != 0) && (s2 == 0))
245 strcpy (vmsname, name);
246 strcat (vmsname, "]");
247 return vmsname;
249 else
250 return name;
253 else
255 if ((type == 1) && (s1 != 0) && (s2 == 0))
257 strcpy (vmsname, name);
258 strcat (vmsname, "]");
259 return vmsname;
261 else
262 return name;
266 /* case 26 */
268 s = strchr (name, '[');
270 if (s != 0)
272 s1 = strchr (s+1, '[');
273 if (s1 == 0)
275 if ((type == 1)
276 && (strchr (s+1, ']') == 0))
278 strcpy (vmsname, name);
279 strcat (vmsname, "]");
280 return vmsname;
282 else
283 return name; /* single [, keep unchanged */
285 s1--;
286 if (*s1 != ']')
288 return name; /* not ][, keep unchanged */
291 /* we have ][ */
293 s = name;
295 /* s -> starting char
296 s1 -> ending ']' */
300 strncpy (vptr, s, s1-s); /* copy up to but not including ']' */
301 vptr += s1-s;
302 if (*s1 == 0)
303 break;
304 s = s1 + 1; /* s -> char behind ']' */
305 if (*s != '[') /* was '][' ? */
306 break; /* no, last ] found, exit */
307 s++;
308 if (*s != '.')
309 *vptr++ = '.';
310 s1 = strchr (s, ']');
311 if (s1 == 0) /* no closing ] */
312 s1 = s + strlen (s);
314 while (1);
316 *vptr++ = ']';
318 fptr = s;
322 else /* no [ in name */
326 int state;
327 int rooted = 1; /* flag if logical is rooted, else insert [000000] */
329 state = 0;
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 */
362 s = strchr (fptr, '/');
363 if (s == 0) /* no '/' (16) */
365 if (type == 1)
367 strcpy (vptr, "[.");
368 vptr += 2;
370 copyto (&vptr, &fptr, 0, (type==1));
371 if (type == 1)
372 *vptr++ = ']';
373 state = -1;
375 else /* found '/' (17..21) */
377 if ((type == 2)
378 && (*(s+1) == 0)) /* 17(2) */
380 copyto (&vptr, &fptr, '/', 1);
381 state = 7;
383 else
385 strcpy (vptr, "[.");
386 vptr += 2;
387 copyto (&vptr, &fptr, '/', 1);
388 nstate = N_OPEN;
389 state = 9;
392 break;
394 case 3: /* '//' at start */
395 while (*fptr == '/') /* collapse all '/' */
396 fptr++;
397 if (*fptr == 0) /* just // */
399 char cwdbuf[MAXPATHLEN+1];
401 s1 = getcwd(cwdbuf, MAXPATHLEN);
402 if (s1 == 0)
404 return ""; /* FIXME, err getcwd */
406 s = strchr (s1, ':');
407 if (s == 0)
409 return ""; /* FIXME, err no device */
411 strncpy (vptr, s1, s-s1+1);
412 vptr += s-s1+1;
413 state = -1;
414 break;
417 s = vptr;
419 if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
421 *vptr++ = ':';
422 state = -1;
423 break;
425 *vptr = ':';
426 nstate = N_DEVICE;
427 if (*fptr == 0) /* just '//a/' */
429 strcpy (vptr+1, "[000000]");
430 vptr += 9;
431 state = -1;
432 break;
434 *vptr = 0;
435 /* check logical for [000000] insertion */
436 s1 = trnlog (s);
437 if (*s1 != 0)
438 { /* found translation */
439 char *s2;
440 for (;;) /* loop over all nested logicals */
442 s2 = s1 + strlen (s1) - 1;
443 if (*s2 == ':') /* translation ends in ':' */
445 s2 = trnlog (s1);
446 free (s1);
447 if (*s2 == 0)
449 rooted = 0;
450 break;
452 s1 = s2;
453 continue; /* next iteration */
455 if (*s2 == ']') /* translation ends in ']' */
457 if (*(s2-1) == '.') /* ends in '.]' */
459 if (strncmp (fptr, "000000", 6) != 0)
460 rooted = 0;
462 else
464 strcpy (vmsname, s1);
465 s = strchr (vmsname, ']');
466 *s = '.';
467 nstate = N_DOT;
468 vptr = s;
471 break;
473 free (s1);
475 else
476 rooted = 0;
478 if (*vptr == 0)
480 nstate = N_DEVICE;
481 *vptr++ = ':';
483 else
484 vptr++;
486 if (rooted == 0)
488 strcpy (vptr, "[000000.");
489 vptr += 8;
490 s1 = vptr-1;
491 nstate = N_DOT;
493 else
494 s1 = 0;
496 /* s1-> '.' after 000000 or NULL */
498 s = strchr (fptr, '/');
499 if (s == 0)
500 { /* no next '/' */
501 if (*(vptr-1) == '.')
502 *(vptr-1) = ']';
503 else if (rooted == 0)
504 *vptr++ = ']';
505 copyto (&vptr, &fptr, 0, (type == 1));
506 state = -1;
507 break;
509 else
511 while (*(s+1) == '/') /* skip multiple '/' */
512 s++;
515 if ((rooted != 0)
516 && (*(vptr-1) != '.'))
518 *vptr++ = '[';
519 nstate = N_DOT;
521 else
522 if ((nstate == N_DOT)
523 && (s1 != 0)
524 && (*(s+1) == 0))
526 if (type == 2)
528 *s1 = ']';
529 nstate = N_CLOSED;
532 state = 9;
533 break;
535 case 4: /* single '/' at start (9..15) */
536 if (*fptr == 0)
537 state = 5;
538 else
539 state = 6;
540 break;
542 case 5: /* just '/' at start (9) */
543 if (type != 2)
545 *vptr++ = '[';
546 nstate = N_OPEN;
548 strcpy (vptr, "000000");
549 vptr += 6;
550 if (type == 2)
551 state = 7;
552 else
553 state = 8;
554 break;
556 case 6: /* chars following '/' at start 10..15 */
557 *vptr++ = '[';
558 nstate = N_OPEN;
559 s = strchr (fptr, '/');
560 if (s == 0) /* 10 */
562 if (type != 1)
564 strcpy (vptr, "000000]");
565 vptr += 7;
567 copyto (&vptr, &fptr, 0, (type == 1));
568 if (type == 1)
570 *vptr++ = ']';
572 state = -1;
574 else /* 11..15 */
576 if ( (type == 2)
577 && (*(s+1) == 0)) /* 11(2) */
579 strcpy (vptr, "000000]");
580 nstate = N_CLOSED;
581 vptr += 7;
583 copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
584 state = 9;
586 break;
588 case 7: /* add '.dir' and exit */
589 if ((nstate == N_OPEN)
590 || (nstate == N_DOT))
592 s = vptr-1;
593 while (s > vmsname)
595 if (*s == ']')
597 break;
599 if (*s == '.')
601 *s = ']';
602 break;
604 s--;
607 strcpy (vptr, ".dir");
608 vptr += 4;
609 state = -1;
610 break;
612 case 8: /* add ']' and exit */
613 *vptr++ = ']';
614 state = -1;
615 break;
617 case 9: /* 17..21, fptr -> 1st '/' + 1 */
618 if (*fptr == 0)
620 if (type == 2)
622 state = 7;
624 else
625 state = 8;
626 break;
628 s = strchr (fptr, '/');
629 if (s == 0)
631 if (type != 1)
633 if (nstate == N_OPEN)
635 *vptr++ = ']';
636 nstate = N_CLOSED;
638 as_dir = 0;
640 else
642 if (nstate == N_OPEN)
644 *vptr++ = '.';
645 nstate = N_DOT;
647 as_dir = 1;
650 else
652 while (*(s+1) == '/')
653 s++;
654 if ( (type == 2)
655 && (*(s+1) == 0)) /* 19(2), 21(2)*/
657 if (nstate != N_CLOSED)
659 *vptr++ = ']';
660 nstate = N_CLOSED;
662 as_dir = 1;
664 else
666 if (nstate == N_OPEN)
668 *vptr++ = '.';
669 nstate = N_DOT;
671 as_dir = 1;
674 if ( (*fptr == '.') /* check for '..' or '../' */
675 && (*(fptr+1) == '.')
676 && ((*(fptr+2) == '/')
677 || (*(fptr+2) == 0)) )
679 fptr += 2;
680 if (*fptr == '/')
684 fptr++;
686 while (*fptr == '/');
688 else if (*fptr == 0)
689 type = 1;
690 vptr--; /* vptr -> '.' or ']' */
691 s1 = vptr;
692 for (;;)
694 s1--;
695 if (*s1 == '.') /* one back */
697 vptr = s1;
698 nstate = N_OPEN;
699 break;
701 if (*s1 == '[') /* top level reached */
703 if (*fptr == 0)
705 strcpy (s1, "[000000]");
706 vptr = s1 + 8;
707 nstate = N_CLOSED;
708 s = 0;
709 break;
711 else
713 vptr = s1+1;
714 nstate = N_OPEN;
715 break;
720 else
722 copyto (&vptr, &fptr, '/', as_dir);
723 if (nstate == N_DOT)
724 nstate = N_OPEN;
726 if (s == 0)
727 { /* 18,20 */
728 if (type == 1)
729 *vptr++ = ']';
730 state = -1;
732 else
734 if (*(s+1) == 0)
736 if (type == 2) /* 19,21 */
738 state = 7;
740 else
742 *vptr++ = ']';
743 state = -1;
747 break;
749 case 10: /* 1,2 first is '.' */
750 if (*fptr == '.')
752 fptr++;
753 state = 11;
755 else
756 state = 12;
757 break;
759 case 11: /* 2, '..' at start */
760 count = 1;
761 if (*fptr != 0)
763 if (*fptr != '/') /* got ..xxx */
765 return name;
767 do /* got ../ */
769 fptr++;
770 while (*fptr == '/') fptr++;
771 if (*fptr != '.')
772 break;
773 if (*(fptr+1) != '.')
774 break;
775 fptr += 2;
776 if ((*fptr == 0)
777 || (*fptr == '/'))
778 count++;
780 while (*fptr == '/');
782 { /* got '..' or '../' */
783 char cwdbuf[MAXPATHLEN+1];
785 s1 = getcwd(cwdbuf, MAXPATHLEN);
786 if (s1 == 0)
788 return ""; /* FIXME, err getcwd */
790 strcpy (vptr, s1);
791 s = strchr (vptr, ']');
792 if (s != 0)
794 nstate = N_OPEN;
795 while (s > vptr)
797 s--;
798 if (*s == '[')
800 s++;
801 strcpy (s, "000000]");
802 state = -1;
803 break;
805 else if (*s == '.')
807 if (--count == 0)
809 if (*fptr == 0) /* had '..' or '../' */
811 *s++ = ']';
812 state = -1;
814 else /* had '../xxx' */
816 state = 9;
818 *s = 0;
819 break;
824 vptr += strlen (vptr);
826 break;
828 case 12: /* 1, '.' at start */
829 if (*fptr != 0)
831 if (*fptr != '/')
833 return name;
835 while (*fptr == '/')
836 fptr++;
840 char cwdbuf[MAXPATHLEN+1];
842 s1 = getcwd(cwdbuf, MAXPATHLEN);
843 if (s1 == 0)
845 return ""; /*FIXME, err getcwd */
847 strcpy (vptr, s1);
848 if (*fptr == 0)
850 state = -1;
851 break;
853 else
855 s = strchr (vptr, ']');
856 if (s == 0)
858 state = -1;
859 break;
861 *s = 0;
862 nstate = N_OPEN;
863 vptr += strlen (vptr);
864 state = 9;
867 break;
871 while (state > 0);
877 /* directory conversion done
878 fptr -> filename part of input string
879 vptr -> free space in vmsname
882 *vptr++ = 0;
884 return vmsname;
890 convert from vms-style to unix-style
892 dev:[dir1.dir2] //dev/dir1/dir2/
895 char *
896 unixify (char *name)
898 static char piece[512];
899 char *s, *p;
901 if (strchr (name, '/') != 0) /* already in unix style */
902 return name;
904 p = piece;
905 *p = 0;
907 /* device part */
909 s = strchr (name, ':');
911 if (s != 0)
913 *s = 0;
914 *p++ = '/';
915 *p++ = '/';
916 strcpy (p, name);
917 p += strlen (p);
918 *s = ':';
921 /* directory part */
923 *p++ = '/';
924 s = strchr (name, '[');
926 if (s != 0)
928 s++;
929 switch (*s)
931 case ']': /* [] */
932 strcat (p, "./");
933 break;
934 case '-': /* [- */
935 strcat (p, "../");
936 break;
937 case '.':
938 strcat (p, "./"); /* [. */
939 break;
940 default:
941 s--;
942 break;
944 s++;
945 while (*s)
947 if (*s == '.')
948 *p++ = '/';
949 else
950 *p++ = *s;
951 s++;
952 if (*s == ']')
954 s++;
955 break;
958 if (*s != 0) /* more after ']' ?? */
960 if (*(p-1) != '/')
961 *p++ = '/';
962 strcpy (p, s); /* copy it anyway */
966 else /* no '[' anywhere */
969 *p++ = 0;
972 /* force end with '/' */
974 if (*(p-1) != '/')
975 *p++ = '/';
976 *p = 0;
978 return piece;
981 /* EOF */