bugs in Jambase fixed; new vars added (for building Main in separate dirs); C++ vars...
[k8jam.git] / pathunix.c
bloba49d8a2c329ad8096d751aa03095cdaacce63de3
1 /*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
7 /*
8 * pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
10 * External routines:
12 * path_parse() - split a file name into dir/base/suffix/member
13 * path_build() - build a filename given dir/base/suffix/member
14 * path_parent() - make a PATHNAME point to its parent dir
16 * File_parse() and path_build() just manipuate a string and a structure;
17 * they do not make system calls.
19 * 04/08/94 (seiwald) - Coherent/386 support added.
20 * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
21 * 12/19/94 (mikem) - solaris string table insanity support
22 * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
23 * 02/14/95 (seiwald) - parse and build /xxx properly
24 * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
25 * should expect hdr searches to come up with strings
26 * like "thing/thing.h". So we need to test for "/" as
27 * well as "\" when parsing pathnames.
28 * 03/16/95 (seiwald) - fixed accursed typo on line 69.
29 * 05/03/96 (seiwald) - split from filent.c, fileunix.c
30 * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
31 * don't include the archive member name.
32 * 01/13/01 (seiwald) - turn off \ handling on UNIX, on by accident
33 * 11/04/02 (seiwald) - const-ing for string literals
36 # include "jam.h"
37 # include "pathsys.h"
39 # ifdef USE_PATHUNIX
42 * path_parse() - split a file name into dir/base/suffix/member
45 void path_parse (const char *file, PATHNAME *f) {
46 const char *p, *q;
47 const char *end;
49 memset((char *)f, 0, sizeof(*f));
51 /* Look for <grist> */
52 if (file[0] == '<' && (p = strchr(file, '>'))) {
53 f->f_grist.ptr = file;
54 f->f_grist.len = p - file;
55 file = p+1;
58 /* Look for dir/ */
59 p = strrchr(file, '/');
61 #if PATH_DELIM == '\\'
62 /* On NT, look for dir\ as well */
64 char *p1 = strrchr( file, '\\' );
65 p = p1 > p ? p1 : p;
67 #endif
69 if (p) {
70 f->f_dir.ptr = file;
71 f->f_dir.len = p - file;
72 /* Special case for / - dirname is /, not "" */
73 if (!f->f_dir.len) f->f_dir.len = 1;
74 #if PATH_DELIM == '\\'
75 /* Special case for D:/ - dirname is D:/, not "D:" */
76 if (f->f_dir.len == 2 && file[1] == ':') f->f_dir.len = 3;
77 #endif
78 file = p+1;
81 end = file+strlen(file);
83 /* Look for (member) */
84 if ((p = strchr(file, '(')) && end[-1] == ')') {
85 f->f_member.ptr = p+1;
86 f->f_member.len = end-p-2;
87 end = p;
90 /* Look for .suffix */
91 /* This would be memrchr() */
92 p = 0;
93 q = file;
94 while ((q = (char *)memchr(q, '.', end-q))) p = q++;
95 if (p) {
96 f->f_suffix.ptr = p;
97 f->f_suffix.len = end-p;
98 end = p;
101 /* Leaves base */
102 f->f_base.ptr = file;
103 f->f_base.len = end-file;
108 * path_build() - build a filename given dir/base/suffix/member
110 void path_build (PATHNAME *f, char *file, int binding) {
111 /* Start with the grist. If the current grist isn't */
112 /* surrounded by <>'s, add them. */
114 if (f->f_grist.len) {
115 if (f->f_grist.ptr[0] != '<') *file++ = '<';
116 memcpy(file, f->f_grist.ptr, f->f_grist.len);
117 file += f->f_grist.len;
118 if (file[-1] != '>') *file++ = '>';
121 /* Don't prepend root if it's . or directory is rooted */
122 #if PATH_DELIM == '/'
123 if (f->f_root.len && !(f->f_root.len == 1 && f->f_root.ptr[0] == '.') &&
124 !(f->f_dir.len && f->f_dir.ptr[0] == '/'))
125 #else /* unix */
126 if (f->f_root.len && !(f->f_root.len == 1 && f->f_root.ptr[0] == '.') &&
127 !(f->f_dir.len && f->f_dir.ptr[0] == '/') &&
128 !(f->f_dir.len && f->f_dir.ptr[0] == '\\') &&
129 !(f->f_dir.len && f->f_dir.ptr[1] == ':'))
130 #endif /* unix */
132 memcpy(file, f->f_root.ptr, f->f_root.len);
133 file += f->f_root.len;
134 *file++ = PATH_DELIM;
137 if (f->f_dir.len) {
138 memcpy(file, f->f_dir.ptr, f->f_dir.len);
139 file += f->f_dir.len;
142 /* UNIX: Put / between dir and file */
143 /* NT: Put \ between dir and file */
144 if (f->f_dir.len && (f->f_base.len || f->f_suffix.len)) {
145 /* UNIX: Special case for dir \ : don't add another \ */
146 /* NT: Special case for dir / : don't add another / */
147 #if PATH_DELIM == '\\'
148 if (!(f->f_dir.len == 3 && f->f_dir.ptr[1] == ':'))
149 #endif
150 if (!(f->f_dir.len == 1 && f->f_dir.ptr[0] == PATH_DELIM)) *file++ = PATH_DELIM;
153 if (f->f_base.len) {
154 memcpy(file, f->f_base.ptr, f->f_base.len);
155 file += f->f_base.len;
158 if (f->f_suffix.len) {
159 memcpy(file, f->f_suffix.ptr, f->f_suffix.len);
160 file += f->f_suffix.len;
163 if (f->f_member.len) {
164 *file++ = '(';
165 memcpy(file, f->f_member.ptr, f->f_member.len);
166 file += f->f_member.len;
167 *file++ = ')';
169 *file = 0;
174 * path_parent() - make a PATHNAME point to its parent dir
176 void path_parent (PATHNAME *f) {
177 /* just set everything else to nothing */
178 f->f_base.ptr = f->f_suffix.ptr = f->f_member.ptr = "";
179 f->f_base.len = f->f_suffix.len = f->f_member.len = 0;
183 # endif /* unix, NT, OS/2, AmigaOS */