2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * This file is part of Jam - see jam.c for Copyright information.
8 * pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
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
42 * path_parse() - split a file name into dir/base/suffix/member
45 void path_parse (const char *file
, PATHNAME
*f
) {
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
;
59 p
= strrchr(file
, '/');
61 #if PATH_DELIM == '\\'
62 /* On NT, look for dir\ as well */
64 char *p1
= strrchr( 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;
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;
90 /* Look for .suffix */
91 /* This would be memrchr() */
94 while ((q
= (char *)memchr(q
, '.', end
-q
))) p
= q
++;
97 f
->f_suffix
.len
= end
-p
;
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] == '/'))
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] == ':'))
132 memcpy(file
, f
->f_root
.ptr
, f
->f_root
.len
);
133 file
+= f
->f_root
.len
;
134 *file
++ = PATH_DELIM
;
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] == ':'))
150 if (!(f
->f_dir
.len
== 1 && f
->f_dir
.ptr
[0] == PATH_DELIM
)) *file
++ = PATH_DELIM
;
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
) {
165 memcpy(file
, f
->f_member
.ptr
, f
->f_member
.len
);
166 file
+= f
->f_member
.len
;
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 */