(root)/
make-4.4/
src/
vmsify.c
       1  /* vmsify.c -- Module for vms <-> unix file name conversion
       2  Copyright (C) 1996-2022 Free Software Foundation, Inc.
       3  This file is part of GNU Make.
       4  
       5  GNU Make is free software; you can redistribute it and/or modify it under the
       6  terms of the GNU General Public License as published by the Free Software
       7  Foundation; either version 3 of the License, or (at your option) any later
       8  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  this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Written by Klaus K�mpf (kkaempf@progis.de)
      18     of proGIS Software, Aachen, Germany */
      19  
      20  
      21  #include <stdio.h>
      22  #include <string.h>
      23  #include <ctype.h>
      24  
      25  #include "makeint.h"
      26  
      27  #if VMS
      28  #include <unixlib.h>
      29  #include <stdlib.h>
      30  #include <jpidef.h>
      31  #include <descrip.h>
      32  #include <uaidef.h>
      33  #include <ssdef.h>
      34  #include <starlet.h>
      35  #include <lib$routines.h>
      36  /* Initialize a string descriptor (struct dsc$descriptor_s) for an
      37     arbitrary string.   ADDR is a pointer to the first character
      38     of the string, and LEN is the length of the string. */
      39  
      40  #define INIT_DSC_S(dsc, addr, len) do { \
      41    (dsc).dsc$b_dtype = DSC$K_DTYPE_T;    \
      42    (dsc).dsc$b_class = DSC$K_CLASS_S;    \
      43    (dsc).dsc$w_length = (len);           \
      44    (dsc).dsc$a_pointer = (addr);         \
      45  } while (0)
      46  
      47  /* Initialize a string descriptor (struct dsc$descriptor_s) for a
      48     NUL-terminated string.  S is a pointer to the string; the length
      49     is determined by calling strlen(). */
      50  
      51  #define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
      52  #endif
      53  
      54  /*
      55    copy 'from' to 'to' up to but not including 'upto'
      56    return 0 if eos on from
      57    return 1 if upto found
      58  
      59    return 'to' at last char + 1
      60    return 'from' at match + 1 or eos if no match
      61  
      62    if as_dir == 1, change all '.' to '_'
      63    else change all '.' but the last to '_'
      64  */
      65  
      66  static int
      67  copyto (char **to, const char **from, char upto, int as_dir)
      68  {
      69    const char *s;
      70  
      71    s = strrchr (*from, '.');
      72  
      73    while (**from)
      74      {
      75        if (**from == upto)
      76  	{
      77  	  do
      78  	    {
      79  	      (*from)++;
      80  	    }
      81  	  while (**from == upto);
      82  	  return 1;
      83  	}
      84        if (**from == '.')
      85  	{
      86  	  if ((as_dir == 1)
      87  	      || (*from != s))
      88  	    **to = '_';
      89  	  else
      90  	    **to = '.';
      91  	}
      92        else
      93  	{
      94  #ifdef HAVE_CASE_INSENSITIVE_FS
      95  	  if (isupper ((unsigned char)**from))
      96  	    **to = tolower ((unsigned char)**from);
      97  	  else
      98  #endif
      99  	    **to = **from;
     100  	}
     101        (*to)++;
     102        (*from)++;
     103      }
     104  
     105    return 0;
     106  }
     107  
     108  
     109  /*
     110    get translation of logical name
     111  
     112  */
     113  
     114  static char *
     115  trnlog (const char *name)
     116  {
     117    int stat;
     118    static char reslt[1024];
     119    $DESCRIPTOR (reslt_dsc, reslt);
     120    short resltlen;
     121    struct dsc$descriptor_s name_dsc;
     122    char *s;
     123  
     124    /*
     125     * the string isn't changed, but there is no string descriptor with
     126     * "const char *dsc$a_pointer"
     127     */
     128    INIT_DSC_CSTRING (name_dsc, (char *)name);
     129  
     130    stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
     131  
     132    if ((stat&1) == 0)
     133      {
     134        return "";
     135      }
     136    if (stat == SS$_NOTRAN)
     137      {
     138        return "";
     139      }
     140    reslt[resltlen] = '\0';
     141  
     142    s = xmalloc (resltlen+1);
     143    strcpy (s, reslt);
     144    return s;
     145  }
     146  
     147  static char *
     148  showall (char *s)
     149  {
     150    static char t[512];
     151    char *pt;
     152  
     153    pt = t;
     154    if (strchr (s, '\\') == 0)
     155      return s;
     156    while (*s)
     157      {
     158        if (*s == '\\')
     159  	{
     160  	  *pt++ = *s;
     161  	}
     162        *pt++ = *s++;
     163      }
     164    return pt;
     165  }
     166  
     167  
     168  enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
     169  
     170  /*
     171    convert unix style name to vms style
     172    type = 0 -> name is a full name (directory and filename part)
     173    type = 1 -> name is a directory
     174    type = 2 -> name is a filename without directory
     175  
     176    The following conversions are applied
     177  			(0)		(1)			(2)
     178  	input		full name	dir name		file name
     179  
     180  1	./		<cwd>		[]			<current directory>.dir
     181  2	../		<home of cwd>	<home of cwd>		<home of cwd>.dir
     182  
     183  3	//		<dev of cwd>:	<dev of cwd>:[000000]	<dev of cwd>:000000.dir
     184  4	//a		a:		a:			a:
     185  5	//a/		a:		a:			a:000000.dir
     186  
     187  9	/		[000000]	[000000]		000000.dir
     188  10	/a		[000000]a	[a]			[000000]a
     189  11	/a/		[a]		[a]			[000000]a.dir
     190  12	/a/b		[a]b		[a.b]			[a]b
     191  13	/a/b/		[a.b]		[a.b]			[a]b.dir
     192  14	/a/b/c		[a.b]c		[a.b.c]			[a.b]c
     193  15	/a/b/c/		[a.b.c]		[a.b.c]			[a.b]c.dir
     194  
     195  16	a		a		[.a]			a
     196  17	a/		[.a]		[.a]			a.dir
     197  18	a/b		[.a]b		[.a.b]			[.a]b
     198  19	a/b/		[.a.b]		[.a.b]			[.a]b.dir
     199  20	a/b/c		[.a.b]c		[.a.b.c]		[.a.b]c
     200  21	a/b/c/		[.a.b.c]	[.a.b.c]		[.a.b]c.dir
     201  
     202  22	a.b.c		a_b.c		[.a_b_c]		a_b_c.dir
     203  
     204  23	[x][y]z		[x.y]z		[x.y]z			[x.y]z
     205  24	[x][.y]z	[x.y]z		[x.y]z			[x.y]z
     206  
     207  25  filenames with '$'  are left unchanged if they contain no '/'
     208  25  filenames with ':' are left unchanged
     209  26  filenames with a single pair of '[' ']' are left unchanged
     210  
     211    The input string is not written to.  The result is also const because
     212    it's a static buffer; we don't want to change it.
     213  */
     214  
     215  const char *
     216  vmsify (const char *name, int type)
     217  {
     218  /* max 255 device
     219     max 39 directory
     220     max 39 filename
     221     max 39 filetype
     222     max 5 version
     223  */
     224  /* todo: VMSMAXPATHLEN is defined for ODS2 names: it needs to be adjusted. */
     225  #define VMSMAXPATHLEN 512
     226  
     227    enum namestate nstate;
     228    static char vmsname[VMSMAXPATHLEN+1];
     229    const char *fptr;
     230    const char *t;
     231    char *vptr;
     232    int as_dir;
     233    int count;
     234    const char *s;
     235    const char *s1;
     236    const char *s2;
     237  
     238    if (name == 0)
     239      return 0;
     240    fptr = name;
     241    vptr = vmsname;
     242    nstate = N_START;
     243  
     244    /* case 25a */
     245    t = strpbrk (name, "$:");
     246  
     247    if (t != 0)
     248      {
     249  //      const char *s1;
     250  //      const char *s2;
     251  
     252        if (type == 1)
     253          {
     254            s1 = strchr (t+1, '[');
     255            s2 = strchr (t+1, ']');
     256          }
     257  
     258        if (*t == '$')
     259          {
     260            if (strchr (name, '/') == 0)
     261              {
     262                strcpy (vmsname, name);
     263                if ((type == 1) && (s1 != 0) && (s2 == 0))
     264                  strcat (vmsname, "]");
     265                return vmsname;
     266              }
     267          }
     268        else
     269          {
     270            strcpy (vmsname, name);
     271            if ((type == 1) && (s1 != 0) && (s2 == 0))
     272              strcat (vmsname, "]");
     273            return vmsname;
     274          }
     275      }
     276  
     277    /* case 26 */
     278    t = strchr (name, '[');
     279  
     280    if (t != 0)
     281      {
     282  //      const char *s;
     283  //      const char *s1 = strchr (t+1, '[');
     284        s1 = strchr (t+1, '[');
     285        if (s1 == 0)
     286  	{
     287            strcpy (vmsname, name);
     288  	  if ((type == 1) && (strchr (t+1, ']') == 0))
     289              strcat (vmsname, "]");
     290            return vmsname;
     291  	}
     292        s1--;
     293        if (*s1 != ']')
     294  	{
     295            strcpy (vmsname, name);
     296  	  return vmsname;		/* not ][, keep unchanged */
     297  	}
     298  
     299        /* we have ][ */
     300  
     301        s = name;
     302  
     303        /* s  -> starting char
     304  	 s1 -> ending ']'  */
     305        do
     306  	{
     307  	  strncpy (vptr, s, s1-s);	/* copy up to but not including ']' */
     308  	  vptr += s1-s;
     309  	  if (*s1 == 0)
     310  	    break;
     311  	  s = s1 + 1;			/* s -> char behind ']' */
     312  	  if (*s != '[')		/* was '][' ? */
     313  	    break;			/* no, last ] found, exit */
     314  	  s++;
     315  	  if (*s != '.')
     316  	    *vptr++ = '.';
     317  	  s1 = strchr (s, ']');
     318  	  if (s1 == 0)			/* no closing ] */
     319  	    s1 = s + strlen (s);
     320  	}
     321        while (1);
     322  
     323        *vptr++ = ']';
     324  
     325        fptr = s;
     326  
     327      }
     328    else		/* no [ in name */
     329      {
     330        int state = 0;
     331        int rooted = 1;	/* flag if logical is rooted, else insert [000000] */
     332  
     333        do
     334  	{
     335        switch (state)
     336  	{
     337  	  case 0:				/* start of loop */
     338  	    if (*fptr == '/')
     339  	      {
     340  		fptr++;
     341  		state = 1;
     342  	      }
     343  	    else if (*fptr == '.')
     344  	      {
     345  		fptr++;
     346  		state = 10;
     347  	      }
     348  	    else
     349  	      state = 2;
     350  	    break;
     351  
     352  	  case 1:				/* '/' at start */
     353  	    if (*fptr == '/')
     354  	      {
     355  		fptr++;
     356  		state = 3;
     357  	      }
     358  	    else
     359  	      state = 4;
     360  	    break;
     361  
     362  	  case 2:				/* no '/' at start */
     363              {
     364              const char *s = strchr (fptr, '/');
     365  	    if (s == 0)			/* no '/' (16) */
     366  	      {
     367  		if (type == 1)
     368  		  {
     369  		    strcpy (vptr, "[.");
     370  		    vptr += 2;
     371  		  }
     372  		copyto (&vptr, &fptr, 0, (type==1));
     373  		if (type == 1)
     374  		  *vptr++ = ']';
     375  		state = -1;
     376  	      }
     377  	    else			/* found '/' (17..21) */
     378  	      {
     379  		if ((type == 2)
     380  		    && (*(s+1) == 0))	/* 17(2) */
     381  		  {
     382  		    copyto (&vptr, &fptr, '/', 1);
     383  		    state = 7;
     384  		  }
     385  		else
     386  		  {
     387  		    strcpy (vptr, "[.");
     388  		    vptr += 2;
     389  		    copyto (&vptr, &fptr, '/', 1);
     390  		    nstate = N_OPEN;
     391  		    state = 9;
     392  		  }
     393  	      }
     394  	    break;
     395              }
     396  
     397  	  case 3:				/* '//' at start */
     398              {
     399  //            const char *s;
     400  //            const char *s1;
     401              char *vp;
     402  	    while (*fptr == '/')	/* collapse all '/' */
     403  	      fptr++;
     404  	    if (*fptr == 0)		/* just // */
     405  	      {
     406  		char cwdbuf[VMSMAXPATHLEN+1];
     407  
     408  		s1 = getcwd(cwdbuf, VMSMAXPATHLEN);
     409  		if (s1 == 0)
     410  		  {
     411                      vmsname[0] = '\0';
     412  		    return vmsname;	/* FIXME, err getcwd */
     413  		  }
     414  		s = strchr (s1, ':');
     415  		if (s == 0)
     416  		  {
     417                      vmsname[0] = '\0';
     418  		    return vmsname;	/* FIXME, err no device */
     419  		  }
     420  		strncpy (vptr, s1, s-s1+1);
     421  		vptr += s-s1+1;
     422  		state = -1;
     423  		break;
     424  	      }
     425  
     426  	    s = vptr;
     427  
     428  	    if (copyto (&vptr, &fptr, '/', 1) == 0)	/* copy device part */
     429  	      {
     430  		*vptr++ = ':';
     431  		state = -1;
     432  		break;
     433  	      }
     434  	    *vptr = ':';
     435  	    nstate = N_DEVICE;
     436  	    if (*fptr == 0)	/* just '//a/' */
     437  	      {
     438  		strcpy (vptr+1, "[000000]");
     439  		vptr += 9;
     440  		state = -1;
     441  		break;
     442  	      }
     443  	    *vptr = 0;
     444  				/* check logical for [000000] insertion */
     445  	    vp = trnlog (s);
     446  	    if (*vp != '\0')
     447  	      {			/* found translation */
     448  		for (;;)	/* loop over all nested logicals */
     449  		  {
     450  		    char *vp2 = vp + strlen (vp) - 1;
     451  		    if (*vp2 == ':')	/* translation ends in ':' */
     452  		      {
     453  			vp2 = trnlog (vp);
     454  			free (vp);
     455  			if (*vp2 == 0)
     456  			  {
     457  			    rooted = 0;
     458  			    break;
     459  			  }
     460  			vp = vp2;
     461  			continue;	/* next iteration */
     462  		      }
     463  		    if (*vp2 == ']')	/* translation ends in ']' */
     464  		      {
     465  			if (*(vp2-1) == '.')	/* ends in '.]' */
     466  			  {
     467  			    if (strncmp (fptr, "000000", 6) != 0)
     468  			      rooted = 0;
     469  			  }
     470  			else
     471  			  {
     472  			    strcpy (vmsname, s1);
     473  			    vp = strchr (vmsname, ']');
     474  			    *vp = '.';
     475  			    nstate = N_DOT;
     476  			    vptr = vp;
     477  			  }
     478  		      }
     479  		    break;
     480  		  }
     481  		free (vp);
     482  	      }
     483  	    else
     484  	      rooted = 0;
     485  
     486  	    if (*vptr == 0)
     487  	      {
     488  		nstate = N_DEVICE;
     489  	        *vptr++ = ':';
     490  	      }
     491  	    else
     492  	      vptr++;
     493  
     494  	    if (rooted == 0)
     495  	      {
     496  		nstate = N_DOT;
     497  	        strcpy (vptr, "[000000.");
     498  		vptr += 8;
     499  		vp = vptr-1;
     500  	      }
     501  	    else
     502  	      vp = 0;
     503  
     504              /* vp-> '.' after 000000 or NULL */
     505  
     506  	    s = strchr (fptr, '/');
     507  	    if (s == 0)
     508  	      {				/* no next '/' */
     509  		if (*(vptr-1) == '.')
     510  		  *(vptr-1) = ']';
     511  		else if (rooted == 0)
     512  		  *vptr++ = ']';
     513  		copyto (&vptr, &fptr, 0, (type == 1));
     514  		state = -1;
     515  		break;
     516  	      }
     517  	    else
     518  	      {
     519  		while (*(s+1) == '/')	/* skip multiple '/' */
     520  		  s++;
     521  	      }
     522  
     523  	    if ((rooted != 0)
     524  	        && (*(vptr-1) != '.'))
     525  	      {
     526  		*vptr++ = '[';
     527  		nstate = N_DOT;
     528  	      }
     529  	    else
     530  	      if ((nstate == N_DOT)
     531  		 && (vp != 0)
     532  		 && (*(s+1) == 0))
     533  		{
     534  		  if (type == 2)
     535  		    {
     536  		      *vp = ']';
     537  		      nstate = N_CLOSED;
     538  		    }
     539  		}
     540  	    state = 9;
     541  	    break;
     542              }
     543  	  case 4:				/* single '/' at start (9..15) */
     544  	    if (*fptr == 0)
     545  	      state = 5;
     546  	    else
     547  	      state = 6;
     548  	    break;
     549  
     550  	  case 5:				/* just '/' at start (9) */
     551  	    if (type != 2)
     552  	      {
     553  	        *vptr++ = '[';
     554  		nstate = N_OPEN;
     555  	      }
     556  	    strcpy (vptr, "000000");
     557  	    vptr += 6;
     558  	    if (type == 2)
     559  	      state = 7;
     560  	    else
     561  	      state = 8;
     562  	    break;
     563  
     564  	  case 6:		/* chars following '/' at start 10..15 */
     565              {
     566              const char *s;
     567  	    *vptr++ = '[';
     568  	    nstate = N_OPEN;
     569  	    s = strchr (fptr, '/');
     570  	    if (s == 0)			/* 10 */
     571  	      {
     572  		if (type != 1)
     573  		  {
     574  		    strcpy (vptr, "000000]");
     575  		    vptr += 7;
     576  		  }
     577  		copyto (&vptr, &fptr, 0, (type == 1));
     578  		if (type == 1)
     579  		  {
     580  		    *vptr++ = ']';
     581  		  }
     582  		state = -1;
     583  	      }
     584  	    else			/* 11..15 */
     585  	      {
     586  		if ( (type == 2)
     587  		   && (*(s+1) == 0))	/* 11(2) */
     588  		  {
     589  		    strcpy (vptr, "000000]");
     590  		    nstate = N_CLOSED;
     591  		    vptr += 7;
     592  		  }
     593  		copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
     594  		state = 9;
     595  	      }
     596  	    break;
     597              }
     598  
     599  	  case 7:				/* add '.dir' and exit */
     600  	    if ((nstate == N_OPEN)
     601  		|| (nstate == N_DOT))
     602  	      {
     603  		char *vp = vptr-1;
     604  		while (vp > vmsname)
     605  		  {
     606  		    if (*vp == ']')
     607  		      {
     608  			break;
     609  		      }
     610  		    if (*vp == '.')
     611  		      {
     612  			*vp = ']';
     613  			break;
     614  		      }
     615  		    vp--;
     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              {
     630              const char *s;
     631  	    if (*fptr == 0)
     632  	      {
     633  		if (type == 2)
     634  		  {
     635  		    state = 7;
     636  		  }
     637  		else
     638  		  state = 8;
     639  		break;
     640  	      }
     641  	    s = strchr (fptr, '/');
     642  	    if (s == 0)
     643  	      {
     644  		if (type != 1)
     645  		  {
     646  		    if (nstate == N_OPEN)
     647  		      {
     648  			*vptr++ = ']';
     649  			nstate = N_CLOSED;
     650  		      }
     651  		    as_dir = 0;
     652  		  }
     653  		else
     654  		  {
     655  		    if (nstate == N_OPEN)
     656  		      {
     657  			*vptr++ = '.';
     658  			nstate = N_DOT;
     659  		      }
     660  		    as_dir = 1;
     661  		  }
     662  	      }
     663  	    else
     664  	      {
     665  		while (*(s+1) == '/')
     666  		  s++;
     667  		if ( (type == 2)
     668  		    && (*(s+1) == 0))		/* 19(2), 21(2)*/
     669  		  {
     670  		    if (nstate != N_CLOSED)
     671  		      {
     672  			*vptr++ = ']';
     673  			nstate = N_CLOSED;
     674  		      }
     675  		    as_dir = 1;
     676  		  }
     677  		else
     678  		  {
     679  		    if (nstate == N_OPEN)
     680  		      {
     681  			*vptr++ = '.';
     682  			nstate = N_DOT;
     683  		      }
     684  		    as_dir = 1;
     685  		  }
     686  	      }
     687  	    if ( (*fptr == '.')			/* check for '..' or '../' */
     688  		&& (*(fptr+1) == '.')
     689  		&& ((*(fptr+2) == '/')
     690  		    || (*(fptr+2) == 0)) )
     691  	      {
     692                  char *vp;
     693  		fptr += 2;
     694  		if (*fptr == '/')
     695  		  {
     696  		    do
     697  		      {
     698  			fptr++;
     699  		      }
     700  		    while (*fptr == '/');
     701  		  }
     702  		else if (*fptr == 0)
     703  		  type = 1;
     704  		vptr--;				/* vptr -> '.' or ']' */
     705  		vp = vptr;
     706  		for (;;)
     707  		  {
     708  		    vp--;
     709  		    if (*vp == '.')		/* one back */
     710  		      {
     711  			vptr = vp;
     712  			nstate = N_OPEN;
     713  			break;
     714  		      }
     715  		    if (*vp == '[')		/* top level reached */
     716  		      {
     717  			if (*fptr == 0)
     718  			  {
     719  			    strcpy (vp, "[000000]");
     720  			    vptr = vp + 8;
     721  			    nstate = N_CLOSED;
     722  			    s = 0;
     723  			    break;
     724  			  }
     725  			else
     726  			  {
     727  			    vptr = vp+1;
     728  			    nstate = N_OPEN;
     729  			    break;
     730  			  }
     731  		      }
     732  		  }
     733  	      }
     734  	    else
     735  	      {
     736  		copyto (&vptr, &fptr, '/', as_dir);
     737  		if (nstate == N_DOT)
     738  		  nstate = N_OPEN;
     739  	      }
     740  	    if (s == 0)
     741  	      {					/* 18,20 */
     742  		if (type == 1)
     743  		  *vptr++ = ']';
     744  		state = -1;
     745  	      }
     746  	    else
     747  	      {
     748  		if (*(s+1) == 0)
     749  		  {
     750  		    if (type == 2)		/* 19,21 */
     751  		      {
     752  		        state = 7;
     753  		      }
     754  		    else
     755  		      {
     756  			*vptr++ = ']';
     757  			state = -1;
     758  		      }
     759  		  }
     760  	      }
     761  	    break;
     762              }
     763  
     764  	  case 10:				/* 1,2 first is '.' */
     765  	    if (*fptr == '.')
     766  	      {
     767  		fptr++;
     768  		state = 11;
     769  	      }
     770  	    else
     771  	      state = 12;
     772  	    break;
     773  
     774  	  case 11:				/* 2, '..' at start */
     775  	    count = 1;
     776  	    if (*fptr != 0)
     777  	      {
     778  		if (*fptr != '/')		/* got ..xxx */
     779  		  {
     780                      strcpy (vmsname, name);
     781  		    return vmsname;
     782  		  }
     783  		do				/* got ../ */
     784  		  {
     785  		    fptr++;
     786  		    while (*fptr == '/') fptr++;
     787  		    if (*fptr != '.')
     788  		      break;
     789  		    if (*(fptr+1) != '.')
     790  		      break;
     791  		    fptr += 2;
     792  		    if ((*fptr == 0)
     793  			|| (*fptr == '/'))
     794  		      count++;
     795  		  }
     796  		while (*fptr == '/');
     797  	      }
     798  	    {					/* got '..' or '../' */
     799                char *vp;
     800  	      char cwdbuf[VMSMAXPATHLEN+1];
     801  
     802  	      vp = getcwd(cwdbuf, VMSMAXPATHLEN);
     803  	      if (vp == 0)
     804  		{
     805                    vmsname[0] = '\0';
     806  		  return vmsname;    /* FIXME, err getcwd */
     807  		}
     808  	      strcpy (vptr, vp);
     809  	      vp = strchr (vptr, ']');
     810  	      if (vp != 0)
     811  		{
     812  		  nstate = N_OPEN;
     813  		  while (vp > vptr)
     814  		    {
     815  		      vp--;
     816  		      if (*vp == '[')
     817  			{
     818  			  vp++;
     819  			  strcpy (vp, "000000]");
     820  			  state = -1;
     821  			  break;
     822  			}
     823  		      else if (*vp == '.')
     824  			{
     825  			  if (--count == 0)
     826  			    {
     827  			      if (*fptr == 0)	/* had '..' or '../' */
     828  				{
     829  				  *vp++ = ']';
     830  				  state = -1;
     831  				}
     832  			      else			/* had '../xxx' */
     833  				{
     834  				  state = 9;
     835  				}
     836  			      *vp = '\0';
     837  			      break;
     838  			    }
     839  			}
     840  		    }
     841  		}
     842  	      vptr += strlen (vptr);
     843  	    }
     844  	    break;
     845  
     846  	  case 12:				/* 1, '.' at start */
     847  	    if (*fptr != 0)
     848  	      {
     849  		if (*fptr != '/')
     850  		  {
     851                      strcpy (vmsname, name);
     852  		    return vmsname;
     853  		  }
     854  		while (*fptr == '/')
     855  		  fptr++;
     856  	      }
     857  
     858  	    {
     859                char *vp;
     860  	      char cwdbuf[VMSMAXPATHLEN+1];
     861  
     862  	      vp = getcwd(cwdbuf, VMSMAXPATHLEN);
     863  	      if (vp == 0)
     864  		{
     865                    vmsname[0] = '\0';
     866  		  return vmsname;    /*FIXME, err getcwd */
     867  		}
     868  	      strcpy (vptr, vp);
     869              }
     870              if (*fptr == 0)
     871                {
     872                  state = -1;
     873                  break;
     874                }
     875              else
     876                {
     877                  char *vp = strchr (vptr, ']');
     878                  if (vp == 0)
     879                    {
     880                      state = -1;
     881                      break;
     882                    }
     883                  *vp = '\0';
     884                  nstate = N_OPEN;
     885                  vptr += strlen (vptr);
     886                  state = 9;
     887                }
     888  	    break;
     889  	}
     890  
     891  	}
     892        while (state > 0);
     893  
     894  
     895      }
     896  
     897  
     898    /* directory conversion done
     899       fptr -> filename part of input string
     900       vptr -> free space in vmsname
     901    */
     902  
     903    *vptr++ = 0;
     904  
     905    return vmsname;
     906  }
     907  
     908  
     909  
     910  /*
     911    convert from vms-style to unix-style
     912  
     913    dev:[dir1.dir2]	//dev/dir1/dir2/
     914  */
     915  
     916  const char *
     917  unixify (const char *name)
     918  {
     919    static char piece[512];
     920    const char *s;
     921    char *p;
     922  
     923    if (strchr (name, '/') != 0)		/* already in unix style */
     924      {
     925        strcpy (piece, name);
     926        return piece;
     927      }
     928  
     929    p = piece;
     930    *p = 0;
     931  
     932    /* device part */
     933  
     934    s = strchr (name, ':');
     935  
     936    if (s != 0)
     937      {
     938        int l = s - name;
     939        *p++ = '/';
     940        *p++ = '/';
     941        strncpy (p, name, l);
     942        p += l;
     943      }
     944  
     945    /* directory part */
     946  
     947    *p++ = '/';
     948    s = strchr (name, '[');
     949  
     950    if (s != 0)
     951      {
     952        s++;
     953        switch (*s)
     954          {
     955  	  case ']':		/* [] */
     956  	    strcat (p, "./");
     957  	    break;
     958  	  case '-':		/* [- */
     959  	    strcat (p, "../");
     960  	    break;
     961  	  case '.':
     962  	    strcat (p, "./");	/* [. */
     963  	    break;
     964  	  default:
     965  	    s--;
     966  	    break;
     967          }
     968        s++;
     969        while (*s)
     970          {
     971  	  if (*s == '.')
     972  	    *p++ = '/';
     973  	  else
     974  	    *p++ = *s;
     975  	  s++;
     976  	  if (*s == ']')
     977  	    {
     978  	      s++;
     979  	      break;
     980  	    }
     981          }
     982        if (*s != 0)		/* more after ']' ?? */
     983          {
     984  	  if (*(p-1) != '/')
     985  	    *p++ = '/';
     986  	  strcpy (p, s);		/* copy it anyway */
     987          }
     988      }
     989  
     990    else		/* no '[' anywhere */
     991  
     992      {
     993        *p++ = 0;
     994      }
     995  
     996    /* force end with '/' */
     997  
     998    if (*(p-1) != '/')
     999      *p++ = '/';
    1000    *p = 0;
    1001  
    1002    return piece;
    1003  }
    1004  
    1005  /* EOF */