OSDN Git Service

update copyrights
[pf3gnuchains/gcc-fork.git] / gcc / cppfiles.c
1 /* Part of CPP library.  (include file handling)
2    Copyright (C) 1986, 87, 89, 92 - 95, 1998 Free Software Foundation, Inc.
3    Written by Per Bothner, 1994.
4    Based on CCCP program by Paul Rubin, June 1986
5    Adapted to ANSI C, Richard Stallman, Jan 1987
6    Split out of cpplib.c, Zack Weinberg, Oct 1998
7
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22  In other words, you are welcome to use, share and improve this program.
23  You are forbidden to forbid anyone else to use, share and improve
24  what you give them.   Help stamp out software-hoarding!  */
25
26 #include "config.h"
27 #include "system.h"
28 #include "cpplib.h"
29
30 /* The entry points to this file are: find_include_file, finclude,
31    append_include_chain, deps_output, and file_cleanup.
32    file_cleanup is only called through CPP_BUFFER(pfile)->cleanup,
33    so it's static anyway. */
34
35 static void add_import                  PROTO ((cpp_reader *, int, char *));
36 static int lookup_import                PROTO ((cpp_reader *, char *,
37                                                 struct file_name_list *));
38 static int redundant_include_p          PROTO ((cpp_reader *, char *));
39 static struct file_name_map *read_name_map      PROTO ((cpp_reader *, char *));
40 static char *read_filename_string       PROTO ((int, FILE *));
41 static int open_include_file            PROTO ((cpp_reader *, char *,
42                                                 struct file_name_list *));
43 static int safe_read                    PROTO ((int, char *, int));
44
45 /* Not safe to prototype these. */
46 extern char *xmalloc();
47 extern char *xrealloc();
48
49 /* Append a chain of `struct file_name_list's
50    to the end of the main include chain.
51    FIRST is the beginning of the chain to append, and LAST is the end.  */
52
53 void
54 append_include_chain (pfile, first, last)
55      cpp_reader *pfile;
56      struct file_name_list *first, *last;
57 {
58   struct cpp_options *opts = CPP_OPTIONS (pfile);
59   struct file_name_list *dir;
60
61   if (!first || !last)
62     return;
63
64   if (opts->include == 0)
65     opts->include = first;
66   else
67     opts->last_include->next = first;
68
69   if (opts->first_bracket_include == 0)
70     opts->first_bracket_include = first;
71
72   for (dir = first; ; dir = dir->next) {
73     int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE;
74     if (len > pfile->max_include_len)
75       pfile->max_include_len = len;
76     if (dir == last)
77       break;
78   }
79
80   last->next = NULL;
81   opts->last_include = last;
82 }
83
84 /* Add output to `deps_buffer' for the -M switch.
85    STRING points to the text to be output.
86    SPACER is ':' for targets, ' ' for dependencies, zero for text
87    to be inserted literally.  */
88
89 void
90 deps_output (pfile, string, spacer)
91      cpp_reader *pfile;
92      char *string;
93      int spacer;
94 {
95   int size;
96
97   if (!*string)
98     return;
99
100 #ifdef VMS
101   hack_vms_include_specification (string);
102 #endif
103
104   size = strlen (string);
105
106 #ifndef MAX_OUTPUT_COLUMNS
107 #define MAX_OUTPUT_COLUMNS 72
108 #endif
109   if (spacer
110       && pfile->deps_column > 0
111       && (pfile->deps_column + size) > MAX_OUTPUT_COLUMNS)
112     {
113       deps_output (pfile, " \\\n  ", 0);
114       pfile->deps_column = 0;
115     }
116
117   if (pfile->deps_size + size + 8 > pfile->deps_allocated_size)
118     {
119       pfile->deps_allocated_size = (pfile->deps_size + size + 50) * 2;
120       pfile->deps_buffer = (char *) xrealloc (pfile->deps_buffer,
121                                               pfile->deps_allocated_size);
122     }
123   if (spacer == ' ' && pfile->deps_column > 0)
124     pfile->deps_buffer[pfile->deps_size++] = ' ';
125   bcopy (string, &pfile->deps_buffer[pfile->deps_size], size);
126   pfile->deps_size += size;
127   pfile->deps_column += size;
128   if (spacer == ':')
129     pfile->deps_buffer[pfile->deps_size++] = ':';
130   pfile->deps_buffer[pfile->deps_size] = 0;
131 }
132
133 static int
134 file_cleanup (pbuf, pfile)
135      cpp_buffer *pbuf;
136      cpp_reader *pfile ATTRIBUTE_UNUSED;
137 {
138   if (pbuf->buf)
139     {
140       free (pbuf->buf);
141       pbuf->buf = 0;
142     }
143   return 0;
144 }
145
146 int
147 find_include_file (pfile, fbeg, flen, fname,
148                    importing, search_start, foundhere)
149      cpp_reader *pfile;
150      char *fbeg;
151      unsigned long flen;
152      char *fname;
153      int importing;
154      struct file_name_list *search_start;
155      struct file_name_list **foundhere;
156 {
157   struct file_name_list *searchptr;
158   int f;
159     
160   /* If specified file name is absolute, just open it.  */
161
162   if (*fbeg == '/')
163   {
164     strcpy (fname, fbeg);
165 #ifdef VMS
166     hack_vms_include_specification (fname);
167 #endif
168     if (redundant_include_p (pfile, fname))
169       return -2;
170     if (importing)
171       f = lookup_import (pfile, fname, NULL_PTR);
172     else
173       f = open_include_file (pfile, fname, NULL_PTR);
174     if (f == -2)
175       return -2;        /* Already included this file */
176   }
177   else
178   {
179     /* Search directory path, trying to open the file.
180        Copy each filename tried into FNAME.  */
181
182     for (searchptr = search_start; searchptr; searchptr = searchptr->next)
183     {
184       unsigned int l = 0;
185       if (searchptr->fname)
186       {
187         /* The empty string in a search path is ignored.
188            This makes it possible to turn off entirely
189            a standard piece of the list.  */
190         if (searchptr->fname[0] == 0)
191           continue;
192
193         l = strlen (searchptr->fname);
194
195         bcopy (searchptr->fname, fname, l);
196         fname[l++] = '/';
197       }
198
199       bcopy (fbeg, &fname[l], flen);
200       fname[flen+l] = '\0';
201 #ifdef VMS
202       hack_vms_include_specification (fname);
203 #endif /* VMS */
204       /* ??? There are currently 3 separate mechanisms for avoiding processing
205          of redundant include files: #import, #pragma once, and
206          redundant_include_p.  It would be nice if they were unified.  */
207       if (redundant_include_p (pfile, fname))
208         return -2;
209       if (importing)
210         f = lookup_import (pfile, fname, searchptr);
211       else
212         f = open_include_file (pfile, fname, searchptr);
213       if (f == -2)
214         return -2;                      /* Already included this file */
215 #ifdef EACCES
216       else if (f == -1 && errno == EACCES)
217         cpp_warning (pfile, "Header file %s exists, but is not readable",
218                      fname);
219 #endif
220       if (f >= 0)
221         break;
222     }
223   }
224
225   if (f < 0)
226     {
227       /* A file that was not found.  */
228       bcopy (fbeg, fname, flen);
229       fname[flen] = 0;
230
231       return -1;
232     }
233   else
234     {
235       /* Check to see if this include file is a once-only include file.
236          If so, give up.  */
237
238       struct file_name_list *ptr;
239
240       for (ptr = pfile->dont_repeat_files; ptr; ptr = ptr->next)
241           if (!strcmp (ptr->fname, fname))
242             {
243               close (f);
244               return -2;                /* This file was once'd.  */
245             }
246     }
247
248     /* Record file on "seen" list for #import.  */
249     add_import (pfile, f, fname);
250
251     *foundhere = searchptr;
252     return f;
253 }
254
255 /* Return nonzero if there is no need to include file NAME
256    because it has already been included and it contains a conditional
257    to make a repeated include do nothing.  */
258
259 static int
260 redundant_include_p (pfile, name)
261      cpp_reader *pfile;
262      char *name;
263 {
264   struct file_name_list *l = pfile->all_include_files;
265   for (; l; l = l->next)
266     if (! strcmp (name, l->fname)
267         && l->control_macro
268         && cpp_lookup (pfile, l->control_macro, -1, -1))
269       return 1;
270   return 0;
271 }
272
273
274
275 /* Maintain and search list of included files, for #import.  */
276
277 /* Hash a file name for import_hash_table.  */
278
279 static int 
280 import_hash (f)
281      char *f;
282 {
283   int val = 0;
284
285   while (*f) val += *f++;
286   return (val%IMPORT_HASH_SIZE);
287 }
288
289 /* Search for file FILENAME in import_hash_table.
290    Return -2 if found, either a matching name or a matching inode.
291    Otherwise, open the file and return a file descriptor if successful
292    or -1 if unsuccessful.  */
293
294 static int
295 lookup_import (pfile, filename, searchptr)
296      cpp_reader *pfile;
297      char *filename;
298      struct file_name_list *searchptr;
299 {
300   struct import_file *i;
301   int h;
302   int hashval;
303   struct stat sb;
304   int fd;
305
306   hashval = import_hash (filename);
307
308   /* Attempt to find file in list of already included files */
309   i = pfile->import_hash_table[hashval];
310
311   while (i) {
312     if (!strcmp (filename, i->name))
313       return -2;                /* return found */
314     i = i->next;
315   }
316   /* Open it and try a match on inode/dev */
317   fd = open_include_file (pfile, filename, searchptr);
318   if (fd < 0)
319     return fd;
320   fstat (fd, &sb);
321   for (h = 0; h < IMPORT_HASH_SIZE; h++) {
322     i = pfile->import_hash_table[h];
323     while (i) {
324       /* Compare the inode and the device.
325          Supposedly on some systems the inode is not a scalar.  */
326       if (!bcmp ((char *) &i->inode, (char *) &sb.st_ino, sizeof (sb.st_ino))
327           && i->dev == sb.st_dev) {
328         close (fd);
329         return -2;              /* return found */
330       }
331       i = i->next;
332     }
333   }
334   return fd;                    /* Not found, return open file */
335 }
336
337 /* Add the file FNAME, open on descriptor FD, to import_hash_table.  */
338
339 static void
340 add_import (pfile, fd, fname)
341      cpp_reader *pfile;
342      int fd;
343      char *fname;
344 {
345   struct import_file *i;
346   int hashval;
347   struct stat sb;
348
349   hashval = import_hash (fname);
350   fstat (fd, &sb);
351   i = (struct import_file *)xmalloc (sizeof (struct import_file));
352   i->name = (char *)xmalloc (strlen (fname)+1);
353   strcpy (i->name, fname);
354   bcopy ((char *) &sb.st_ino, (char *) &i->inode, sizeof (sb.st_ino));
355   i->dev = sb.st_dev;
356   i->next = pfile->import_hash_table[hashval];
357   pfile->import_hash_table[hashval] = i;
358 }
359
360 /* The file_name_map structure holds a mapping of file names for a
361    particular directory.  This mapping is read from the file named
362    FILE_NAME_MAP_FILE in that directory.  Such a file can be used to
363    map filenames on a file system with severe filename restrictions,
364    such as DOS.  The format of the file name map file is just a series
365    of lines with two tokens on each line.  The first token is the name
366    to map, and the second token is the actual name to use.  */
367
368 struct file_name_map
369 {
370   struct file_name_map *map_next;
371   char *map_from;
372   char *map_to;
373 };
374
375 #define FILE_NAME_MAP_FILE "header.gcc"
376
377 /* Read a space delimited string of unlimited length from a stdio
378    file.  */
379
380 static char *
381 read_filename_string (ch, f)
382      int ch;
383      FILE *f;
384 {
385   char *alloc, *set;
386   int len;
387
388   len = 20;
389   set = alloc = xmalloc (len + 1);
390   if (! is_space[ch])
391     {
392       *set++ = ch;
393       while ((ch = getc (f)) != EOF && ! is_space[ch])
394         {
395           if (set - alloc == len)
396             {
397               len *= 2;
398               alloc = xrealloc (alloc, len + 1);
399               set = alloc + len / 2;
400             }
401           *set++ = ch;
402         }
403     }
404   *set = '\0';
405   ungetc (ch, f);
406   return alloc;
407 }
408
409 /* This structure holds a linked list of file name maps, one per directory.  */
410
411 struct file_name_map_list
412 {
413   struct file_name_map_list *map_list_next;
414   char *map_list_name;
415   struct file_name_map *map_list_map;
416 };
417
418 /* Read the file name map file for DIRNAME.  */
419
420 static struct file_name_map *
421 read_name_map (pfile, dirname)
422      cpp_reader *pfile;
423      char *dirname;
424 {
425   register struct file_name_map_list *map_list_ptr;
426   char *name;
427   FILE *f;
428
429   for (map_list_ptr = CPP_OPTIONS (pfile)->map_list; map_list_ptr;
430        map_list_ptr = map_list_ptr->map_list_next)
431     if (! strcmp (map_list_ptr->map_list_name, dirname))
432       return map_list_ptr->map_list_map;
433
434   map_list_ptr = ((struct file_name_map_list *)
435                   xmalloc (sizeof (struct file_name_map_list)));
436   map_list_ptr->map_list_name = savestring (dirname);
437   map_list_ptr->map_list_map = NULL;
438
439   name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
440   strcpy (name, dirname);
441   if (*dirname)
442     strcat (name, "/");
443   strcat (name, FILE_NAME_MAP_FILE);
444   f = fopen (name, "r");
445   if (!f)
446     map_list_ptr->map_list_map = NULL;
447   else
448     {
449       int ch;
450       int dirlen = strlen (dirname);
451
452       while ((ch = getc (f)) != EOF)
453         {
454           char *from, *to;
455           struct file_name_map *ptr;
456
457           if (is_space[ch])
458             continue;
459           from = read_filename_string (ch, f);
460           while ((ch = getc (f)) != EOF && is_hor_space[ch])
461             ;
462           to = read_filename_string (ch, f);
463
464           ptr = ((struct file_name_map *)
465                  xmalloc (sizeof (struct file_name_map)));
466           ptr->map_from = from;
467
468           /* Make the real filename absolute.  */
469           if (*to == '/')
470             ptr->map_to = to;
471           else
472             {
473               ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
474               strcpy (ptr->map_to, dirname);
475               ptr->map_to[dirlen] = '/';
476               strcpy (ptr->map_to + dirlen + 1, to);
477               free (to);
478             }         
479
480           ptr->map_next = map_list_ptr->map_list_map;
481           map_list_ptr->map_list_map = ptr;
482
483           while ((ch = getc (f)) != '\n')
484             if (ch == EOF)
485               break;
486         }
487       fclose (f);
488     }
489   
490   map_list_ptr->map_list_next = CPP_OPTIONS (pfile)->map_list;
491   CPP_OPTIONS (pfile)->map_list = map_list_ptr;
492
493   return map_list_ptr->map_list_map;
494 }  
495
496 /* Try to open include file FILENAME.  SEARCHPTR is the directory
497    being tried from the include file search path.  This function maps
498    filenames on file systems based on information read by
499    read_name_map.  */
500
501 static int
502 open_include_file (pfile, filename, searchptr)
503      cpp_reader *pfile;
504      char *filename;
505      struct file_name_list *searchptr;
506 {
507   if (CPP_OPTIONS (pfile)->remap)
508     {
509       register struct file_name_map *map;
510       register char *from;
511       char *p, *dir;
512
513       if (searchptr && ! searchptr->got_name_map)
514         {
515           searchptr->name_map = read_name_map (pfile,
516                                                searchptr->fname
517                                                ? searchptr->fname : ".");
518           searchptr->got_name_map = 1;
519         }
520
521       /* First check the mapping for the directory we are using.  */
522       if (searchptr && searchptr->name_map)
523         {
524           from = filename;
525           if (searchptr->fname)
526             from += strlen (searchptr->fname) + 1;
527           for (map = searchptr->name_map; map; map = map->map_next)
528             {
529               if (! strcmp (map->map_from, from))
530                 {
531                   /* Found a match.  */
532                   return open (map->map_to, O_RDONLY, 0666);
533                 }
534             }
535         }
536
537       /* Try to find a mapping file for the particular directory we are
538          looking in.  Thus #include <sys/types.h> will look up sys/types.h
539          in /usr/include/header.gcc and look up types.h in
540          /usr/include/sys/header.gcc.  */
541       p = rindex (filename, '/');
542       if (! p)
543         p = filename;
544       if (searchptr
545           && searchptr->fname
546           && strlen (searchptr->fname) == (size_t) (p - filename)
547           && ! strncmp (searchptr->fname, filename, p - filename))
548         {
549           /* FILENAME is in SEARCHPTR, which we've already checked.  */
550           return open (filename, O_RDONLY, 0666);
551         }
552
553       if (p == filename)
554         {
555           dir = ".";
556           from = filename;
557         }
558       else
559         {
560           dir = (char *) alloca (p - filename + 1);
561           bcopy (filename, dir, p - filename);
562           dir[p - filename] = '\0';
563           from = p + 1;
564         }
565       for (map = read_name_map (pfile, dir); map; map = map->map_next)
566         if (! strcmp (map->map_from, from))
567           return open (map->map_to, O_RDONLY, 0666);
568     }
569
570   return open (filename, O_RDONLY, 0666);
571 }
572
573 /* Process the contents of include file FNAME, already open on descriptor F,
574    with output to OP.
575    SYSTEM_HEADER_P is 1 if this file resides in any one of the known
576    "system" include directories (as decided by the `is_system_include'
577    function above).
578    DIRPTR is the link in the dir path through which this file was found,
579    or 0 if the file name was absolute or via the current directory.
580    Return 1 on success, 0 on failure.
581
582    The caller is responsible for the cpp_push_buffer.  */
583
584 int
585 finclude (pfile, f, fname, system_header_p, dirptr)
586      cpp_reader *pfile;
587      int f;
588      char *fname;
589      int system_header_p;
590      struct file_name_list *dirptr;
591 {
592   struct stat st;
593   size_t st_size;
594   long i;
595   int length;
596   cpp_buffer *fp;                       /* For input stack frame */
597 #if 0
598   int missing_newline = 0;
599 #endif
600
601   if (fstat (f, &st) < 0)
602     {
603       cpp_perror_with_name (pfile, fname);
604       close (f);
605       cpp_pop_buffer (pfile);
606       return 0;
607     }
608
609   fp = CPP_BUFFER (pfile);
610   fp->nominal_fname = fp->fname = fname;
611 #if 0
612   fp->length = 0;
613 #endif
614   fp->dir = dirptr;
615   fp->system_header_p = system_header_p;
616   fp->lineno = 1;
617   fp->colno = 1;
618   fp->cleanup = file_cleanup;
619
620   if (S_ISREG (st.st_mode)) {
621     st_size = (size_t) st.st_size;
622     if (st_size != st.st_size || st_size + 2 < st_size) {
623       cpp_error (pfile, "file `%s' too large", fname);
624       close (f);
625       return 0;
626     }
627     fp->buf = (U_CHAR *) xmalloc (st_size + 2);
628     fp->alimit = fp->buf + st_size + 2;
629     fp->cur = fp->buf;
630
631     /* Read the file contents, knowing that st_size is an upper bound
632        on the number of bytes we can read.  */
633     length = safe_read (f, fp->buf, st_size);
634     fp->rlimit = fp->buf + length;
635     if (length < 0) goto nope;
636   }
637   else if (S_ISDIR (st.st_mode)) {
638     cpp_error (pfile, "directory `%s' specified in #include", fname);
639     close (f);
640     return 0;
641   } else {
642     /* Cannot count its file size before reading.
643        First read the entire file into heap and
644        copy them into buffer on stack.  */
645
646     size_t bsize = 2000;
647
648     st_size = 0;
649     fp->buf = (U_CHAR *) xmalloc (bsize + 2);
650
651     for (;;) {
652       i = safe_read (f, fp->buf + st_size, bsize - st_size);
653       if (i < 0)
654         goto nope;      /* error! */
655       st_size += i;
656       if (st_size != bsize)
657         break;  /* End of file */
658       bsize *= 2;
659       fp->buf = (U_CHAR *) xrealloc (fp->buf, bsize + 2);
660     }
661     fp->cur = fp->buf;
662     length = st_size;
663   }
664
665   if ((length > 0 && fp->buf[length - 1] != '\n')
666       /* Backslash-newline at end is not good enough.  */
667       || (length > 1 && fp->buf[length - 2] == '\\')) {
668     fp->buf[length++] = '\n';
669 #if 0
670     missing_newline = 1;
671 #endif
672   }
673   fp->buf[length] = '\0';
674   fp->rlimit = fp->buf + length;
675
676   /* Close descriptor now, so nesting does not use lots of descriptors.  */
677   close (f);
678
679   /* Must do this before calling trigraph_pcp, so that the correct file name
680      will be printed in warning messages.  */
681
682   pfile->input_stack_listing_current = 0;
683
684 #if 0
685   if (!no_trigraphs)
686     trigraph_pcp (fp);
687 #endif
688
689 #if 0
690   rescan (op, 0);
691
692   if (missing_newline)
693     fp->lineno--;
694
695   if (CPP_PEDANTIC (pfile) && missing_newline)
696     pedwarn ("file does not end in newline");
697
698   indepth--;
699   input_file_stack_tick++;
700   free (fp->buf);
701 #endif
702   return 1;
703
704  nope:
705
706   cpp_perror_with_name (pfile, fname);
707   close (f);
708   free (fp->buf);
709   return 1;
710 }
711
712 /* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
713    retrying if necessary.  If MAX_READ_LEN is defined, read at most
714    that bytes at a time.  Return a negative value if an error occurs,
715    otherwise return the actual number of bytes read,
716    which must be LEN unless end-of-file was reached.  */
717
718 static int
719 safe_read (desc, ptr, len)
720      int desc;
721      char *ptr;
722      int len;
723 {
724   int left, rcount, nchars;
725
726   left = len;
727   while (left > 0) {
728     rcount = left;
729 #ifdef MAX_READ_LEN
730     if (rcount > MAX_READ_LEN)
731       rcount = MAX_READ_LEN;
732 #endif
733     nchars = read (desc, ptr, rcount);
734     if (nchars < 0)
735       {
736 #ifdef EINTR
737         if (errno == EINTR)
738           continue;
739 #endif
740         return nchars;
741       }
742     if (nchars == 0)
743       break;
744     ptr += nchars;
745     left -= nchars;
746   }
747   return len - left;
748 }
749
750 #ifdef VMS
751
752 /* Under VMS we need to fix up the "include" specification filename.
753
754    Rules for possible conversions
755
756         fullname                tried paths
757
758         name                    name
759         ./dir/name              [.dir]name
760         /dir/name               dir:name
761         /name                   [000000]name, name
762         dir/name                dir:[000000]name, dir:name, dir/name
763         dir1/dir2/name          dir1:[dir2]name, dir1:[000000.dir2]name
764         path:/name              path:[000000]name, path:name
765         path:/dir/name          path:[000000.dir]name, path:[dir]name
766         path:dir/name           path:[dir]name
767         [path]:[dir]name        [path.dir]name
768         path/[dir]name          [path.dir]name
769
770    The path:/name input is constructed when expanding <> includes. */
771
772
773 static void
774 hack_vms_include_specification (fullname)
775      char *fullname;
776 {
777   register char *basename, *unixname, *local_ptr, *first_slash;
778   int f, check_filename_before_returning, must_revert;
779   char Local[512];
780
781   check_filename_before_returning = 0;
782   must_revert = 0;
783   /* See if we can find a 1st slash. If not, there's no path information.  */
784   first_slash = index (fullname, '/');
785   if (first_slash == 0)
786     return 0;                           /* Nothing to do!!! */
787
788   /* construct device spec if none given.  */
789
790   if (index (fullname, ':') == 0)
791     {
792
793       /* If fullname has a slash, take it as device spec.  */
794
795       if (first_slash == fullname)
796         {
797           first_slash = index (fullname+1, '/');        /* 2nd slash ? */
798           if (first_slash)
799             *first_slash = ':';                         /* make device spec  */
800           for (basename = fullname; *basename != 0; basename++)
801             *basename = *(basename+1);                  /* remove leading slash  */
802         }
803       else if ((first_slash[-1] != '.')         /* keep ':/', './' */
804             && (first_slash[-1] != ':')
805             && (first_slash[-1] != ']'))        /* or a vms path  */
806         {
807           *first_slash = ':';
808         }
809       else if ((first_slash[1] == '[')          /* skip './' in './[dir'  */
810             && (first_slash[-1] == '.'))
811         fullname += 2;
812     }
813
814   /* Get part after first ':' (basename[-1] == ':')
815      or last '/' (basename[-1] == '/').  */
816
817   basename = base_name (fullname);
818
819   local_ptr = Local;                    /* initialize */
820
821   /* We are trying to do a number of things here.  First of all, we are
822      trying to hammer the filenames into a standard format, such that later
823      processing can handle them.
824      
825      If the file name contains something like [dir.], then it recognizes this
826      as a root, and strips the ".]".  Later processing will add whatever is
827      needed to get things working properly.
828      
829      If no device is specified, then the first directory name is taken to be
830      a device name (or a rooted logical).  */
831
832   /* Point to the UNIX filename part (which needs to be fixed!)
833      but skip vms path information.
834      [basename != fullname since first_slash != 0].  */
835
836   if ((basename[-1] == ':')             /* vms path spec.  */
837       || (basename[-1] == ']')
838       || (basename[-1] == '>'))
839     unixname = basename;
840   else
841     unixname = fullname;
842
843   if (*unixname == '/')
844     unixname++;
845
846   /* If the directory spec is not rooted, we can just copy
847      the UNIX filename part and we are done.  */
848
849   if (((basename - fullname) > 1)
850      && (  (basename[-1] == ']')
851         || (basename[-1] == '>')))
852     {
853       if (basename[-2] != '.')
854         {
855
856         /* The VMS part ends in a `]', and the preceding character is not a `.'.
857            -> PATH]:/name (basename = '/name', unixname = 'name')
858            We strip the `]', and then splice the two parts of the name in the
859            usual way.  Given the default locations for include files in cccp.c,
860            we will only use this code if the user specifies alternate locations
861            with the /include (-I) switch on the command line.  */
862
863           basename -= 1;        /* Strip "]" */
864           unixname--;           /* backspace */
865         }
866       else
867         {
868
869         /* The VMS part has a ".]" at the end, and this will not do.  Later
870            processing will add a second directory spec, and this would be a syntax
871            error.  Thus we strip the ".]", and thus merge the directory specs.
872            We also backspace unixname, so that it points to a '/'.  This inhibits the
873            generation of the 000000 root directory spec (which does not belong here
874            in this case).  */
875
876           basename -= 2;        /* Strip ".]" */
877           unixname--;           /* backspace */
878         }
879     }
880
881   else
882
883     {
884
885       /* We drop in here if there is no VMS style directory specification yet.
886          If there is no device specification either, we make the first dir a
887          device and try that.  If we do not do this, then we will be essentially
888          searching the users default directory (as if they did a #include "asdf.h").
889         
890          Then all we need to do is to push a '[' into the output string. Later
891          processing will fill this in, and close the bracket.  */
892
893       if ((unixname != fullname)        /* vms path spec found.  */
894          && (basename[-1] != ':'))
895         *local_ptr++ = ':';             /* dev not in spec.  take first dir */
896
897       *local_ptr++ = '[';               /* Open the directory specification */
898     }
899
900     if (unixname == fullname)           /* no vms dir spec.  */
901       {
902         must_revert = 1;
903         if ((first_slash != 0)          /* unix dir spec.  */
904             && (*unixname != '/')       /* not beginning with '/'  */
905             && (*unixname != '.'))      /* or './' or '../'  */
906           *local_ptr++ = '.';           /* dir is local !  */
907       }
908
909   /* at this point we assume that we have the device spec, and (at least
910      the opening "[" for a directory specification.  We may have directories
911      specified already.
912
913      If there are no other slashes then the filename will be
914      in the "root" directory.  Otherwise, we need to add
915      directory specifications.  */
916
917   if (index (unixname, '/') == 0)
918     {
919       /* if no directories specified yet and none are following.  */
920       if (local_ptr[-1] == '[')
921         {
922           /* Just add "000000]" as the directory string */
923           strcpy (local_ptr, "000000]");
924           local_ptr += strlen (local_ptr);
925           check_filename_before_returning = 1; /* we might need to fool with this later */
926         }
927     }
928   else
929     {
930
931       /* As long as there are still subdirectories to add, do them.  */
932       while (index (unixname, '/') != 0)
933         {
934           /* If this token is "." we can ignore it
935                if it's not at the beginning of a path.  */
936           if ((unixname[0] == '.') && (unixname[1] == '/'))
937             {
938               /* remove it at beginning of path.  */
939               if (  ((unixname == fullname)             /* no device spec  */
940                     && (fullname+2 != basename))        /* starts with ./ */
941                                                         /* or  */
942                  || ((basename[-1] == ':')              /* device spec  */
943                     && (unixname-1 == basename)))       /* and ./ afterwards  */
944                 *local_ptr++ = '.';                     /* make '[.' start of path.  */
945               unixname += 2;
946               continue;
947             }
948
949           /* Add a subdirectory spec. Do not duplicate "." */
950           if (  local_ptr[-1] != '.'
951              && local_ptr[-1] != '['
952              && local_ptr[-1] != '<')
953             *local_ptr++ = '.';
954
955           /* If this is ".." then the spec becomes "-" */
956           if (  (unixname[0] == '.')
957              && (unixname[1] == '.')
958              && (unixname[2] == '/'))
959             {
960               /* Add "-" and skip the ".." */
961               if ((local_ptr[-1] == '.')
962                   && (local_ptr[-2] == '['))
963                 local_ptr--;                    /* prevent [.-  */
964               *local_ptr++ = '-';
965               unixname += 3;
966               continue;
967             }
968
969           /* Copy the subdirectory */
970           while (*unixname != '/')
971             *local_ptr++= *unixname++;
972
973           unixname++;                   /* Skip the "/" */
974         }
975
976       /* Close the directory specification */
977       if (local_ptr[-1] == '.')         /* no trailing periods */
978         local_ptr--;
979
980       if (local_ptr[-1] == '[')         /* no dir needed */
981         local_ptr--;
982       else
983         *local_ptr++ = ']';
984     }
985
986   /* Now add the filename.  */
987
988   while (*unixname)
989     *local_ptr++ = *unixname++;
990   *local_ptr = 0;
991
992   /* Now append it to the original VMS spec.  */
993
994   strcpy ((must_revert==1)?fullname:basename, Local);
995
996   /* If we put a [000000] in the filename, try to open it first. If this fails,
997      remove the [000000], and return that name.  This provides flexibility
998      to the user in that they can use both rooted and non-rooted logical names
999      to point to the location of the file.  */
1000
1001   if (check_filename_before_returning)
1002     {
1003       f = open (fullname, O_RDONLY, 0666);
1004       if (f >= 0)
1005         {
1006           /* The file name is OK as it is, so return it as is.  */
1007           close (f);
1008           return 1;
1009         }
1010
1011       /* The filename did not work.  Try to remove the [000000] from the name,
1012          and return it.  */
1013
1014       basename = index (fullname, '[');
1015       local_ptr = index (fullname, ']') + 1;
1016       strcpy (basename, local_ptr);             /* this gets rid of it */
1017
1018     }
1019
1020   return 1;
1021 }
1022 #endif  /* VMS */