1/* 2 vmsify.c 3 4 Module for vms <-> unix file name conversion 5 6 Written by Klaus K�mpf (kkaempf@progis.de) 7 of proGIS Software, Aachen, Germany 8 9*/ 10 11#include <stdio.h> 12#include <string.h> 13#include <ctype.h> 14 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. */ 27 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) 34 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(). */ 38 39#define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s)) 40#endif 41 42/* 43 copy 'from' to 'to' up to but not including 'upto' 44 return 0 if eos on from 45 return 1 if upto found 46 47 return 'to' at last char + 1 48 return 'from' at match + 1 or eos if no match 49 50 if as_dir == 1, change all '.' to '_' 51 else change all '.' but the last to '_' 52*/ 53 54static int 55copyto (char **to, char **from, char upto, int as_dir) 56{ 57 char *s; 58 59 s = strrchr (*from, '.'); 60 61 while (**from) 62 { 63 if (**from == upto) 64 { 65 do 66 { 67 (*from)++; 68 } 69 while (**from == upto); 70 return 1; 71 } 72 if (**from == '.') 73 { 74 if ((as_dir == 1) 75 || (*from != s)) 76 **to = '_'; 77 else 78 **to = '.'; 79 } 80 else 81 { 82 if (isupper ((unsigned char)**from)) 83 **to = tolower ((unsigned char)**from); 84 else 85 **to = **from; 86 } 87 (*to)++; 88 (*from)++; 89 } 90 91 return 0; 92} 93 94 95/* 96 get translation of logical name 97 98*/ 99 100static char * 101trnlog (char *name) 102{ 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; 109 110 INIT_DSC_CSTRING (name_dsc, name); 111 112 stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc); 113 114 if ((stat&1) == 0) 115 { 116 return ""; 117 } 118 if (stat == SS$_NOTRAN) 119 { 120 return ""; 121 } 122 reslt[resltlen] = '\0'; 123 124 s = (char *)malloc (resltlen+1); 125 if (s == 0) 126 return ""; 127 strcpy (s, reslt); 128 return s; 129} 130 131static char * 132showall (char *s) 133{ 134 static char t[512]; 135 char *pt; 136 137 pt = t; 138 if (strchr (s, '\\') == 0) 139 return s; 140 while (*s) 141 { 142 if (*s == '\\') 143 { 144 *pt++ = *s; 145 } 146 *pt++ = *s++; 147 } 148 return pt; 149} 150 151 152enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE }; 153 154/* 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 159 160 The following conversions are applied 161 (0) (1) (2) 162 input full name dir name file name 163 1641 ./ <cwd> [] <current directory>.dir 1652 ../ <home of cwd> <home of cwd> <home of cwd>.dir 166 1673 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir 1684 //a a: a: a: 1695 //a/ a: a: a:000000.dir 170 1719 / [000000] [000000] 000000.dir 17210 /a [000000]a [a] [000000]a 17311 /a/ [a] [a] [000000]a.dir 17412 /a/b [a]b [a.b] [a]b 17513 /a/b/ [a.b] [a.b] [a]b.dir 17614 /a/b/c [a.b]c [a.b.c] [a.b]c 17715 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir 178 17916 a a [.a] a 18017 a/ [.a] [.a] a.dir 18118 a/b [.a]b [.a.b] [.a]b 18219 a/b/ [.a.b] [.a.b] [.a]b.dir 18320 a/b/c [.a.b]c [.a.b.c] [.a.b]c 18421 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir 185 18622 a.b.c a_b.c [.a_b_c] a_b_c.dir 187 18823 [x][y]z [x.y]z [x.y]z [x.y]z 18924 [x][.y]z [x.y]z [x.y]z [x.y]z 190 19125 filenames with '$' are left unchanged if they contain no '/' 19225 filenames with ':' are left unchanged 19326 filenames with a single pair of '[' ']' are left unchanged 194 195 the input string is not written to 196*/ 197 198char * 199vmsify (name, type) 200 char *name; 201 int type; 202{ 203/* max 255 device 204 max 39 directory 205 max 39 filename 206 max 39 filetype 207 max 5 version 208*/ 209#define MAXPATHLEN 512 210 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; 218 219 if (name == 0) 220 return 0; 221 fptr = name; 222 vptr = vmsname; 223 nstate = N_START; 224 225 /* case 25a */ 226 227 s = strpbrk (name, "$:"); 228 if (s != 0) 229 { 230 char *s1; 231 char *s2; 232 233 if (type == 1) 234 { 235 s1 = strchr (s+1, '['); 236 s2 = strchr (s+1, ']'); 237 } 238 239 if (*s == '$') 240 { 241 if (strchr (name, '/') == 0) 242 { 243 if ((type == 1) && (s1 != 0) && (s2 == 0)) 244 { 245 strcpy (vmsname, name); 246 strcat (vmsname, "]"); 247 return vmsname; 248 } 249 else 250 return name; 251 } 252 } 253 else 254 { 255 if ((type == 1) && (s1 != 0) && (s2 == 0)) 256 { 257 strcpy (vmsname, name); 258 strcat (vmsname, "]"); 259 return vmsname; 260 } 261 else 262 return name; 263 } 264 } 265 266 /* case 26 */ 267 268 s = strchr (name, '['); 269 270 if (s != 0) 271 { 272 s1 = strchr (s+1, '['); 273 if (s1 == 0) 274 { 275 if ((type == 1) 276 && (strchr (s+1, ']') == 0)) 277 { 278 strcpy (vmsname, name); 279 strcat (vmsname, "]"); 280 return vmsname; 281 } 282 else 283 return name; /* single [, keep unchanged */ 284 } 285 s1--; 286 if (*s1 != ']') 287 { 288 return name; /* not ][, keep unchanged */ 289 } 290 291 /* we have ][ */ 292 293 s = name; 294 295 /* s -> starting char 296 s1 -> ending ']' */ 297 298 do 299 { 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); 313 } 314 while (1); 315 316 *vptr++ = ']'; 317 318 fptr = s; 319 320 } 321 322 else /* no [ in name */ 323 324 { 325 326 int state; 327 int rooted = 1; /* flag if logical is rooted, else insert [000000] */ 328 329 state = 0; 330 331 do 332 { 333 334 switch (state) 335 { 336 case 0: /* start of loop */ 337 if (*fptr == '/') 338 { 339 fptr++; 340 state = 1; 341 } 342 else if (*fptr == '.') 343 { 344 fptr++; 345 state = 10; 346 } 347 else 348 state = 2; 349 break; 350 351 case 1: /* '/' at start */ 352 if (*fptr == '/') 353 { 354 fptr++; 355 state = 3; 356 } 357 else 358 state = 4; 359 break; 360 361 case 2: /* no '/' at start */ 362 s = strchr (fptr, '/'); 363 if (s == 0) /* no '/' (16) */ 364 { 365 if (type == 1) 366 { 367 strcpy (vptr, "[."); 368 vptr += 2; 369 } 370 copyto (&vptr, &fptr, 0, (type==1)); 371 if (type == 1) 372 *vptr++ = ']'; 373 state = -1; 374 } 375 else /* found '/' (17..21) */ 376 { 377 if ((type == 2) 378 && (*(s+1) == 0)) /* 17(2) */ 379 { 380 copyto (&vptr, &fptr, '/', 1); 381 state = 7; 382 } 383 else 384 { 385 strcpy (vptr, "[."); 386 vptr += 2; 387 copyto (&vptr, &fptr, '/', 1); 388 nstate = N_OPEN; 389 state = 9; 390 } 391 } 392 break; 393 394 case 3: /* '//' at start */ 395 while (*fptr == '/') /* collapse all '/' */ 396 fptr++; 397 if (*fptr == 0) /* just // */ 398 { 399 char cwdbuf[MAXPATHLEN+1]; 400 401 s1 = getcwd(cwdbuf, MAXPATHLEN); 402 if (s1 == 0) 403 { 404 return ""; /* FIXME, err getcwd */ 405 } 406 s = strchr (s1, ':'); 407 if (s == 0) 408 { 409 return ""; /* FIXME, err no device */ 410 } 411 strncpy (vptr, s1, s-s1+1); 412 vptr += s-s1+1; 413 state = -1; 414 break; 415 } 416 417 s = vptr; 418 419 if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */ 420 { 421 *vptr++ = ':'; 422 state = -1; 423 break; 424 } 425 *vptr = ':'; 426 nstate = N_DEVICE; 427 if (*fptr == 0) /* just '//a/' */ 428 { 429 strcpy (vptr+1, "[000000]"); 430 vptr += 9; 431 state = -1; 432 break; 433 } 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 */ 441 { 442 s2 = s1 + strlen (s1) - 1; 443 if (*s2 == ':') /* translation ends in ':' */ 444 { 445 s2 = trnlog (s1); 446 free (s1); 447 if (*s2 == 0) 448 { 449 rooted = 0; 450 break; 451 } 452 s1 = s2; 453 continue; /* next iteration */ 454 } 455 if (*s2 == ']') /* translation ends in ']' */ 456 { 457 if (*(s2-1) == '.') /* ends in '.]' */ 458 { 459 if (strncmp (fptr, "000000", 6) != 0) 460 rooted = 0; 461 } 462 else 463 { 464 strcpy (vmsname, s1); 465 s = strchr (vmsname, ']'); 466 *s = '.'; 467 nstate = N_DOT; 468 vptr = s; 469 } 470 } 471 break; 472 } 473 free (s1); 474 } 475 else 476 rooted = 0; 477 478 if (*vptr == 0) 479 { 480 nstate = N_DEVICE; 481 *vptr++ = ':'; 482 } 483 else 484 vptr++; 485 486 if (rooted == 0) 487 { 488 strcpy (vptr, "[000000."); 489 vptr += 8; 490 s1 = vptr-1; 491 nstate = N_DOT; 492 } 493 else 494 s1 = 0; 495 496 /* s1-> '.' after 000000 or NULL */ 497 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; 508 } 509 else 510 { 511 while (*(s+1) == '/') /* skip multiple '/' */ 512 s++; 513 } 514 515 if ((rooted != 0) 516 && (*(vptr-1) != '.')) 517 { 518 *vptr++ = '['; 519 nstate = N_DOT; 520 } 521 else 522 if ((nstate == N_DOT) 523 && (s1 != 0) 524 && (*(s+1) == 0)) 525 { 526 if (type == 2) 527 { 528 *s1 = ']'; 529 nstate = N_CLOSED; 530 } 531 } 532 state = 9; 533 break; 534 535 case 4: /* single '/' at start (9..15) */ 536 if (*fptr == 0) 537 state = 5; 538 else 539 state = 6; 540 break; 541 542 case 5: /* just '/' at start (9) */ 543 if (type != 2) 544 { 545 *vptr++ = '['; 546 nstate = N_OPEN; 547 } 548 strcpy (vptr, "000000"); 549 vptr += 6; 550 if (type == 2) 551 state = 7; 552 else 553 state = 8; 554 break; 555 556 case 6: /* chars following '/' at start 10..15 */ 557 *vptr++ = '['; 558 nstate = N_OPEN; 559 s = strchr (fptr, '/'); 560 if (s == 0) /* 10 */ 561 { 562 if (type != 1) 563 { 564 strcpy (vptr, "000000]"); 565 vptr += 7; 566 } 567 copyto (&vptr, &fptr, 0, (type == 1)); 568 if (type == 1) 569 { 570 *vptr++ = ']'; 571 } 572 state = -1; 573 } 574 else /* 11..15 */ 575 { 576 if ( (type == 2) 577 && (*(s+1) == 0)) /* 11(2) */ 578 { 579 strcpy (vptr, "000000]"); 580 nstate = N_CLOSED; 581 vptr += 7; 582 } 583 copyto (&vptr, &fptr, '/', (*(vptr-1) != ']')); 584 state = 9; 585 } 586 break; 587 588 case 7: /* add '.dir' and exit */ 589 if ((nstate == N_OPEN) 590 || (nstate == N_DOT)) 591 { 592 s = vptr-1; 593 while (s > vmsname) 594 { 595 if (*s == ']') 596 { 597 break; 598 } 599 if (*s == '.') 600 { 601 *s = ']'; 602 break; 603 } 604 s--; 605 } 606 } 607 strcpy (vptr, ".dir"); 608 vptr += 4; 609 state = -1; 610 break; 611 612 case 8: /* add ']' and exit */ 613 *vptr++ = ']'; 614 state = -1; 615 break; 616 617 case 9: /* 17..21, fptr -> 1st '/' + 1 */ 618 if (*fptr == 0) 619 { 620 if (type == 2) 621 { 622 state = 7; 623 } 624 else 625 state = 8; 626 break; 627 } 628 s = strchr (fptr, '/'); 629 if (s == 0) 630 { 631 if (type != 1) 632 { 633 if (nstate == N_OPEN) 634 { 635 *vptr++ = ']'; 636 nstate = N_CLOSED; 637 } 638 as_dir = 0; 639 } 640 else 641 { 642 if (nstate == N_OPEN) 643 { 644 *vptr++ = '.'; 645 nstate = N_DOT; 646 } 647 as_dir = 1; 648 } 649 } 650 else 651 { 652 while (*(s+1) == '/') 653 s++; 654 if ( (type == 2) 655 && (*(s+1) == 0)) /* 19(2), 21(2)*/ 656 { 657 if (nstate != N_CLOSED) 658 { 659 *vptr++ = ']'; 660 nstate = N_CLOSED; 661 } 662 as_dir = 1; 663 } 664 else 665 { 666 if (nstate == N_OPEN) 667 { 668 *vptr++ = '.'; 669 nstate = N_DOT; 670 } 671 as_dir = 1; 672 } 673 } 674 if ( (*fptr == '.') /* check for '..' or '../' */ 675 && (*(fptr+1) == '.') 676 && ((*(fptr+2) == '/') 677 || (*(fptr+2) == 0)) ) 678 { 679 fptr += 2; 680 if (*fptr == '/') 681 { 682 do 683 { 684 fptr++; 685 } 686 while (*fptr == '/'); 687 } 688 else if (*fptr == 0) 689 type = 1; 690 vptr--; /* vptr -> '.' or ']' */ 691 s1 = vptr; 692 for (;;) 693 { 694 s1--; 695 if (*s1 == '.') /* one back */ 696 { 697 vptr = s1; 698 nstate = N_OPEN; 699 break; 700 } 701 if (*s1 == '[') /* top level reached */ 702 { 703 if (*fptr == 0) 704 { 705 strcpy (s1, "[000000]"); 706 vptr = s1 + 8; 707 nstate = N_CLOSED; 708 s = 0; 709 break; 710 } 711 else 712 { 713 vptr = s1+1; 714 nstate = N_OPEN; 715 break; 716 } 717 } 718 } 719 } 720 else 721 { 722 copyto (&vptr, &fptr, '/', as_dir); 723 if (nstate == N_DOT) 724 nstate = N_OPEN; 725 } 726 if (s == 0) 727 { /* 18,20 */ 728 if (type == 1) 729 *vptr++ = ']'; 730 state = -1; 731 } 732 else 733 { 734 if (*(s+1) == 0) 735 { 736 if (type == 2) /* 19,21 */ 737 { 738 state = 7; 739 } 740 else 741 { 742 *vptr++ = ']'; 743 state = -1; 744 } 745 } 746 } 747 break; 748 749 case 10: /* 1,2 first is '.' */ 750 if (*fptr == '.') 751 { 752 fptr++; 753 state = 11; 754 } 755 else 756 state = 12; 757 break; 758 759 case 11: /* 2, '..' at start */ 760 count = 1; 761 if (*fptr != 0) 762 { 763 if (*fptr != '/') /* got ..xxx */ 764 { 765 return name; 766 } 767 do /* got ../ */ 768 { 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++; 779 } 780 while (*fptr == '/'); 781 } 782 { /* got '..' or '../' */ 783 char cwdbuf[MAXPATHLEN+1]; 784 785 s1 = getcwd(cwdbuf, MAXPATHLEN); 786 if (s1 == 0) 787 { 788 return ""; /* FIXME, err getcwd */ 789 } 790 strcpy (vptr, s1); 791 s = strchr (vptr, ']'); 792 if (s != 0) 793 { 794 nstate = N_OPEN; 795 while (s > vptr) 796 { 797 s--; 798 if (*s == '[') 799 { 800 s++; 801 strcpy (s, "000000]"); 802 state = -1; 803 break; 804 } 805 else if (*s == '.') 806 { 807 if (--count == 0) 808 { 809 if (*fptr == 0) /* had '..' or '../' */ 810 { 811 *s++ = ']'; 812 state = -1; 813 } 814 else /* had '../xxx' */ 815 { 816 state = 9; 817 } 818 *s = 0; 819 break; 820 } 821 } 822 } 823 } 824 vptr += strlen (vptr); 825 } 826 break; 827 828 case 12: /* 1, '.' at start */ 829 if (*fptr != 0) 830 { 831 if (*fptr != '/') 832 { 833 return name; 834 } 835 while (*fptr == '/') 836 fptr++; 837 } 838 839 { 840 char cwdbuf[MAXPATHLEN+1]; 841 842 s1 = getcwd(cwdbuf, MAXPATHLEN); 843 if (s1 == 0) 844 { 845 return ""; /*FIXME, err getcwd */ 846 } 847 strcpy (vptr, s1); 848 if (*fptr == 0) 849 { 850 state = -1; 851 break; 852 } 853 else 854 { 855 s = strchr (vptr, ']'); 856 if (s == 0) 857 { 858 state = -1; 859 break; 860 } 861 *s = 0; 862 nstate = N_OPEN; 863 vptr += strlen (vptr); 864 state = 9; 865 } 866 } 867 break; 868 } 869 870 } 871 while (state > 0); 872 873 874 } 875 876 877 /* directory conversion done 878 fptr -> filename part of input string 879 vptr -> free space in vmsname 880 */ 881 882 *vptr++ = 0; 883 884 return vmsname; 885} 886 887 888 889/* 890 convert from vms-style to unix-style 891 892 dev:[dir1.dir2] //dev/dir1/dir2/ 893*/ 894 895char * 896unixify (char *name) 897{ 898 static char piece[512]; 899 char *s, *p; 900 901 if (strchr (name, '/') != 0) /* already in unix style */ 902 return name; 903 904 p = piece; 905 *p = 0; 906 907 /* device part */ 908 909 s = strchr (name, ':'); 910 911 if (s != 0) 912 { 913 *s = 0; 914 *p++ = '/'; 915 *p++ = '/'; 916 strcpy (p, name); 917 p += strlen (p); 918 *s = ':'; 919 } 920 921 /* directory part */ 922 923 *p++ = '/'; 924 s = strchr (name, '['); 925 926 if (s != 0) 927 { 928 s++; 929 switch (*s) 930 { 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; 943 } 944 s++; 945 while (*s) 946 { 947 if (*s == '.') 948 *p++ = '/'; 949 else 950 *p++ = *s; 951 s++; 952 if (*s == ']') 953 { 954 s++; 955 break; 956 } 957 } 958 if (*s != 0) /* more after ']' ?? */ 959 { 960 if (*(p-1) != '/') 961 *p++ = '/'; 962 strcpy (p, s); /* copy it anyway */ 963 } 964 } 965 966 else /* no '[' anywhere */ 967 968 { 969 *p++ = 0; 970 } 971 972 /* force end with '/' */ 973 974 if (*(p-1) != '/') 975 *p++ = '/'; 976 *p = 0; 977 978 return piece; 979} 980 981/* EOF */ 982