f58fee73c492074ad9232072d2f8312ae3e98236
[platform/upstream/make.git] / vmsify.c
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
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 *
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 *
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 *
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 *
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 */