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 Kmpf (kkaempf (at) 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 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 * 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 * 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 * 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 * 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