summaryrefslogtreecommitdiff
path: root/vmsify.c
diff options
context:
space:
mode:
Diffstat (limited to 'vmsify.c')
-rw-r--r--vmsify.c1005
1 files changed, 1005 insertions, 0 deletions
diff --git a/vmsify.c b/vmsify.c
new file mode 100644
index 0000000..f58fee7
--- /dev/null
+++ b/vmsify.c
@@ -0,0 +1,1005 @@
+/* vmsify.c -- Module for vms <-> unix file name conversion
+Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+2007, 2008, 2009, 2010 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>
+
+#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 = malloc (resltlen+1);
+ if (s == 0)
+ return "";
+ 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
+*/
+#define MAXPATHLEN 512
+
+ enum namestate nstate;
+ static char vmsname[MAXPATHLEN+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[MAXPATHLEN+1];
+
+ s1 = getcwd(cwdbuf, MAXPATHLEN);
+ 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[MAXPATHLEN+1];
+
+ vp = getcwd(cwdbuf, MAXPATHLEN);
+ 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[MAXPATHLEN+1];
+
+ vp = getcwd(cwdbuf, MAXPATHLEN);
+ 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 */