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
53 memset( (char *)f
, 0, sizeof( *f
) );
55 /* Look for <grist> */
57 if( file
[0] == '<' && ( p
= strchr( file
, '>' ) ) )
59 f
->f_grist
.ptr
= file
;
60 f
->f_grist
.len
= p
- file
;
66 p
= strrchr( file
, '/' );
68 # if PATH_DELIM == '\\'
69 /* On NT, look for dir\ as well */
71 char *p1
= strrchr( file
, '\\' );
79 f
->f_dir
.len
= p
- file
;
81 /* Special case for / - dirname is /, not "" */
86 # if PATH_DELIM == '\\'
87 /* Special case for D:/ - dirname is D:/, not "D:" */
89 if( f
->f_dir
.len
== 2 && file
[1] == ':' )
96 end
= file
+ strlen( file
);
98 /* Look for (member) */
100 if( ( p
= strchr( file
, '(' ) ) && end
[-1] == ')' )
102 f
->f_member
.ptr
= p
+ 1;
103 f
->f_member
.len
= end
- p
- 2;
107 /* Look for .suffix */
108 /* This would be memrchr() */
113 while ((q
= (char *)memchr(q
, '.', end
-q
)))
119 f
->f_suffix
.len
= end
- p
;
125 f
->f_base
.ptr
= file
;
126 f
->f_base
.len
= end
- file
;
130 * path_build() - build a filename given dir/base/suffix/member
139 /* Start with the grist. If the current grist isn't */
140 /* surrounded by <>'s, add them. */
144 if( f
->f_grist
.ptr
[0] != '<' ) *file
++ = '<';
145 memcpy( file
, f
->f_grist
.ptr
, f
->f_grist
.len
);
146 file
+= f
->f_grist
.len
;
147 if( file
[-1] != '>' ) *file
++ = '>';
150 /* Don't prepend root if it's . or directory is rooted */
152 # if PATH_DELIM == '/'
155 && !( f
->f_root
.len
== 1 && f
->f_root
.ptr
[0] == '.' )
156 && !( f
->f_dir
.len
&& f
->f_dir
.ptr
[0] == '/' ) )
161 && !( f
->f_root
.len
== 1 && f
->f_root
.ptr
[0] == '.' )
162 && !( f
->f_dir
.len
&& f
->f_dir
.ptr
[0] == '/' )
163 && !( f
->f_dir
.len
&& f
->f_dir
.ptr
[0] == '\\' )
164 && !( f
->f_dir
.len
&& f
->f_dir
.ptr
[1] == ':' ) )
169 memcpy( file
, f
->f_root
.ptr
, f
->f_root
.len
);
170 file
+= f
->f_root
.len
;
171 *file
++ = PATH_DELIM
;
176 memcpy( file
, f
->f_dir
.ptr
, f
->f_dir
.len
);
177 file
+= f
->f_dir
.len
;
180 /* UNIX: Put / between dir and file */
181 /* NT: Put \ between dir and file */
183 if( f
->f_dir
.len
&& ( f
->f_base
.len
|| f
->f_suffix
.len
) )
185 /* UNIX: Special case for dir \ : don't add another \ */
186 /* NT: Special case for dir / : don't add another / */
188 # if PATH_DELIM == '\\'
189 if( !( f
->f_dir
.len
== 3 && f
->f_dir
.ptr
[1] == ':' ) )
191 if( !( f
->f_dir
.len
== 1 && f
->f_dir
.ptr
[0] == PATH_DELIM
) )
192 *file
++ = PATH_DELIM
;
197 memcpy( file
, f
->f_base
.ptr
, f
->f_base
.len
);
198 file
+= f
->f_base
.len
;
201 if( f
->f_suffix
.len
)
203 memcpy( file
, f
->f_suffix
.ptr
, f
->f_suffix
.len
);
204 file
+= f
->f_suffix
.len
;
207 if( f
->f_member
.len
)
210 memcpy( file
, f
->f_member
.ptr
, f
->f_member
.len
);
211 file
+= f
->f_member
.len
;
218 * path_parent() - make a PATHNAME point to its parent dir
222 path_parent( PATHNAME
*f
)
224 /* just set everything else to nothing */
228 f
->f_member
.ptr
= "";
235 # endif /* unix, NT, OS/2, AmigaOS */