codec cleanup
[platform/upstream/boost-jam.git] / pathmac.c
1 /*
2  * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3  *
4  * This file is part of Jam - see jam.c for Copyright information.
5  */
6
7 /*  This file is ALSO:
8  *  Copyright 2001-2004 David Abrahams.
9  *  Distributed under the Boost Software License, Version 1.0.
10  *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
11  */
12
13 # include "jam.h"
14 # include "pathsys.h"
15
16 # ifdef OS_MAC
17
18 # define DELIM ':'
19
20 /*
21  * pathunix.c - manipulate file names on UNIX, NT, OS2
22  *
23  * External routines:
24  *
25  *  path_parse() - split a file name into dir/base/suffix/member
26  *  path_build() - build a filename given dir/base/suffix/member
27  *  path_parent() - make a PATHNAME point to its parent dir
28  *
29  * File_parse() and path_build() just manipuate a string and a structure;
30  * they do not make system calls.
31  *
32  * 04/08/94 (seiwald) - Coherent/386 support added.
33  * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
34  * 12/19/94 (mikem) - solaris string table insanity support
35  * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
36  * 02/14/95 (seiwald) - parse and build /xxx properly
37  * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
38  *                    should expect hdr searches to come up with strings
39  *                    like "thing/thing.h". So we need to test for "/" as
40  *                    well as "\" when parsing pathnames.
41  * 03/16/95 (seiwald) - fixed accursed typo on line 69.
42  * 05/03/96 (seiwald) - split from filent.c, fileunix.c
43  * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
44  *            don't include the archive member name.
45  * 01/10/01 (seiwald) - path_parse now strips the trailing : from the
46  *          directory name, unless the directory name is all
47  *          :'s, so that $(d:P) works.
48  */
49
50 /*
51  * path_parse() - split a file name into dir/base/suffix/member
52  */
53
54 void
55 path_parse(
56     char    *file,
57     PATHNAME *f )
58 {
59     char *p, *q;
60     char *end;
61
62     memset( (char *)f, 0, sizeof( *f ) );
63
64     /* Look for <grist> */
65
66     if ( file[0] == '<' && ( p = strchr( file, '>' ) ) )
67     {
68         f->f_grist.ptr = file;
69         f->f_grist.len = p - file;
70         file = p + 1;
71     }
72
73     /* Look for dir: */
74
75     if ( p = strrchr( file, DELIM ) )
76     {
77         f->f_dir.ptr = file;
78         f->f_dir.len = p - file;
79         file = p + 1;
80
81         /* All :'s? Include last : as part of directory name */
82
83         while ( ( p > f->f_dir.ptr ) && ( *--p == DELIM ) );
84
85         if ( p == f->f_dir.ptr )
86             ++f->f_dir.len;
87     }
88
89     end = file + strlen( file );
90
91     /* Look for (member). */
92
93     if ( ( p = strchr( file, '(' ) ) && ( end[-1] == ')' ) )
94     {
95         f->f_member.ptr = p + 1;
96         f->f_member.len = end - p - 2;
97         end = p;
98     }
99
100     /* Look for .suffix */
101     /* This would be memrchr() */
102
103     p = 0;
104     q = file;
105
106     while ( q = memchr( q, '.', end - q ) )
107         p = q++;
108
109     if ( p )
110     {
111         f->f_suffix.ptr = p;
112         f->f_suffix.len = end - p;
113         end = p;
114     }
115
116     /* Leaves base */
117
118     f->f_base.ptr = file;
119     f->f_base.len = end - file;
120 }
121
122 /*
123  * path_build() - build a filename given dir/base/suffix/member.
124  */
125
126 # define DIR_EMPTY  0   /* "" */
127 # define DIR_DOT    1   /* : */
128 # define DIR_DOTDOT 2   /* :: */
129 # define DIR_ABS    3   /* dira:dirb: */
130 # define DIR_REL    4   /* :dira:dirb: */
131
132 # define G_DIR      0   /* take dir */
133 # define G_ROOT     1   /* take root */
134 # define G_CAT      2   /* prepend root to dir */
135 # define G_DTDR     3   /* :: of rel dir */
136 # define G_DDDD     4   /* make it ::: (../..) */
137 # define G_MT       5   /* leave it empty */
138
139 char grid[5][5] = {
140 /*      EMPTY   DOT DOTDOT  ABS REL */
141 /* EMPTY */   { G_MT,   G_DIR,  G_DIR,  G_DIR,  G_DIR },
142 /* DOT */     { G_ROOT, G_DIR,  G_DIR,  G_DIR,  G_DIR },
143 /* DOTDOT */  { G_ROOT, G_ROOT, G_DDDD, G_DIR,  G_DTDR },
144 /* ABS */     { G_ROOT, G_ROOT, G_ROOT, G_DIR,  G_CAT },
145 /* REL */     { G_ROOT, G_ROOT, G_ROOT, G_DIR,  G_CAT }
146 };
147
148 static int file_flags( char * ptr, int len )
149 {
150     if ( !len )
151         return DIR_EMPTY;
152     if ( ( len == 1 ) && ( ptr[0] == DELIM ) )
153         return DIR_DOT;
154     if ( ( len == 2 ) && ( ptr[0] == DELIM ) && ( ptr[1] == DELIM ) )
155         return DIR_DOTDOT;
156     if ( ptr[0] == DELIM )
157         return DIR_REL;
158     return DIR_ABS;
159 }
160
161
162 void path_build( PATHNAME * f, string * file, int binding )
163 {
164     int dflag;
165     int rflag;
166     int act;
167
168     file_build1( f, file );
169
170     /* Combine root & directory, according to the grid. */
171
172     dflag = file_flags( f->f_dir.ptr, f->f_dir.len );
173     rflag = file_flags( f->f_root.ptr, f->f_root.len );
174
175     switch ( act = grid[ rflag ][ dflag ] )
176     {
177     case G_DTDR:
178         {
179             /* :: of rel dir */
180             string_push_back( file, DELIM );
181         }
182         /* fall through */
183
184     case G_DIR:
185         /* take dir */
186         string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );
187         break;
188
189     case G_ROOT:
190         /* take root */
191         string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
192         break;
193
194     case G_CAT:
195         /* prepend root to dir */
196         string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len  );
197         if ( file->value[ file->size - 1 ] == DELIM )
198             string_pop_back( file );
199         string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len  );
200         break;
201
202     case G_DDDD:
203         /* make it ::: (../..) */
204         string_append( file, ":::" );
205         break;
206     }
207
208     /* Put : between dir and file (if none already). */
209
210     if ( ( act != G_MT ) &&
211         ( file->value[ file->size - 1 ] != DELIM ) &&
212         ( f->f_base.len || f->f_suffix.len ) )
213     {
214         string_push_back( file, DELIM );
215     }
216
217     if ( f->f_base.len )
218         string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len  );
219
220     if ( f->f_suffix.len )
221         string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len  );
222
223     if ( f->f_member.len )
224     {
225         string_push_back( file, '(' );
226         string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len  );
227         string_push_back( file, ')' );
228     }
229
230     if ( DEBUG_SEARCH )
231         printf( " -> '%s'\n", file->value );
232 }
233
234
235 /*
236  *  path_parent() - make a PATHNAME point to its parent dir
237  */
238
239 void path_parent( PATHNAME * f )
240 {
241     /* Just set everything else to nothing. */
242
243     f->f_base.ptr =
244     f->f_suffix.ptr =
245     f->f_member.ptr = "";
246
247     f->f_base.len =
248     f->f_suffix.len =
249     f->f_member.len = 0;
250 }
251
252 # endif /* OS_MAC */