diff options
Diffstat (limited to 'src/kmk/vmsify.c')
-rw-r--r-- | src/kmk/vmsify.c | 1005 |
1 files changed, 1005 insertions, 0 deletions
diff --git a/src/kmk/vmsify.c b/src/kmk/vmsify.c new file mode 100644 index 0000000..e504a09 --- /dev/null +++ b/src/kmk/vmsify.c @@ -0,0 +1,1005 @@ +/* vmsify.c -- Module for vms <-> unix file name conversion +Copyright (C) 1996-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Klaus Kämpf (kkaempf@progis.de) + of proGIS Software, Aachen, Germany */ + + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "makeint.h" + +#if VMS +#include <unixlib.h> +#include <stdlib.h> +#include <jpidef.h> +#include <descrip.h> +#include <uaidef.h> +#include <ssdef.h> +#include <starlet.h> +#include <lib$routines.h> +/* Initialize a string descriptor (struct dsc$descriptor_s) for an + arbitrary string. ADDR is a pointer to the first character + of the string, and LEN is the length of the string. */ + +#define INIT_DSC_S(dsc, addr, len) do { \ + (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \ + (dsc).dsc$b_class = DSC$K_CLASS_S; \ + (dsc).dsc$w_length = (len); \ + (dsc).dsc$a_pointer = (addr); \ +} while (0) + +/* Initialize a string descriptor (struct dsc$descriptor_s) for a + NUL-terminated string. S is a pointer to the string; the length + is determined by calling strlen(). */ + +#define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s)) +#endif + +/* + copy 'from' to 'to' up to but not including 'upto' + return 0 if eos on from + return 1 if upto found + + return 'to' at last char + 1 + return 'from' at match + 1 or eos if no match + + if as_dir == 1, change all '.' to '_' + else change all '.' but the last to '_' +*/ + +static int +copyto (char **to, const char **from, char upto, int as_dir) +{ + const char *s; + + s = strrchr (*from, '.'); + + while (**from) + { + if (**from == upto) + { + do + { + (*from)++; + } + while (**from == upto); + return 1; + } + if (**from == '.') + { + if ((as_dir == 1) + || (*from != s)) + **to = '_'; + else + **to = '.'; + } + else + { +#ifdef HAVE_CASE_INSENSITIVE_FS + if (isupper ((unsigned char)**from)) + **to = tolower ((unsigned char)**from); + else +#endif + **to = **from; + } + (*to)++; + (*from)++; + } + + return 0; +} + + +/* + get translation of logical name + +*/ + +static char * +trnlog (const char *name) +{ + int stat; + static char reslt[1024]; + $DESCRIPTOR (reslt_dsc, reslt); + short resltlen; + struct dsc$descriptor_s name_dsc; + char *s; + + /* + * the string isn't changed, but there is no string descriptor with + * "const char *dsc$a_pointer" + */ + INIT_DSC_CSTRING (name_dsc, (char *)name); + + stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc); + + if ((stat&1) == 0) + { + return ""; + } + if (stat == SS$_NOTRAN) + { + return ""; + } + reslt[resltlen] = '\0'; + + s = xmalloc (resltlen+1); + strcpy (s, reslt); + return s; +} + +static char * +showall (char *s) +{ + static char t[512]; + char *pt; + + pt = t; + if (strchr (s, '\\') == 0) + return s; + while (*s) + { + if (*s == '\\') + { + *pt++ = *s; + } + *pt++ = *s++; + } + return pt; +} + + +enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE }; + +/* + convert unix style name to vms style + type = 0 -> name is a full name (directory and filename part) + type = 1 -> name is a directory + type = 2 -> name is a filename without directory + + The following conversions are applied + (0) (1) (2) + input full name dir name file name + +1 ./ <cwd> [] <current directory>.dir +2 ../ <home of cwd> <home of cwd> <home of cwd>.dir + +3 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir +4 //a a: a: a: +5 //a/ a: a: a:000000.dir + +9 / [000000] [000000] 000000.dir +10 /a [000000]a [a] [000000]a +11 /a/ [a] [a] [000000]a.dir +12 /a/b [a]b [a.b] [a]b +13 /a/b/ [a.b] [a.b] [a]b.dir +14 /a/b/c [a.b]c [a.b.c] [a.b]c +15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir + +16 a a [.a] a +17 a/ [.a] [.a] a.dir +18 a/b [.a]b [.a.b] [.a]b +19 a/b/ [.a.b] [.a.b] [.a]b.dir +20 a/b/c [.a.b]c [.a.b.c] [.a.b]c +21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir + +22 a.b.c a_b.c [.a_b_c] a_b_c.dir + +23 [x][y]z [x.y]z [x.y]z [x.y]z +24 [x][.y]z [x.y]z [x.y]z [x.y]z + +25 filenames with '$' are left unchanged if they contain no '/' +25 filenames with ':' are left unchanged +26 filenames with a single pair of '[' ']' are left unchanged + + The input string is not written to. The result is also const because + it's a static buffer; we don't want to change it. +*/ + +const char * +vmsify (const char *name, int type) +{ +/* max 255 device + max 39 directory + max 39 filename + max 39 filetype + max 5 version +*/ +/* todo: VMSMAXPATHLEN is defined for ODS2 names: it needs to be adjusted. */ +#define VMSMAXPATHLEN 512 + + enum namestate nstate; + static char vmsname[VMSMAXPATHLEN+1]; + const char *fptr; + const char *t; + char *vptr; + int as_dir; + int count; + const char *s; + const char *s1; + const char *s2; + + if (name == 0) + return 0; + fptr = name; + vptr = vmsname; + nstate = N_START; + + /* case 25a */ + t = strpbrk (name, "$:"); + + if (t != 0) + { +// const char *s1; +// const char *s2; + + if (type == 1) + { + s1 = strchr (t+1, '['); + s2 = strchr (t+1, ']'); + } + + if (*t == '$') + { + if (strchr (name, '/') == 0) + { + strcpy (vmsname, name); + if ((type == 1) && (s1 != 0) && (s2 == 0)) + strcat (vmsname, "]"); + return vmsname; + } + } + else + { + strcpy (vmsname, name); + if ((type == 1) && (s1 != 0) && (s2 == 0)) + strcat (vmsname, "]"); + return vmsname; + } + } + + /* case 26 */ + t = strchr (name, '['); + + if (t != 0) + { +// const char *s; +// const char *s1 = strchr (t+1, '['); + s1 = strchr (t+1, '['); + if (s1 == 0) + { + strcpy (vmsname, name); + if ((type == 1) && (strchr (t+1, ']') == 0)) + strcat (vmsname, "]"); + return vmsname; + } + s1--; + if (*s1 != ']') + { + strcpy (vmsname, name); + return vmsname; /* not ][, keep unchanged */ + } + + /* we have ][ */ + + s = name; + + /* s -> starting char + s1 -> ending ']' */ + do + { + strncpy (vptr, s, s1-s); /* copy up to but not including ']' */ + vptr += s1-s; + if (*s1 == 0) + break; + s = s1 + 1; /* s -> char behind ']' */ + if (*s != '[') /* was '][' ? */ + break; /* no, last ] found, exit */ + s++; + if (*s != '.') + *vptr++ = '.'; + s1 = strchr (s, ']'); + if (s1 == 0) /* no closing ] */ + s1 = s + strlen (s); + } + while (1); + + *vptr++ = ']'; + + fptr = s; + + } + else /* no [ in name */ + { + int state = 0; + int rooted = 1; /* flag if logical is rooted, else insert [000000] */ + + do + { + switch (state) + { + case 0: /* start of loop */ + if (*fptr == '/') + { + fptr++; + state = 1; + } + else if (*fptr == '.') + { + fptr++; + state = 10; + } + else + state = 2; + break; + + case 1: /* '/' at start */ + if (*fptr == '/') + { + fptr++; + state = 3; + } + else + state = 4; + break; + + case 2: /* no '/' at start */ + { + const char *s = strchr (fptr, '/'); + if (s == 0) /* no '/' (16) */ + { + if (type == 1) + { + strcpy (vptr, "[."); + vptr += 2; + } + copyto (&vptr, &fptr, 0, (type==1)); + if (type == 1) + *vptr++ = ']'; + state = -1; + } + else /* found '/' (17..21) */ + { + if ((type == 2) + && (*(s+1) == 0)) /* 17(2) */ + { + copyto (&vptr, &fptr, '/', 1); + state = 7; + } + else + { + strcpy (vptr, "[."); + vptr += 2; + copyto (&vptr, &fptr, '/', 1); + nstate = N_OPEN; + state = 9; + } + } + break; + } + + case 3: /* '//' at start */ + { +// const char *s; +// const char *s1; + char *vp; + while (*fptr == '/') /* collapse all '/' */ + fptr++; + if (*fptr == 0) /* just // */ + { + char cwdbuf[VMSMAXPATHLEN+1]; + + s1 = getcwd(cwdbuf, VMSMAXPATHLEN); + if (s1 == 0) + { + vmsname[0] = '\0'; + return vmsname; /* FIXME, err getcwd */ + } + s = strchr (s1, ':'); + if (s == 0) + { + vmsname[0] = '\0'; + return vmsname; /* FIXME, err no device */ + } + strncpy (vptr, s1, s-s1+1); + vptr += s-s1+1; + state = -1; + break; + } + + s = vptr; + + if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */ + { + *vptr++ = ':'; + state = -1; + break; + } + *vptr = ':'; + nstate = N_DEVICE; + if (*fptr == 0) /* just '//a/' */ + { + strcpy (vptr+1, "[000000]"); + vptr += 9; + state = -1; + break; + } + *vptr = 0; + /* check logical for [000000] insertion */ + vp = trnlog (s); + if (*vp != '\0') + { /* found translation */ + for (;;) /* loop over all nested logicals */ + { + char *vp2 = vp + strlen (vp) - 1; + if (*vp2 == ':') /* translation ends in ':' */ + { + vp2 = trnlog (vp); + free (vp); + if (*vp2 == 0) + { + rooted = 0; + break; + } + vp = vp2; + continue; /* next iteration */ + } + if (*vp2 == ']') /* translation ends in ']' */ + { + if (*(vp2-1) == '.') /* ends in '.]' */ + { + if (strncmp (fptr, "000000", 6) != 0) + rooted = 0; + } + else + { + strcpy (vmsname, s1); + vp = strchr (vmsname, ']'); + *vp = '.'; + nstate = N_DOT; + vptr = vp; + } + } + break; + } + free (vp); + } + else + rooted = 0; + + if (*vptr == 0) + { + nstate = N_DEVICE; + *vptr++ = ':'; + } + else + vptr++; + + if (rooted == 0) + { + nstate = N_DOT; + strcpy (vptr, "[000000."); + vptr += 8; + vp = vptr-1; + } + else + vp = 0; + + /* vp-> '.' after 000000 or NULL */ + + s = strchr (fptr, '/'); + if (s == 0) + { /* no next '/' */ + if (*(vptr-1) == '.') + *(vptr-1) = ']'; + else if (rooted == 0) + *vptr++ = ']'; + copyto (&vptr, &fptr, 0, (type == 1)); + state = -1; + break; + } + else + { + while (*(s+1) == '/') /* skip multiple '/' */ + s++; + } + + if ((rooted != 0) + && (*(vptr-1) != '.')) + { + *vptr++ = '['; + nstate = N_DOT; + } + else + if ((nstate == N_DOT) + && (vp != 0) + && (*(s+1) == 0)) + { + if (type == 2) + { + *vp = ']'; + nstate = N_CLOSED; + } + } + state = 9; + break; + } + case 4: /* single '/' at start (9..15) */ + if (*fptr == 0) + state = 5; + else + state = 6; + break; + + case 5: /* just '/' at start (9) */ + if (type != 2) + { + *vptr++ = '['; + nstate = N_OPEN; + } + strcpy (vptr, "000000"); + vptr += 6; + if (type == 2) + state = 7; + else + state = 8; + break; + + case 6: /* chars following '/' at start 10..15 */ + { + const char *s; + *vptr++ = '['; + nstate = N_OPEN; + s = strchr (fptr, '/'); + if (s == 0) /* 10 */ + { + if (type != 1) + { + strcpy (vptr, "000000]"); + vptr += 7; + } + copyto (&vptr, &fptr, 0, (type == 1)); + if (type == 1) + { + *vptr++ = ']'; + } + state = -1; + } + else /* 11..15 */ + { + if ( (type == 2) + && (*(s+1) == 0)) /* 11(2) */ + { + strcpy (vptr, "000000]"); + nstate = N_CLOSED; + vptr += 7; + } + copyto (&vptr, &fptr, '/', (*(vptr-1) != ']')); + state = 9; + } + break; + } + + case 7: /* add '.dir' and exit */ + if ((nstate == N_OPEN) + || (nstate == N_DOT)) + { + char *vp = vptr-1; + while (vp > vmsname) + { + if (*vp == ']') + { + break; + } + if (*vp == '.') + { + *vp = ']'; + break; + } + vp--; + } + } + strcpy (vptr, ".dir"); + vptr += 4; + state = -1; + break; + + case 8: /* add ']' and exit */ + *vptr++ = ']'; + state = -1; + break; + + case 9: /* 17..21, fptr -> 1st '/' + 1 */ + { + const char *s; + if (*fptr == 0) + { + if (type == 2) + { + state = 7; + } + else + state = 8; + break; + } + s = strchr (fptr, '/'); + if (s == 0) + { + if (type != 1) + { + if (nstate == N_OPEN) + { + *vptr++ = ']'; + nstate = N_CLOSED; + } + as_dir = 0; + } + else + { + if (nstate == N_OPEN) + { + *vptr++ = '.'; + nstate = N_DOT; + } + as_dir = 1; + } + } + else + { + while (*(s+1) == '/') + s++; + if ( (type == 2) + && (*(s+1) == 0)) /* 19(2), 21(2)*/ + { + if (nstate != N_CLOSED) + { + *vptr++ = ']'; + nstate = N_CLOSED; + } + as_dir = 1; + } + else + { + if (nstate == N_OPEN) + { + *vptr++ = '.'; + nstate = N_DOT; + } + as_dir = 1; + } + } + if ( (*fptr == '.') /* check for '..' or '../' */ + && (*(fptr+1) == '.') + && ((*(fptr+2) == '/') + || (*(fptr+2) == 0)) ) + { + char *vp; + fptr += 2; + if (*fptr == '/') + { + do + { + fptr++; + } + while (*fptr == '/'); + } + else if (*fptr == 0) + type = 1; + vptr--; /* vptr -> '.' or ']' */ + vp = vptr; + for (;;) + { + vp--; + if (*vp == '.') /* one back */ + { + vptr = vp; + nstate = N_OPEN; + break; + } + if (*vp == '[') /* top level reached */ + { + if (*fptr == 0) + { + strcpy (vp, "[000000]"); + vptr = vp + 8; + nstate = N_CLOSED; + s = 0; + break; + } + else + { + vptr = vp+1; + nstate = N_OPEN; + break; + } + } + } + } + else + { + copyto (&vptr, &fptr, '/', as_dir); + if (nstate == N_DOT) + nstate = N_OPEN; + } + if (s == 0) + { /* 18,20 */ + if (type == 1) + *vptr++ = ']'; + state = -1; + } + else + { + if (*(s+1) == 0) + { + if (type == 2) /* 19,21 */ + { + state = 7; + } + else + { + *vptr++ = ']'; + state = -1; + } + } + } + break; + } + + case 10: /* 1,2 first is '.' */ + if (*fptr == '.') + { + fptr++; + state = 11; + } + else + state = 12; + break; + + case 11: /* 2, '..' at start */ + count = 1; + if (*fptr != 0) + { + if (*fptr != '/') /* got ..xxx */ + { + strcpy (vmsname, name); + return vmsname; + } + do /* got ../ */ + { + fptr++; + while (*fptr == '/') fptr++; + if (*fptr != '.') + break; + if (*(fptr+1) != '.') + break; + fptr += 2; + if ((*fptr == 0) + || (*fptr == '/')) + count++; + } + while (*fptr == '/'); + } + { /* got '..' or '../' */ + char *vp; + char cwdbuf[VMSMAXPATHLEN+1]; + + vp = getcwd(cwdbuf, VMSMAXPATHLEN); + if (vp == 0) + { + vmsname[0] = '\0'; + return vmsname; /* FIXME, err getcwd */ + } + strcpy (vptr, vp); + vp = strchr (vptr, ']'); + if (vp != 0) + { + nstate = N_OPEN; + while (vp > vptr) + { + vp--; + if (*vp == '[') + { + vp++; + strcpy (vp, "000000]"); + state = -1; + break; + } + else if (*vp == '.') + { + if (--count == 0) + { + if (*fptr == 0) /* had '..' or '../' */ + { + *vp++ = ']'; + state = -1; + } + else /* had '../xxx' */ + { + state = 9; + } + *vp = '\0'; + break; + } + } + } + } + vptr += strlen (vptr); + } + break; + + case 12: /* 1, '.' at start */ + if (*fptr != 0) + { + if (*fptr != '/') + { + strcpy (vmsname, name); + return vmsname; + } + while (*fptr == '/') + fptr++; + } + + { + char *vp; + char cwdbuf[VMSMAXPATHLEN+1]; + + vp = getcwd(cwdbuf, VMSMAXPATHLEN); + if (vp == 0) + { + vmsname[0] = '\0'; + return vmsname; /*FIXME, err getcwd */ + } + strcpy (vptr, vp); + } + if (*fptr == 0) + { + state = -1; + break; + } + else + { + char *vp = strchr (vptr, ']'); + if (vp == 0) + { + state = -1; + break; + } + *vp = '\0'; + nstate = N_OPEN; + vptr += strlen (vptr); + state = 9; + } + break; + } + + } + while (state > 0); + + + } + + + /* directory conversion done + fptr -> filename part of input string + vptr -> free space in vmsname + */ + + *vptr++ = 0; + + return vmsname; +} + + + +/* + convert from vms-style to unix-style + + dev:[dir1.dir2] //dev/dir1/dir2/ +*/ + +const char * +unixify (const char *name) +{ + static char piece[512]; + const char *s; + char *p; + + if (strchr (name, '/') != 0) /* already in unix style */ + { + strcpy (piece, name); + return piece; + } + + p = piece; + *p = 0; + + /* device part */ + + s = strchr (name, ':'); + + if (s != 0) + { + int l = s - name; + *p++ = '/'; + *p++ = '/'; + strncpy (p, name, l); + p += l; + } + + /* directory part */ + + *p++ = '/'; + s = strchr (name, '['); + + if (s != 0) + { + s++; + switch (*s) + { + case ']': /* [] */ + strcat (p, "./"); + break; + case '-': /* [- */ + strcat (p, "../"); + break; + case '.': + strcat (p, "./"); /* [. */ + break; + default: + s--; + break; + } + s++; + while (*s) + { + if (*s == '.') + *p++ = '/'; + else + *p++ = *s; + s++; + if (*s == ']') + { + s++; + break; + } + } + if (*s != 0) /* more after ']' ?? */ + { + if (*(p-1) != '/') + *p++ = '/'; + strcpy (p, s); /* copy it anyway */ + } + } + + else /* no '[' anywhere */ + + { + *p++ = 0; + } + + /* force end with '/' */ + + if (*(p-1) != '/') + *p++ = '/'; + *p = 0; + + return piece; +} + +/* EOF */ |