summaryrefslogtreecommitdiff
path: root/tools/build/src/engine/pathsys.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/build/src/engine/pathsys.c')
-rw-r--r--tools/build/src/engine/pathsys.c285
1 files changed, 285 insertions, 0 deletions
diff --git a/tools/build/src/engine/pathsys.c b/tools/build/src/engine/pathsys.c
new file mode 100644
index 000000000..ae4e6e052
--- /dev/null
+++ b/tools/build/src/engine/pathsys.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * Copyright 2005 Rene Rivera.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+/*
+ * pathsys.c - platform independent path manipulation support
+ *
+ * External routines:
+ * path_build() - build a filename given dir/base/suffix/member
+ * path_parent() - make a PATHNAME point to its parent dir
+ * path_parse() - split a file name into dir/base/suffix/member
+ * path_tmpdir() - returns the system dependent temporary folder path
+ * path_tmpfile() - returns a new temporary path
+ * path_tmpnam() - returns a new temporary name
+ *
+ * File_parse() and path_build() just manipulate a string and a structure;
+ * they do not make system calls.
+ */
+
+#include "jam.h"
+#include "pathsys.h"
+
+#include "filesys.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+
+/* Internal OS specific implementation details - have names ending with an
+ * underscore and are expected to be implemented in an OS specific pathXXX.c
+ * module.
+ */
+unsigned long path_get_process_id_( void );
+void path_get_temp_path_( string * buffer );
+
+
+/*
+ * path_parse() - split a file name into dir/base/suffix/member
+ */
+
+void path_parse( char const * file, PATHNAME * f )
+{
+ char const * p;
+ char const * q;
+ char const * end;
+
+ memset( (char *)f, 0, sizeof( *f ) );
+
+ /* Look for '<grist>'. */
+
+ if ( ( file[ 0 ] == '<' ) && ( p = strchr( file, '>' ) ) )
+ {
+ f->f_grist.ptr = file;
+ f->f_grist.len = p - file;
+ file = p + 1;
+ }
+
+ /* Look for 'dir/'. */
+
+ p = strrchr( file, '/' );
+
+#if PATH_DELIM == '\\'
+ /* On NT, look for dir\ as well */
+ {
+ char * const p1 = strrchr( p ? p + 1 : file, '\\' );
+ if ( p1 ) p = p1;
+ }
+#endif
+
+ if ( p )
+ {
+ f->f_dir.ptr = file;
+ f->f_dir.len = p - file;
+
+ /* Special case for / - dirname is /, not "" */
+ if ( !f->f_dir.len )
+ ++f->f_dir.len;
+
+#if PATH_DELIM == '\\'
+ /* Special case for D:/ - dirname is D:/, not "D:" */
+ if ( f->f_dir.len == 2 && file[ 1 ] == ':' )
+ ++f->f_dir.len;
+#endif
+
+ file = p + 1;
+ }
+
+ end = file + strlen( file );
+
+ /* Look for '(member)'. */
+ if ( ( p = strchr( file, '(' ) ) && ( end[ -1 ] == ')' ) )
+ {
+ f->f_member.ptr = p + 1;
+ f->f_member.len = end - p - 2;
+ end = p;
+ }
+
+ /* Look for '.suffix'. This would be memrchr(). */
+ p = 0;
+ for ( q = file; ( q = (char *)memchr( q, '.', end - q ) ); ++q )
+ p = q;
+ if ( p )
+ {
+ f->f_suffix.ptr = p;
+ f->f_suffix.len = end - p;
+ end = p;
+ }
+
+ /* Leaves base. */
+ f->f_base.ptr = file;
+ f->f_base.len = end - file;
+}
+
+
+/*
+ * is_path_delim() - true iff c is a path delimiter
+ */
+
+static int is_path_delim( char const c )
+{
+ return c == PATH_DELIM
+#if PATH_DELIM == '\\'
+ || c == '/'
+#endif
+ ;
+}
+
+
+/*
+ * as_path_delim() - convert c to a path delimiter if it is not one already
+ */
+
+static char as_path_delim( char const c )
+{
+ return is_path_delim( c ) ? c : PATH_DELIM;
+}
+
+
+/*
+ * path_build() - build a filename given dir/base/suffix/member
+ *
+ * To avoid changing slash direction on NT when reconstituting paths, instead of
+ * unconditionally appending PATH_DELIM we check the past-the-end character of
+ * the previous path element. If it is a path delimiter, we append that, and
+ * only append PATH_DELIM as a last resort. This heuristic is based on the fact
+ * that PATHNAME objects are usually the result of calling path_parse, which
+ * leaves the original slashes in the past-the-end position. Correctness depends
+ * on the assumption that all strings are zero terminated, so a past-the-end
+ * character will always be available.
+ *
+ * As an attendant patch, we had to ensure that backslashes are used explicitly
+ * in 'timestamp.c'.
+ */
+
+void path_build( PATHNAME * f, string * file )
+{
+ file_build1( f, file );
+
+ /* Do not prepend root if it is '.' or the directory is rooted. */
+ if ( f->f_root.len
+ && !( f->f_root.len == 1 && f->f_root.ptr[ 0 ] == '.' )
+ && !( f->f_dir.len && f->f_dir.ptr[ 0 ] == '/' )
+#if PATH_DELIM == '\\'
+ && !( f->f_dir.len && f->f_dir.ptr[ 0 ] == '\\' )
+ && !( f->f_dir.len && f->f_dir.ptr[ 1 ] == ':' )
+#endif
+ )
+ {
+ string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len
+ );
+ /* If 'root' already ends with a path delimeter, do not add another one.
+ */
+ if ( !is_path_delim( f->f_root.ptr[ f->f_root.len - 1 ] ) )
+ string_push_back( file, as_path_delim( f->f_root.ptr[ f->f_root.len
+ ] ) );
+ }
+
+ if ( f->f_dir.len )
+ string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
+
+ /* Put path separator between dir and file. */
+ /* Special case for root dir: do not add another path separator. */
+ if ( f->f_dir.len && ( f->f_base.len || f->f_suffix.len )
+#if PATH_DELIM == '\\'
+ && !( f->f_dir.len == 3 && f->f_dir.ptr[ 1 ] == ':' )
+#endif
+ && !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[ 0 ] ) ) )
+ string_push_back( file, as_path_delim( f->f_dir.ptr[ f->f_dir.len ] ) );
+
+ if ( f->f_base.len )
+ string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len
+ );
+
+ if ( f->f_suffix.len )
+ string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr +
+ f->f_suffix.len );
+
+ if ( f->f_member.len )
+ {
+ string_push_back( file, '(' );
+ string_append_range( file, f->f_member.ptr, f->f_member.ptr +
+ f->f_member.len );
+ string_push_back( file, ')' );
+ }
+}
+
+
+/*
+ * path_parent() - make a PATHNAME point to its parent dir
+ */
+
+void path_parent( PATHNAME * f )
+{
+ f->f_base.ptr = f->f_suffix.ptr = f->f_member.ptr = "";
+ f->f_base.len = f->f_suffix.len = f->f_member.len = 0;
+}
+
+
+/*
+ * path_tmpdir() - returns the system dependent temporary folder path
+ *
+ * Returned value is stored inside a static buffer and should not be modified.
+ * Returned value does *not* include a trailing path separator.
+ */
+
+string const * path_tmpdir()
+{
+ static string buffer[ 1 ];
+ static int have_result;
+ if ( !have_result )
+ {
+ string_new( buffer );
+ path_get_temp_path_( buffer );
+ have_result = 1;
+ }
+ return buffer;
+}
+
+
+/*
+ * path_tmpnam() - returns a new temporary name
+ */
+
+OBJECT * path_tmpnam( void )
+{
+ char name_buffer[ 64 ];
+ unsigned long const pid = path_get_process_id_();
+ static unsigned long t;
+ if ( !t ) t = time( 0 ) & 0xffff;
+ t += 1;
+ sprintf( name_buffer, "jam%lx%lx.000", pid, t );
+ return object_new( name_buffer );
+}
+
+
+/*
+ * path_tmpfile() - returns a new temporary path
+ */
+
+OBJECT * path_tmpfile( void )
+{
+ OBJECT * result;
+ OBJECT * tmpnam;
+
+ string file_path[ 1 ];
+ string_copy( file_path, path_tmpdir()->value );
+ string_push_back( file_path, PATH_DELIM );
+ tmpnam = path_tmpnam();
+ string_append( file_path, object_str( tmpnam ) );
+ object_free( tmpnam );
+ result = object_new( file_path->value );
+ string_free( file_path );
+
+ return result;
+}