1 /* vmsify.c -- Module for vms <-> unix file name conversion
2 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008, 2009, 2010 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 3 of the License, or (at your option) any later
9 version.
10 
11 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along with
16 this program.  If not, see <http://www.gnu.org/licenses/>.  */
17 
18 /* Written by Klaus K�mpf (kkaempf@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
copyto(char ** to,const char ** from,char upto,int as_dir)66 copyto (char **to, const char **from, char upto, int as_dir)
67 {
68   const 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 *
trnlog(const char * name)114 trnlog (const 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   /*
124    * the string isn't changed, but there is no string descriptor with
125    * "const char *dsc$a_pointer"
126    */
127   INIT_DSC_CSTRING (name_dsc, (char *)name);
128 
129   stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
130 
131   if ((stat&1) == 0)
132     {
133       return "";
134     }
135   if (stat == SS$_NOTRAN)
136     {
137       return "";
138     }
139   reslt[resltlen] = '\0';
140 
141   s = malloc (resltlen+1);
142   if (s == 0)
143     return "";
144   strcpy (s, reslt);
145   return s;
146 }
147 
148 static char *
showall(char * s)149 showall (char *s)
150 {
151   static char t[512];
152   char *pt;
153 
154   pt = t;
155   if (strchr (s, '\\') == 0)
156     return s;
157   while (*s)
158     {
159       if (*s == '\\')
160 	{
161 	  *pt++ = *s;
162 	}
163       *pt++ = *s++;
164     }
165   return pt;
166 }
167 
168 
169 enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
170 
171 /*
172   convert unix style name to vms style
173   type = 0 -> name is a full name (directory and filename part)
174   type = 1 -> name is a directory
175   type = 2 -> name is a filename without directory
176 
177   The following conversions are applied
178 			(0)		(1)			(2)
179 	input		full name	dir name		file name
180 
181 1	./		<cwd>		[]			<current directory>.dir
182 2	../		<home of cwd>	<home of cwd>		<home of cwd>.dir
183 
184 3	//		<dev of cwd>:	<dev of cwd>:[000000]	<dev of cwd>:000000.dir
185 4	//a		a:		a:			a:
186 5	//a/		a:		a:			a:000000.dir
187 
188 9	/		[000000]	[000000]		000000.dir
189 10	/a		[000000]a	[a]			[000000]a
190 11	/a/		[a]		[a]			[000000]a.dir
191 12	/a/b		[a]b		[a.b]			[a]b
192 13	/a/b/		[a.b]		[a.b]			[a]b.dir
193 14	/a/b/c		[a.b]c		[a.b.c]			[a.b]c
194 15	/a/b/c/		[a.b.c]		[a.b.c]			[a.b]c.dir
195 
196 16	a		a		[.a]			a
197 17	a/		[.a]		[.a]			a.dir
198 18	a/b		[.a]b		[.a.b]			[.a]b
199 19	a/b/		[.a.b]		[.a.b]			[.a]b.dir
200 20	a/b/c		[.a.b]c		[.a.b.c]		[.a.b]c
201 21	a/b/c/		[.a.b.c]	[.a.b.c]		[.a.b]c.dir
202 
203 22	a.b.c		a_b.c		[.a_b_c]		a_b_c.dir
204 
205 23	[x][y]z		[x.y]z		[x.y]z			[x.y]z
206 24	[x][.y]z	[x.y]z		[x.y]z			[x.y]z
207 
208 25  filenames with '$'  are left unchanged if they contain no '/'
209 25  filenames with ':' are left unchanged
210 26  filenames with a single pair of '[' ']' are left unchanged
211 
212   The input string is not written to.  The result is also const because
213   it's a static buffer; we don't want to change it.
214 */
215 
216 const char *
vmsify(const char * name,int type)217 vmsify (const char *name, int type)
218 {
219 /* max 255 device
220    max 39 directory
221    max 39 filename
222    max 39 filetype
223    max 5 version
224 */
225 #define MAXPATHLEN 512
226 
227   enum namestate nstate;
228   static char vmsname[MAXPATHLEN+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[MAXPATHLEN+1];
407 
408 		s1 = getcwd(cwdbuf, MAXPATHLEN);
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[MAXPATHLEN+1];
801 
802 	      vp = getcwd(cwdbuf, MAXPATHLEN);
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[MAXPATHLEN+1];
861 
862 	      vp = getcwd(cwdbuf, MAXPATHLEN);
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 *
unixify(const char * name)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 */
1006