Note "sinclude".
[make.git] / vmsify.c
blob7d1fa6f185eee9f8d2b4f049ad2be5712abb17fd
1 /*
2 vmsify.c
4 Module for vms <-> unix file name conversion
6 Written by Klaus Kämpf (kkaempf@didymus.rmi.de)
8 */
10 #include <string.h>
11 #include <ctype.h>
13 #if VMS
14 #include <unixlib.h>
15 #include <stdlib.h>
16 #include <jpidef.h>
17 #include <descrip.h>
18 #include <uaidef.h>
19 #include <ssdef.h>
20 #include <starlet.h>
21 #include <lib$routines.h>
22 /* Initialize a string descriptor (struct dsc$descriptor_s) for an
23 arbitrary string. ADDR is a pointer to the first character
24 of the string, and LEN is the length of the string. */
26 #define INIT_DSC_S(dsc, addr, len) do { \
27 (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \
28 (dsc).dsc$b_class = DSC$K_CLASS_S; \
29 (dsc).dsc$w_length = (len); \
30 (dsc).dsc$a_pointer = (addr); \
31 } while (0)
33 /* Initialize a string descriptor (struct dsc$descriptor_s) for a
34 NUL-terminated string. S is a pointer to the string; the length
35 is determined by calling strlen(). */
37 #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
38 #endif
41 copy 'from' to 'to' up to but not including 'upto'
42 return 0 if eos on from
43 return 1 if upto found
45 return 'to' at last char + 1
46 return 'from' at match + 1 or eos if no match
48 if as_dir == 1, change all '.' to '_'
49 else change all '.' but the last to '_'
52 static int
53 copyto (char **to, char **from, char upto, int as_dir)
55 char *s;
57 s = strrchr (*from, '.');
59 while (**from)
61 if (**from == upto)
65 (*from)++;
67 while (**from == upto);
68 return 1;
70 if (**from == '.')
72 if ((as_dir == 1)
73 || (*from != s))
74 **to = '_';
75 else
76 **to = '.';
78 else
80 if (islower (**from))
81 **to = toupper (**from);
82 else
83 **to = **from;
85 (*to)++;
86 (*from)++;
89 return 0;
94 get translation of logical name
98 static char *
99 trnlog (char *name)
101 int stat;
102 static char reslt[1024];
103 $DESCRIPTOR (reslt_dsc, reslt);
104 short resltlen;
105 struct dsc$descriptor_s name_dsc;
106 char *s;
108 INIT_DSC_CSTRING (name_dsc, name);
110 stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
112 if ((stat&1) == 0)
114 return "";
116 if (stat == SS$_NOTRAN)
118 return "";
120 reslt[resltlen] = '\0';
122 s = (char *)malloc (resltlen+1);
123 if (s == 0)
124 return "";
125 strcpy (s, reslt);
126 return s;
129 enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
132 convert unix style name to vms style
133 type = 0 -> name is a full name (directory and filename part)
134 type = 1 -> name is a directory
135 type = 2 -> name is a filename without directory
137 The following conversions are applied
138 (0) (1) (2)
139 input full name dir name file name
141 1 ./ <cwd> [] <current directory>.dir
142 2 ../ <home of cwd> <home of cwd> <home of cwd>.dir
144 3 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir
145 4 //a a: a: a:
146 5 //a/ a: a: a:000000.dir
148 9 / [000000] [000000] 000000.dir
149 10 /a [000000]a [a] [000000]a
150 11 /a/ [a] [a] [000000]a.dir
151 12 /a/b [a]b [a.b] [a]b
152 13 /a/b/ [a.b] [a.b] [a]b.dir
153 14 /a/b/c [a.b]c [a.b.c] [a.b]c
154 15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir
156 16 a a [.a] a
157 17 a/ [.a] [.a] a.dir
158 18 a/b [.a]b [.a.b] [.a]b
159 19 a/b/ [.a.b] [.a.b] [.a]b.dir
160 20 a/b/c [.a.b]c [.a.b.c] [.a.b]c
161 21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir
163 22 a.b.c a_b.c [.a_b_c] a_b_c.dir
165 23 [x][y]z [x.y]z [x.y]z [x.y]z
166 24 [x][.y]z [x.y]z [x.y]z [x.y]z
168 25 filenames with '$' are left unchanged if they contain no '/'
169 25 filenames with ':' are left unchanged
170 26 filenames with a single pair of '[' ']' are left unchanged
172 the input string is not written to
175 char *
176 vmsify (name, type)
177 char *name;
178 int type;
180 /* max 255 device
181 max 39 directory
182 max 39 filename
183 max 39 filetype
184 max 5 version
186 #define MAXPATHLEN 512
188 enum namestate nstate;
189 static char vmsname[MAXPATHLEN+1];
190 char *fptr;
191 char *vptr;
192 char *s,*s1;
193 int as_dir;
194 int count;
196 if (name == 0)
197 return 0;
198 fptr = name;
199 vptr = vmsname;
200 nstate = N_START;
202 /* case 25a */
204 s = strpbrk (name, "$:");
205 if (s != 0)
207 if (*s == '$')
209 if (strchr (name, '/') == 0)
211 return name;
214 else
216 return name;
220 /* case 26 */
222 s = strchr (name, '[');
224 if (s != 0)
226 s1 = strchr (s+1, '[');
227 if (s1 == 0)
229 return name; /* single [, keep unchanged */
231 s1--;
232 if (*s1 != ']')
234 return name; /* not ][, keep unchanged */
237 /* we have ][ */
239 s = name;
241 /* s -> starting char
242 s1 -> ending ']' */
246 strncpy (vptr, s, s1-s); /* copy up to but not including ']' */
247 vptr += s1-s;
248 if (*s1 == 0)
249 break;
250 s = s1 + 1; /* s -> char behind ']' */
251 if (*s != '[') /* was '][' ? */
252 break; /* no, last ] found, exit */
253 s++;
254 if (*s != '.')
255 *vptr++ = '.';
256 s1 = strchr (s, ']');
257 if (s1 == 0) /* no closing ] */
258 s1 = s + strlen (s);
260 while (1);
262 *vptr++ = ']';
264 fptr = s;
268 else /* no [ in name */
272 int state;
273 int rooted = 1; /* flag if logical is rooted, else insert [000000] */
275 state = 0;
280 switch (state)
282 case 0: /* start of loop */
283 if (*fptr == '/')
285 fptr++;
286 state = 1;
288 else if (*fptr == '.')
290 fptr++;
291 state = 10;
293 else
294 state = 2;
295 break;
297 case 1: /* '/' at start */
298 if (*fptr == '/')
300 fptr++;
301 state = 3;
303 else
304 state = 4;
305 break;
307 case 2: /* no '/' at start */
308 s = strchr (fptr, '/');
309 if (s == 0) /* no '/' (16) */
311 if (type == 1)
313 strcpy (vptr, "[.");
314 vptr += 2;
316 copyto (&vptr, &fptr, 0, (type==1));
317 if (type == 1)
318 *vptr++ = ']';
319 state = -1;
321 else /* found '/' (17..21) */
323 if ((type == 2)
324 && (*(s+1) == 0)) /* 17(2) */
326 copyto (&vptr, &fptr, '/', 1);
327 state = 7;
329 else
331 strcpy (vptr, "[.");
332 nstate = N_DOT;
333 vptr += 2;
334 copyto (&vptr, &fptr, '/', 1);
335 state = 9;
338 break;
340 case 3: /* '//' at start */
341 while (*fptr == '/') /* collapse all '/' */
342 fptr++;
343 if (*fptr == 0) /* just // */
345 char cwdbuf[MAXPATHLEN+1];
347 s1 = getcwd(cwdbuf, MAXPATHLEN);
348 if (s1 == 0)
350 return ""; /* FIXME, err getcwd */
352 s = strchr (s1, ':');
353 if (s == 0)
355 return ""; /* FIXME, err no device */
357 strncpy (vptr, s1, s-s1+1);
358 vptr += s-s1+1;
359 state = -1;
360 break;
363 s = vptr;
365 if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
367 *vptr++ = ':';
368 state = -1;
369 break;
371 *vptr = ':';
372 nstate = N_DEVICE;
373 if (*fptr == 0) /* just '//a/' */
375 strcpy (vptr+1, "[000000]");
376 vptr += 9;
377 state = -1;
378 break;
380 *vptr = 0;
381 /* check logical for [000000] insertion */
382 s1 = trnlog (s);
383 if (*s1 != 0)
384 { /* found translation */
385 char *s2;
386 for (;;) /* loop over all nested logicals */
388 s2 = s1 + strlen (s1) - 1;
389 if (*s2 == ':') /* translation ends in ':' */
391 s2 = trnlog (s1);
392 free (s1);
393 if (*s2 == 0)
395 rooted = 0;
396 break;
398 s1 = s2;
399 continue; /* next iteration */
401 if (*s2 == ']') /* translation ends in ']' */
403 if (*(s2-1) == '.') /* ends in '.]' */
405 if (strncmp (fptr, "000000", 6) != 0)
406 rooted = 0;
408 else
410 strcpy (vmsname, s1);
411 s = strchr (vmsname, ']');
412 *s = '.';
413 nstate = N_DOT;
414 vptr = s;
417 break;
419 free (s1);
421 else
422 rooted = 0;
424 if (*vptr == 0)
426 nstate = N_DEVICE;
427 *vptr++ = ':';
429 else
430 vptr++;
432 if (rooted == 0)
434 strcpy (vptr, "[000000.");
435 vptr += 8;
436 s1 = vptr-1;
437 nstate = N_DOT;
439 else
440 s1 = 0;
442 /* s1-> '.' after 000000 or NULL */
444 s = strchr (fptr, '/');
445 if (s == 0)
446 { /* no next '/' */
447 if (*(vptr-1) == '.')
448 *(vptr-1) = ']';
449 else if (rooted == 0)
450 *vptr++ = ']';
451 copyto (&vptr, &fptr, 0, (type == 1));
452 state = -1;
453 break;
455 else
457 while (*(s+1) == '/') /* skip multiple '/' */
458 s++;
461 if ((rooted != 0)
462 && (*(vptr-1) != '.'))
464 *vptr++ = '[';
465 nstate = N_DOT;
467 else
468 if ((nstate == N_DOT)
469 && (s1 != 0)
470 && (*(s+1) == 0))
472 if (type == 2)
474 *s1 = ']';
475 nstate = N_CLOSED;
478 state = 9;
479 break;
481 case 4: /* single '/' at start (9..15) */
482 if (*fptr == 0)
483 state = 5;
484 else
485 state = 6;
486 break;
488 case 5: /* just '/' at start (9) */
489 if (type != 2)
491 *vptr++ = '[';
492 nstate = N_OPEN;
494 strcpy (vptr, "000000");
495 vptr += 6;
496 if (type == 2)
497 state = 7;
498 else
499 state = 8;
500 break;
502 case 6: /* chars following '/' at start 10..15 */
503 *vptr++ = '[';
504 nstate = N_OPEN;
505 s = strchr (fptr, '/');
506 if (s == 0) /* 10 */
508 if (type != 1)
510 strcpy (vptr, "000000]");
511 vptr += 7;
513 copyto (&vptr, &fptr, 0, (type == 1));
514 if (type == 1)
516 *vptr++ = ']';
518 state = -1;
520 else /* 11..15 */
522 if ( (type == 2)
523 && (*(s+1) == 0)) /* 11(2) */
525 strcpy (vptr, "000000]");
526 nstate = N_CLOSED;
527 vptr += 7;
529 copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
530 state = 9;
532 break;
534 case 7: /* add '.dir' and exit */
535 if ((nstate == N_OPEN)
536 || (nstate == N_DOT))
538 s = vptr-1;
539 while (s > vmsname)
541 if (*s == ']')
543 break;
545 if (*s == '.')
547 *s = ']';
548 break;
550 s--;
553 strcpy (vptr, ".dir");
554 vptr += 4;
555 state = -1;
556 break;
558 case 8: /* add ']' and exit */
559 *vptr++ = ']';
560 state = -1;
561 break;
563 case 9: /* 17..21, fptr -> 1st '/' + 1 */
564 if (*fptr == 0)
566 if (type == 2)
568 state = 7;
570 else
571 state = 8;
572 break;
574 s = strchr (fptr, '/');
575 if (s == 0)
577 if (type != 1)
579 if (nstate == N_OPEN)
581 *vptr++ = ']';
582 nstate = N_CLOSED;
584 as_dir = 0;
586 else
588 if (nstate == N_OPEN)
590 *vptr++ = '.';
591 nstate = N_DOT;
593 as_dir = 1;
596 else
598 while (*(s+1) == '/')
599 s++;
600 if ( (type == 2)
601 && (*(s+1) == 0)) /* 19(2), 21(2)*/
603 if (nstate != N_CLOSED)
605 *vptr++ = ']';
606 nstate = N_CLOSED;
608 as_dir = 1;
610 else
612 if (nstate == N_OPEN)
614 *vptr++ = '.';
615 nstate = N_DOT;
617 as_dir = 1;
620 if ( (*fptr == '.') /* check for '..' or '../' */
621 && (*(fptr+1) == '.')
622 && ((*(fptr+2) == '/')
623 || (*(fptr+2) == 0)) )
625 fptr += 2;
626 if (*fptr == '/')
630 fptr++;
632 while (*fptr == '/');
634 else if (*fptr == 0)
635 type = 1;
636 vptr--; /* vptr -> '.' or ']' */
637 s1 = vptr;
638 for (;;)
640 s1--;
641 if (*s1 == '.') /* one back */
643 vptr = s1;
644 nstate = N_OPEN;
645 break;
647 if (*s1 == '[') /* top level reached */
649 if (*fptr == 0)
651 strcpy (s1, "[000000]");
652 vptr = s1 + 8;
653 nstate = N_CLOSED;
654 s = 0;
655 break;
657 else
659 vptr = s1+1;
660 nstate = N_OPEN;
661 break;
666 else
668 copyto (&vptr, &fptr, '/', as_dir);
669 if (nstate == N_DOT)
670 nstate = N_OPEN;
672 if (s == 0)
673 { /* 18,20 */
674 if (type == 1)
675 *vptr++ = ']';
676 state = -1;
678 else
680 if (*(s+1) == 0)
682 if (type == 2) /* 19,21 */
684 state = 7;
686 else
688 *vptr++ = ']';
689 state = -1;
693 break;
695 case 10: /* 1,2 first is '.' */
696 if (*fptr == '.')
698 fptr++;
699 state = 11;
701 else
702 state = 12;
703 break;
705 case 11: /* 2, '..' at start */
706 count = 1;
707 if (*fptr != 0)
709 if (*fptr != '/') /* got ..xxx */
711 return name;
713 do /* got ../ */
715 fptr++;
716 while (*fptr == '/') fptr++;
717 if (*fptr != '.')
718 break;
719 if (*(fptr+1) != '.')
720 break;
721 fptr += 2;
722 if ((*fptr == 0)
723 || (*fptr == '/'))
724 count++;
726 while (*fptr == '/');
728 { /* got '..' or '../' */
729 char cwdbuf[MAXPATHLEN+1];
731 s1 = getcwd(cwdbuf, MAXPATHLEN);
732 if (s1 == 0)
734 return ""; /* FIXME, err getcwd */
736 strcpy (vptr, s1);
737 s = strchr (vptr, ']');
738 if (s != 0)
740 while (s > vptr)
742 s--;
743 if (*s == '[')
745 s++;
746 strcpy (s, "000000]");
747 state = -1;
748 break;
750 else if (*s == '.')
752 if (--count == 0)
754 if (*fptr == 0) /* had '..' or '../' */
756 *s++ = ']';
757 state = -1;
759 else /* had '../xxx' */
761 state = 9;
763 *s = 0;
764 break;
769 vptr += strlen (vptr);
771 break;
773 case 12: /* 1, '.' at start */
774 if (*fptr != 0)
776 if (*fptr != '/')
778 return name;
780 fptr++;
784 char cwdbuf[MAXPATHLEN+1];
786 s1 = getcwd(cwdbuf, MAXPATHLEN);
787 if (s1 == 0)
789 return ""; /*FIXME, err getcwd */
791 strcpy (vptr, s1);
792 if (*fptr == 0)
794 state = -1;
795 break;
797 else
799 s = strchr (vptr, ']');
800 if (s == 0)
802 state = -1;
803 break;
805 *s = 0;
806 nstate = N_OPEN;
807 vptr += strlen (vptr);
808 state = 9;
811 break;
815 while (state > 0);
821 /* directory conversion done
822 fptr -> filename part of input string
823 vptr -> free space in vmsname
826 *vptr++ = 0;
828 return vmsname;
834 convert from vms-style to unix-style
836 dev:[dir1.dir2] //dev/dir1/dir2/
839 char *
840 unixify (char *name)
842 static char piece[512];
843 char *s, *p;
845 if (strchr (name, '/') != 0) /* already in unix style */
846 return name;
848 p = piece;
849 *p = 0;
851 /* device part */
853 s = strchr (name, ':');
855 if (s != 0)
857 *s = 0;
858 *p++ = '/';
859 *p++ = '/';
860 strcpy (p, name);
861 p += strlen (p);
862 *s = ':';
865 /* directory part */
867 *p++ = '/';
868 s = strchr (name, '[');
870 if (s != 0)
872 s++;
873 switch (*s)
875 case ']': /* [] */
876 strcat (p, "./");
877 break;
878 case '-': /* [- */
879 strcat (p, "../");
880 break;
881 case '.':
882 strcat (p, "./"); /* [. */
883 break;
884 default:
885 s--;
886 break;
888 s++;
889 while (*s)
891 if (*s == '.')
892 *p++ = '/';
893 else
894 *p++ = *s;
895 s++;
896 if (*s == ']')
898 s++;
899 break;
902 if (*s != 0) /* more after ']' ?? */
904 if (*(p-1) != '/')
905 *p++ = '/';
906 strcpy (p, s); /* copy it anyway */
910 else /* no '[' anywhere */
913 *p++ = 0;
916 /* force end with '/' */
918 if (*(p-1) != '/')
919 *p++ = '/';
920 *p = 0;
922 return piece;
925 /* EOF */