1 /* Part of CPP library. (include file handling)
2 Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1998,
3 1999, 2000 Free Software Foundation, Inc.
4 Written by Per Bothner, 1994.
5 Based on CCCP program by Paul Rubin, June 1986
6 Adapted to ANSI C, Richard Stallman, Jan 1987
7 Split out of cpplib.c, Zack Weinberg, Oct 1998
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
29 #include "splay-tree.h"
32 # include <sys/mman.h>
33 # ifndef MMAP_THRESHOLD
34 # define MMAP_THRESHOLD 3 /* Minimum page count to mmap the file. */
37 #else /* No MMAP_FILE */
38 # undef MMAP_THRESHOLD
39 # define MMAP_THRESHOLD 0
46 #ifndef INCLUDE_LEN_FUDGE
47 # define INCLUDE_LEN_FUDGE 0
50 /* If errno is inspected immediately after a system call fails, it will be
51 nonzero, and no error number will ever be zero. */
62 /* Suppress warning about function macros used w/o arguments in traditional
63 C. It is unlikely that glibc's strcmp macro helps this file at all. */
66 static struct file_name_map *read_name_map
67 PARAMS ((cpp_reader *, const char *));
68 static char *read_filename_string PARAMS ((int, FILE *));
69 static char *remap_filename PARAMS ((cpp_reader *, char *,
70 struct file_name_list *));
71 static struct file_name_list *actual_directory
72 PARAMS ((cpp_reader *, const char *));
73 static struct include_file *find_include_file
74 PARAMS ((cpp_reader *, const char *,
75 struct file_name_list *));
76 static struct include_file *open_file PARAMS ((cpp_reader *, const char *));
77 static int read_include_file PARAMS ((cpp_reader *, struct include_file *));
78 static int stack_include_file PARAMS ((cpp_reader *, struct include_file *));
79 static void purge_cache PARAMS ((struct include_file *));
80 static void destroy_include_file_node PARAMS ((splay_tree_value));
81 static int report_missing_guard PARAMS ((splay_tree_node, void *));
84 static void hack_vms_include_specification PARAMS ((char *));
87 /* We use a splay tree to store information about all the include
88 files seen in this compilation. The key of each tree node is the
89 physical path to the file. The value is 0 if the file does not
90 exist, or a struct include_file pointer. */
93 destroy_include_file_node (v)
96 struct include_file *f = (struct include_file *)v;
100 free (f); /* The tree is registered with free to free f->name. */
105 _cpp_init_includes (pfile)
108 pfile->all_include_files
109 = splay_tree_new ((splay_tree_compare_fn) strcmp,
110 (splay_tree_delete_key_fn) free,
111 destroy_include_file_node);
115 _cpp_cleanup_includes (pfile)
118 splay_tree_delete (pfile->all_include_files);
121 /* Given a file name, look it up in the cache; if there is no entry,
122 create one with a non-NULL value (regardless of success in opening
123 the file). If the file doesn't exist or is inaccessible, this
124 entry is flagged so we don't attempt to open it again in the
125 future. If the file isn't open, open it.
127 Returns an include_file structure with an open file descriptor on
128 success, or NULL on failure. */
130 static struct include_file *
131 open_file (pfile, filename)
133 const char *filename;
136 struct include_file *file;
138 nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) filename);
142 file = (struct include_file *) nd->value;
144 /* Don't retry opening if we failed previously. */
148 /* -1 indicates a file we've opened previously, and since closed. */
154 file = xcnew (struct include_file);
155 file->name = xstrdup (filename);
156 splay_tree_insert (pfile->all_include_files,
157 (splay_tree_key) file->name,
158 (splay_tree_value) file);
161 /* We used to open files in nonblocking mode, but that caused more
162 problems than it solved. Do take care not to acquire a
163 controlling terminal by mistake (this can't happen on sane
164 systems, but paranoia is a virtue).
166 Use the three-argument form of open even though we aren't
167 specifying O_CREAT, to defend against broken system headers.
169 O_BINARY tells some runtime libraries (notably DJGPP) not to do
170 newline translation; we can handle DOS line breaks just fine
173 Special case: the empty string is translated to stdin. */
175 if (filename[0] == '\0')
178 file->fd = open (filename, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
180 if (file->fd != -1 && fstat (file->fd, &file->st) == 0)
182 /* Mark a regular, zero-length file never-reread now. */
183 if (S_ISREG (file->st.st_mode) && file->st.st_size == 0)
184 file->cmacro = NEVER_REREAD;
189 /* Don't issue an error message if the file doesn't exist. */
190 if (errno != ENOENT && errno != ENOTDIR)
191 cpp_error_from_errno (pfile, filename);
193 /* Create a negative node for this path, and return null. */
199 /* Place the file referenced by INC into a new buffer on PFILE's stack.
200 Return 1 if successful, 0 if not. */
203 stack_include_file (pfile, inc)
205 struct include_file *inc;
209 if (pfile->context->prev)
210 cpp_ice (pfile, "attempt to push file buffer with contexts stacked");
212 if (DO_NOT_REREAD (inc))
215 if (inc->buffer == NULL)
216 if (read_include_file (pfile, inc) == 0)
219 fp = cpp_push_buffer (pfile, NULL, 0);
223 /* Initialise controlling macro state. */
224 pfile->mi_state = MI_OUTSIDE;
225 pfile->mi_cmacro = 0;
228 fp->nominal_fname = inc->name;
229 fp->buf = inc->buffer;
230 fp->rlimit = fp->buf + inc->st.st_size;
233 fp->line_base = fp->buf;
235 /* The ->actual_dir field is only used when ignore_srcdir is not in effect;
237 if (!CPP_OPTION (pfile, ignore_srcdir))
238 fp->actual_dir = actual_directory (pfile, inc->name);
241 pfile->include_depth++;
242 pfile->input_stack_listing_current = 0;
244 if (pfile->cb.enter_file)
245 (*pfile->cb.enter_file) (pfile);
250 /* Read the file referenced by INC into the file cache.
252 If fd points to a plain file, we might be able to mmap it; we can
253 definitely allocate the buffer all at once. If fd is a pipe or
254 terminal, we can't do either. If fd is something weird, like a
255 block device or a directory, we don't want to read it at all.
257 Unfortunately, different systems use different st.st_mode values
258 for pipes: some have S_ISFIFO, some S_ISSOCK, some are buggy and
259 zero the entire struct stat except a couple fields. Hence we don't
260 even try to figure out what something is, except for plain files,
261 directories, and block devices.
263 FIXME: Flush file cache and try again if we run out of memory. */
266 read_include_file (pfile, inc)
268 struct include_file *inc;
270 ssize_t size, offset, count;
273 static int pagesize = -1;
276 if (S_ISREG (inc->st.st_mode))
278 /* off_t might have a wider range than ssize_t - in other words,
279 the max size of a file might be bigger than the address
280 space. We can't handle a file that large. (Anyone with
281 a single source file bigger than 2GB needs to rethink
282 their coding style.) Some systems (e.g. AIX 4.1) define
283 SSIZE_MAX to be much smaller than the actual range of the
284 type. Use INTTYPE_MAXIMUM unconditionally to ensure this
286 if (inc->st.st_size > INTTYPE_MAXIMUM (ssize_t))
288 cpp_error (pfile, "%s is too large", inc->name);
291 size = inc->st.st_size;
296 pagesize = getpagesize ();
298 if (size / pagesize >= MMAP_THRESHOLD)
300 buf = (U_CHAR *) mmap (0, size, PROT_READ, MAP_PRIVATE, inc->fd, 0);
301 if (buf == (U_CHAR *)-1)
308 buf = (U_CHAR *) xmalloc (size);
310 while (offset < size)
312 count = read (inc->fd, buf + offset, size - offset);
317 cpp_warning (pfile, "%s is shorter than expected", inc->name);
324 else if (S_ISBLK (inc->st.st_mode))
326 cpp_error (pfile, "%s is a block device", inc->name);
329 else if (S_ISDIR (inc->st.st_mode))
331 cpp_error (pfile, "%s is a directory", inc->name);
336 /* 8 kilobytes is a sensible starting size. It ought to be
337 bigger than the kernel pipe buffer, and it's definitely
338 bigger than the majority of C source files. */
341 buf = (U_CHAR *) xmalloc (size);
343 while ((count = read (inc->fd, buf + offset, size - offset)) > 0)
347 buf = xrealloc (buf, (size *= 2));
353 buf = xrealloc (buf, offset);
354 inc->st.st_size = offset;
363 cpp_error_from_errno (pfile, inc->name);
365 /* Do not try to read this file again. */
368 inc->cmacro = NEVER_REREAD;
374 struct include_file *inc;
380 munmap ((PTR) inc->buffer, inc->st.st_size);
383 free ((PTR) inc->buffer);
388 /* Return 1 if the file named by FNAME has been included before in
389 any context, 0 otherwise. */
391 cpp_included (pfile, fname)
395 struct file_name_list *path;
401 /* Just look it up. */
402 nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) fname);
403 return (nd && nd->value);
406 /* Search directory path for the file. */
407 name = (char *) alloca (strlen (fname) + pfile->max_include_len
408 + 2 + INCLUDE_LEN_FUDGE);
409 for (path = CPP_OPTION (pfile, quote_include); path; path = path->next)
411 memcpy (name, path->name, path->nlen);
412 name[path->nlen] = '/';
413 strcpy (&name[path->nlen+1], fname);
414 _cpp_simplify_pathname (name);
415 if (CPP_OPTION (pfile, remap))
416 name = remap_filename (pfile, name, path);
418 nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name);
425 /* Search for include file FNAME in the include chain starting at
426 SEARCH_START. Return 0 if there is no such file (or it's un-openable),
427 otherwise an include_file structure. */
429 static struct include_file *
430 find_include_file (pfile, fname, search_start)
433 struct file_name_list *search_start;
435 struct file_name_list *path;
437 struct include_file *file;
440 return open_file (pfile, fname);
442 /* Search directory path for the file. */
443 name = (char *) alloca (strlen (fname) + pfile->max_include_len
444 + 2 + INCLUDE_LEN_FUDGE);
445 for (path = search_start; path; path = path->next)
447 memcpy (name, path->name, path->nlen);
448 name[path->nlen] = '/';
449 strcpy (&name[path->nlen+1], fname);
450 _cpp_simplify_pathname (name);
451 if (CPP_OPTION (pfile, remap))
452 name = remap_filename (pfile, name, path);
454 file = open_file (pfile, name);
457 file->sysp = path->sysp;
458 file->foundhere = path;
465 /* #line uses this to save artificial file names. We have to stat the
466 file because an all_include_files entry is always either + or -,
467 there's no 'I don't know' value. */
469 _cpp_fake_include (pfile, fname)
474 struct include_file *file;
477 file = find_include_file (pfile, fname, CPP_OPTION (pfile, quote_include));
488 name = xstrdup (fname);
489 _cpp_simplify_pathname (name);
491 /* We cannot just blindly insert a node, because there's still the
492 chance that the node already exists but isn't on the search path. */
493 nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) name);
497 return (const char *) nd->key;
500 file = xcnew (struct include_file);
503 splay_tree_insert (pfile->all_include_files, (splay_tree_key) name,
504 (splay_tree_value) file);
509 /* Not everyone who wants to set system-header-ness on a buffer can
510 see the details of struct include_file. This is an exported interface
511 because fix-header needs it. */
513 cpp_make_system_header (pfile, pbuf, flag)
518 if (flag < 0 || flag > 2)
519 cpp_ice (pfile, "cpp_make_system_header: bad flag %d\n", flag);
521 cpp_ice (pfile, "cpp_make_system_header called on non-file buffer");
523 pbuf->inc->sysp = flag;
527 cpp_syshdr_flags (pfile, pbuf)
528 cpp_reader *pfile ATTRIBUTE_UNUSED;
531 #ifndef NO_IMPLICIT_EXTERN_C
532 if (CPP_OPTION (pfile, cplusplus) && pbuf->inc->sysp == 2)
540 /* Report on all files that might benefit from a multiple include guard.
543 _cpp_report_missing_guards (pfile)
547 splay_tree_foreach (pfile->all_include_files, report_missing_guard,
552 report_missing_guard (n, b)
556 struct include_file *f = (struct include_file *) n->value;
557 int *bannerp = (int *)b;
559 if (f && f->cmacro == 0 && f->include_count == 1)
563 fputs (_("Multiple include guards may be useful for:\n"), stderr);
566 fputs (f->name, stderr);
572 #define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth))
574 _cpp_execute_include (pfile, header, no_reinclude, search_start)
576 const cpp_token *header;
578 struct file_name_list *search_start;
580 unsigned int len = header->val.str.len;
581 unsigned int angle_brackets = header->type == CPP_HEADER_NAME;
582 struct include_file *inc;
585 fname = alloca (len + 1);
586 memcpy (fname, header->val.str.text, len);
592 search_start = CPP_OPTION (pfile, bracket_include);
593 else if (CPP_OPTION (pfile, ignore_srcdir))
594 search_start = CPP_OPTION (pfile, quote_include);
596 search_start = CPP_BUFFER (pfile)->actual_dir;
600 cpp_error (pfile, "No include path in which to find %s", fname);
605 inc = find_include_file (pfile, fname, search_start);
609 /* For -M, add the file to the dependencies on its first inclusion. */
610 if (!inc->include_count && PRINT_THIS_DEP (pfile, angle_brackets))
611 deps_add_dep (pfile->deps, inc->name);
612 inc->include_count++;
614 /* Actually process the file. */
615 if (stack_include_file (pfile, inc))
618 pfile->system_include_depth++;
621 inc->cmacro = NEVER_REREAD;
623 /* Handle -H option. */
624 if (CPP_OPTION (pfile, print_include_names))
626 cpp_buffer *fp = CPP_BUFFER (pfile);
627 while ((fp = CPP_PREV_BUFFER (fp)) != NULL)
629 fprintf (stderr, " %s\n", inc->name);
635 if (CPP_OPTION (pfile, print_deps_missing_files)
636 && PRINT_THIS_DEP (pfile, angle_brackets))
639 deps_add_dep (pfile->deps, fname);
643 struct file_name_list *ptr;
644 /* If requested as a system header, assume it belongs in
645 the first system header directory. */
646 if (CPP_OPTION (pfile, bracket_include))
647 ptr = CPP_OPTION (pfile, bracket_include);
649 ptr = CPP_OPTION (pfile, quote_include);
651 p = (char *) alloca (strlen (ptr->name)
652 + strlen (fname) + 2);
653 if (*ptr->name != '\0')
655 strcpy (p, ptr->name);
659 _cpp_simplify_pathname (p);
660 deps_add_dep (pfile->deps, p);
663 /* If -M was specified, and this header file won't be added to
664 the dependency list, then don't count this as an error,
665 because we can still produce correct output. Otherwise, we
666 can't produce correct output, because there may be
667 dependencies we need inside the missing file, and we don't
668 know what directory this missing file exists in. */
669 else if (CPP_PRINT_DEPS (pfile)
670 && ! PRINT_THIS_DEP (pfile, angle_brackets))
671 cpp_warning (pfile, "No include path in which to find %s", fname);
673 cpp_error_from_errno (pfile, fname);
676 /* Locate file F, and determine whether it is newer than PFILE. Return -1,
677 if F cannot be located or dated, 1, if it is newer and 0 if older. */
679 _cpp_compare_file_date (pfile, f)
683 unsigned int len = f->val.str.len;
685 struct file_name_list *search_start;
686 struct include_file *inc;
688 if (f->type == CPP_HEADER_NAME)
689 search_start = CPP_OPTION (pfile, bracket_include);
690 else if (CPP_OPTION (pfile, ignore_srcdir))
691 search_start = CPP_OPTION (pfile, quote_include);
693 search_start = CPP_BUFFER (pfile)->actual_dir;
695 fname = alloca (len + 1);
696 memcpy (fname, f->val.str.text, len);
698 inc = find_include_file (pfile, fname, search_start);
708 return inc->st.st_mtime > CPP_BUFFER (pfile)->inc->st.st_mtime;
712 /* Push an input buffer and load it up with the contents of FNAME.
713 If FNAME is "" or NULL, read standard input. */
715 cpp_read_file (pfile, fname)
719 struct include_file *f;
724 f = open_file (pfile, fname);
728 cpp_error_from_errno (pfile, fname);
732 /* Return success for zero-length files. */
733 if (DO_NOT_REREAD (f))
736 return stack_include_file (pfile, f);
739 /* Do appropriate cleanup when a file buffer is popped off the input
742 _cpp_pop_file_buffer (pfile, buf)
746 struct include_file *inc = buf->inc;
748 if (pfile->system_include_depth)
749 pfile->system_include_depth--;
750 if (pfile->include_depth)
751 pfile->include_depth--;
752 pfile->input_stack_listing_current = 0;
754 /* Record the inclusion-preventing macro and its definedness. */
755 if (pfile->mi_state == MI_OUTSIDE && inc->cmacro != NEVER_REREAD)
757 /* This could be NULL meaning no controlling macro. */
758 inc->cmacro = pfile->mi_cmacro;
762 /* Invalidate control macros in the #including file. */
763 pfile->mi_state = MI_FAILED;
766 if (inc->refcnt == 0 && DO_NOT_REREAD (inc))
770 /* The file_name_map structure holds a mapping of file names for a
771 particular directory. This mapping is read from the file named
772 FILE_NAME_MAP_FILE in that directory. Such a file can be used to
773 map filenames on a file system with severe filename restrictions,
774 such as DOS. The format of the file name map file is just a series
775 of lines with two tokens on each line. The first token is the name
776 to map, and the second token is the actual name to use. */
780 struct file_name_map *map_next;
785 #define FILE_NAME_MAP_FILE "header.gcc"
787 /* Read a space delimited string of unlimited length from a stdio
791 read_filename_string (ch, f)
799 set = alloc = xmalloc (len + 1);
803 while ((ch = getc (f)) != EOF && ! is_space(ch))
805 if (set - alloc == len)
808 alloc = xrealloc (alloc, len + 1);
809 set = alloc + len / 2;
819 /* This structure holds a linked list of file name maps, one per directory. */
821 struct file_name_map_list
823 struct file_name_map_list *map_list_next;
825 struct file_name_map *map_list_map;
828 /* Read the file name map file for DIRNAME. */
830 static struct file_name_map *
831 read_name_map (pfile, dirname)
835 register struct file_name_map_list *map_list_ptr;
839 for (map_list_ptr = CPP_OPTION (pfile, map_list); map_list_ptr;
840 map_list_ptr = map_list_ptr->map_list_next)
841 if (! strcmp (map_list_ptr->map_list_name, dirname))
842 return map_list_ptr->map_list_map;
844 map_list_ptr = ((struct file_name_map_list *)
845 xmalloc (sizeof (struct file_name_map_list)));
846 map_list_ptr->map_list_name = xstrdup (dirname);
847 map_list_ptr->map_list_map = NULL;
849 name = (char *) alloca (strlen (dirname) + strlen (FILE_NAME_MAP_FILE) + 2);
850 strcpy (name, dirname);
853 strcat (name, FILE_NAME_MAP_FILE);
854 f = fopen (name, "r");
856 map_list_ptr->map_list_map = (struct file_name_map *)-1;
860 int dirlen = strlen (dirname);
862 while ((ch = getc (f)) != EOF)
865 struct file_name_map *ptr;
869 from = read_filename_string (ch, f);
870 while ((ch = getc (f)) != EOF && is_hspace(ch))
872 to = read_filename_string (ch, f);
874 ptr = ((struct file_name_map *)
875 xmalloc (sizeof (struct file_name_map)));
876 ptr->map_from = from;
878 /* Make the real filename absolute. */
883 ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
884 strcpy (ptr->map_to, dirname);
885 ptr->map_to[dirlen] = '/';
886 strcpy (ptr->map_to + dirlen + 1, to);
890 ptr->map_next = map_list_ptr->map_list_map;
891 map_list_ptr->map_list_map = ptr;
893 while ((ch = getc (f)) != '\n')
900 map_list_ptr->map_list_next = CPP_OPTION (pfile, map_list);
901 CPP_OPTION (pfile, map_list) = map_list_ptr;
903 return map_list_ptr->map_list_map;
906 /* Remap NAME based on the file_name_map (if any) for LOC. */
909 remap_filename (pfile, name, loc)
912 struct file_name_list *loc;
914 struct file_name_map *map;
915 const char *from, *p, *dir;
918 loc->name_map = read_name_map (pfile,
922 if (loc->name_map == (struct file_name_map *)-1)
925 from = name + strlen (loc->name) + 1;
927 for (map = loc->name_map; map; map = map->map_next)
928 if (!strcmp (map->map_from, from))
931 /* Try to find a mapping file for the particular directory we are
932 looking in. Thus #include <sys/types.h> will look up sys/types.h
933 in /usr/include/header.gcc and look up types.h in
934 /usr/include/sys/header.gcc. */
935 p = strrchr (name, '/');
939 && strlen (loc->name) == (size_t) (p - name)
940 && !strncmp (loc->name, name, p - name))
941 /* FILENAME is in SEARCHPTR, which we've already checked. */
951 char * newdir = (char *) alloca (p - name + 1);
952 memcpy (newdir, name, p - name);
953 newdir[p - name] = '\0';
958 for (map = read_name_map (pfile, dir); map; map = map->map_next)
959 if (! strcmp (map->map_from, name))
965 /* Given a path FNAME, extract the directory component and place it
966 onto the actual_dirs list. Return a pointer to the allocated
967 file_name_list structure. These structures are used to implement
968 current-directory "" include searching. */
970 static struct file_name_list *
971 actual_directory (pfile, fname)
975 char *last_slash, *dir;
977 struct file_name_list *x;
979 dir = xstrdup (fname);
980 last_slash = strrchr (dir, '/');
983 if (last_slash == dir)
986 last_slash[1] = '\0';
990 dlen = last_slash - dir;
1001 if (dlen > pfile->max_include_len)
1002 pfile->max_include_len = dlen;
1004 for (x = pfile->actual_dirs; x; x = x->alloc)
1005 if (!strcmp (x->name, dir))
1011 /* Not found, make a new one. */
1012 x = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
1015 x->next = CPP_OPTION (pfile, quote_include);
1016 x->alloc = pfile->actual_dirs;
1017 x->sysp = CPP_BUFFER (pfile)->inc->sysp;
1020 pfile->actual_dirs = x;
1024 /* Simplify a path name in place, deleting redundant components. This
1025 reduces OS overhead and guarantees that equivalent paths compare
1026 the same (modulo symlinks).
1029 foo/bar/../quux foo/quux
1033 //quux //quux (POSIX allows leading // as a namespace escape)
1035 Guarantees no trailing slashes. All transforms reduce the length
1039 _cpp_simplify_pathname (path)
1046 #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
1047 /* Convert all backslashes to slashes. */
1048 for (from = path; *from; from++)
1049 if (*from == '\\') *from = '/';
1051 /* Skip over leading drive letter if present. */
1052 if (ISALPHA (path[0]) && path[1] == ':')
1053 from = to = &path[2];
1060 /* Remove redundant initial /s. */
1069 /* 3 or more initial /s are equivalent to 1 /. */
1070 while (*++from == '/');
1072 /* On some hosts // differs from /; Posix allows this. */
1080 while (*from == '/')
1083 if (from[0] == '.' && from[1] == '/')
1085 else if (from[0] == '.' && from[1] == '\0')
1087 else if (from[0] == '.' && from[1] == '.' && from[2] == '/')
1104 while (to > base && *to != '/') to--;
1110 else if (from[0] == '.' && from[1] == '.' && from[2] == '\0')
1123 while (to > base && *to != '/') to--;
1130 /* Copy this component and trailing /, if any. */
1131 while ((*to++ = *from++) != '/')
1143 /* Trim trailing slash */
1144 if (to[0] == '/' && (!absolute || to > path+1))
1147 /* Change the empty string to "." so that stat() on the result
1148 will always work. */
1157 /* It is not clear when this should be used if at all, so I've
1158 disabled it until someone who understands VMS can look at it. */
1161 /* Under VMS we need to fix up the "include" specification filename.
1163 Rules for possible conversions
1165 fullname tried paths
1168 ./dir/name [.dir]name
1170 /name [000000]name, name
1171 dir/name dir:[000000]name, dir:name, dir/name
1172 dir1/dir2/name dir1:[dir2]name, dir1:[000000.dir2]name
1173 path:/name path:[000000]name, path:name
1174 path:/dir/name path:[000000.dir]name, path:[dir]name
1175 path:dir/name path:[dir]name
1176 [path]:[dir]name [path.dir]name
1177 path/[dir]name [path.dir]name
1179 The path:/name input is constructed when expanding <> includes. */
1183 hack_vms_include_specification (fullname)
1186 register char *basename, *unixname, *local_ptr, *first_slash;
1187 int f, check_filename_before_returning, must_revert;
1190 check_filename_before_returning = 0;
1192 /* See if we can find a 1st slash. If not, there's no path information. */
1193 first_slash = strchr (fullname, '/');
1194 if (first_slash == 0)
1195 return 0; /* Nothing to do!!! */
1197 /* construct device spec if none given. */
1199 if (strchr (fullname, ':') == 0)
1202 /* If fullname has a slash, take it as device spec. */
1204 if (first_slash == fullname)
1206 first_slash = strchr (fullname + 1, '/'); /* 2nd slash ? */
1208 *first_slash = ':'; /* make device spec */
1209 for (basename = fullname; *basename != 0; basename++)
1210 *basename = *(basename+1); /* remove leading slash */
1212 else if ((first_slash[-1] != '.') /* keep ':/', './' */
1213 && (first_slash[-1] != ':')
1214 && (first_slash[-1] != ']')) /* or a vms path */
1218 else if ((first_slash[1] == '[') /* skip './' in './[dir' */
1219 && (first_slash[-1] == '.'))
1223 /* Get part after first ':' (basename[-1] == ':')
1224 or last '/' (basename[-1] == '/'). */
1226 basename = base_name (fullname);
1228 local_ptr = Local; /* initialize */
1230 /* We are trying to do a number of things here. First of all, we are
1231 trying to hammer the filenames into a standard format, such that later
1232 processing can handle them.
1234 If the file name contains something like [dir.], then it recognizes this
1235 as a root, and strips the ".]". Later processing will add whatever is
1236 needed to get things working properly.
1238 If no device is specified, then the first directory name is taken to be
1239 a device name (or a rooted logical). */
1241 /* Point to the UNIX filename part (which needs to be fixed!)
1242 but skip vms path information.
1243 [basename != fullname since first_slash != 0]. */
1245 if ((basename[-1] == ':') /* vms path spec. */
1246 || (basename[-1] == ']')
1247 || (basename[-1] == '>'))
1248 unixname = basename;
1250 unixname = fullname;
1252 if (*unixname == '/')
1255 /* If the directory spec is not rooted, we can just copy
1256 the UNIX filename part and we are done. */
1258 if (((basename - fullname) > 1)
1259 && ( (basename[-1] == ']')
1260 || (basename[-1] == '>')))
1262 if (basename[-2] != '.')
1265 /* The VMS part ends in a `]', and the preceding character is not a `.'.
1266 -> PATH]:/name (basename = '/name', unixname = 'name')
1267 We strip the `]', and then splice the two parts of the name in the
1268 usual way. Given the default locations for include files,
1269 we will only use this code if the user specifies alternate locations
1270 with the /include (-I) switch on the command line. */
1272 basename -= 1; /* Strip "]" */
1273 unixname--; /* backspace */
1278 /* The VMS part has a ".]" at the end, and this will not do. Later
1279 processing will add a second directory spec, and this would be a syntax
1280 error. Thus we strip the ".]", and thus merge the directory specs.
1281 We also backspace unixname, so that it points to a '/'. This inhibits the
1282 generation of the 000000 root directory spec (which does not belong here
1285 basename -= 2; /* Strip ".]" */
1286 unixname--; /* backspace */
1294 /* We drop in here if there is no VMS style directory specification yet.
1295 If there is no device specification either, we make the first dir a
1296 device and try that. If we do not do this, then we will be essentially
1297 searching the users default directory (as if they did a #include "asdf.h").
1299 Then all we need to do is to push a '[' into the output string. Later
1300 processing will fill this in, and close the bracket. */
1302 if ((unixname != fullname) /* vms path spec found. */
1303 && (basename[-1] != ':'))
1304 *local_ptr++ = ':'; /* dev not in spec. take first dir */
1306 *local_ptr++ = '['; /* Open the directory specification */
1309 if (unixname == fullname) /* no vms dir spec. */
1312 if ((first_slash != 0) /* unix dir spec. */
1313 && (*unixname != '/') /* not beginning with '/' */
1314 && (*unixname != '.')) /* or './' or '../' */
1315 *local_ptr++ = '.'; /* dir is local ! */
1318 /* at this point we assume that we have the device spec, and (at least
1319 the opening "[" for a directory specification. We may have directories
1322 If there are no other slashes then the filename will be
1323 in the "root" directory. Otherwise, we need to add
1324 directory specifications. */
1326 if (strchr (unixname, '/') == 0)
1328 /* if no directories specified yet and none are following. */
1329 if (local_ptr[-1] == '[')
1331 /* Just add "000000]" as the directory string */
1332 strcpy (local_ptr, "000000]");
1333 local_ptr += strlen (local_ptr);
1334 check_filename_before_returning = 1; /* we might need to fool with this later */
1340 /* As long as there are still subdirectories to add, do them. */
1341 while (strchr (unixname, '/') != 0)
1343 /* If this token is "." we can ignore it
1344 if it's not at the beginning of a path. */
1345 if ((unixname[0] == '.') && (unixname[1] == '/'))
1347 /* remove it at beginning of path. */
1348 if ( ((unixname == fullname) /* no device spec */
1349 && (fullname+2 != basename)) /* starts with ./ */
1351 || ((basename[-1] == ':') /* device spec */
1352 && (unixname-1 == basename))) /* and ./ afterwards */
1353 *local_ptr++ = '.'; /* make '[.' start of path. */
1358 /* Add a subdirectory spec. Do not duplicate "." */
1359 if ( local_ptr[-1] != '.'
1360 && local_ptr[-1] != '['
1361 && local_ptr[-1] != '<')
1364 /* If this is ".." then the spec becomes "-" */
1365 if ( (unixname[0] == '.')
1366 && (unixname[1] == '.')
1367 && (unixname[2] == '/'))
1369 /* Add "-" and skip the ".." */
1370 if ((local_ptr[-1] == '.')
1371 && (local_ptr[-2] == '['))
1372 local_ptr--; /* prevent [.- */
1378 /* Copy the subdirectory */
1379 while (*unixname != '/')
1380 *local_ptr++= *unixname++;
1382 unixname++; /* Skip the "/" */
1385 /* Close the directory specification */
1386 if (local_ptr[-1] == '.') /* no trailing periods */
1389 if (local_ptr[-1] == '[') /* no dir needed */
1395 /* Now add the filename. */
1398 *local_ptr++ = *unixname++;
1401 /* Now append it to the original VMS spec. */
1403 strcpy ((must_revert==1)?fullname:basename, Local);
1405 /* If we put a [000000] in the filename, try to open it first. If this fails,
1406 remove the [000000], and return that name. This provides flexibility
1407 to the user in that they can use both rooted and non-rooted logical names
1408 to point to the location of the file. */
1410 if (check_filename_before_returning)
1412 f = open (fullname, O_RDONLY|O_NONBLOCK);
1415 /* The file name is OK as it is, so return it as is. */
1420 /* The filename did not work. Try to remove the [000000] from the name,
1423 basename = strchr (fullname, '[');
1424 local_ptr = strchr (fullname, ']') + 1;
1425 strcpy (basename, local_ptr); /* this gets rid of it */