mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 13:02:11 +00:00
New builtin NORMALIZE_PATH.
[SVN r19431]
This commit is contained in:
@@ -239,6 +239,12 @@ load_builtins()
|
||||
bind_builtin( "SORT",
|
||||
builtin_sort, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "path", 0 };
|
||||
bind_builtin( "NORMALIZE_PATH",
|
||||
builtin_normalize_path, 0, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -911,6 +917,96 @@ builtin_sort( PARSE *parse, FRAME *frame )
|
||||
return list_sort(arg1);
|
||||
}
|
||||
|
||||
LIST *builtin_normalize_path( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST* arg1 = lol_get( frame->args, 0 );
|
||||
|
||||
/* First, we iterate over all '/'-separated elements, starting from
|
||||
the end of string. If we see '..', we remove previous path elements.
|
||||
If we see '.', we remove it.
|
||||
The removal is done by putting '\1' in the string. After all the string
|
||||
is processed, we do a second pass, removing '\1' characters.
|
||||
*/
|
||||
|
||||
string in[1], out[1], tmp[1];
|
||||
char* end; /* Last character of the part of string still to be processed. */
|
||||
char* current; /* Working pointer. */
|
||||
int dotdots = 0; /* Number of '..' elements seen and not processed yet. */
|
||||
int rooted = arg1->string[0] == '/';
|
||||
|
||||
/* Make a copy of input: we should not change it. */
|
||||
string_new(in);
|
||||
if (!rooted)
|
||||
string_push_back(in, '/');
|
||||
string_append(in, arg1->string);
|
||||
|
||||
|
||||
end = in->value + in->size - 1;
|
||||
current = end;
|
||||
|
||||
for(;end >= in->value;) {
|
||||
/* Set 'current' to the next occurence of '/', which always exists. */
|
||||
for(current = end; *current != '/'; --current)
|
||||
;
|
||||
|
||||
if (current == end && current != in->value) {
|
||||
/* Found a trailing slash. Remove it. */
|
||||
*current = '\1';
|
||||
} else if (current == end && *(current+1) == '/') {
|
||||
/* Found duplicated slash. Remove it. */
|
||||
*current = '\1';
|
||||
} else if (end - current == 1 && strncmp(current, "/.", 2) == 0) {
|
||||
/* Found '/.'. Drop them all. */
|
||||
*current = '\1';
|
||||
*(current+1) = '\1';
|
||||
} else if (end - current == 2 && strncmp(current, "/..", 3) == 0) {
|
||||
/* Found '/..' */
|
||||
*current = '\1';
|
||||
*(current+1) = '\1';
|
||||
*(current+2) = '\1';
|
||||
++dotdots;
|
||||
} else if (dotdots) {
|
||||
char* p = current;
|
||||
memset(current, '\1', end-current+1);
|
||||
--dotdots;
|
||||
}
|
||||
end = current-1;
|
||||
}
|
||||
|
||||
|
||||
string_new(tmp);
|
||||
while(dotdots--)
|
||||
string_append(tmp, "/..");
|
||||
string_append(tmp, in->value);
|
||||
string_copy(in, tmp->value);
|
||||
string_free(tmp);
|
||||
|
||||
|
||||
string_new(out);
|
||||
/* The resulting path is either empty or has '/' as the first significant
|
||||
element. If the original path was not rooted, we need to drop first '/'.
|
||||
If the original path was rooted, and we've got empty path, need to add '/'
|
||||
*/
|
||||
if (!rooted) {
|
||||
current = strchr(in->value, '/');
|
||||
if (current)
|
||||
*current = '\1';
|
||||
}
|
||||
|
||||
for (current = in->value; *current; ++current)
|
||||
if (*current != '\1')
|
||||
string_push_back(out, *current);
|
||||
|
||||
|
||||
char* result = newstr(out->size ? out->value : (rooted ? "/" : "."));
|
||||
string_free(in);
|
||||
string_free(out);
|
||||
|
||||
return list_new(0, result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void lol_build( LOL* lol, char** elements )
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@ LIST *builtin_import_module( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
|
||||
LIST *builtin_instance( PARSE *parse, FRAME *frame );
|
||||
LIST *builtin_sort( PARSE *parse, FRAME *frame );
|
||||
LIST *builtin_normalize_path( PARSE *parse, FRAME *frame );
|
||||
|
||||
void backtrace( FRAME *frame );
|
||||
|
||||
|
||||
@@ -239,6 +239,12 @@ load_builtins()
|
||||
bind_builtin( "SORT",
|
||||
builtin_sort, 0, args );
|
||||
}
|
||||
|
||||
{
|
||||
char * args[] = { "path", 0 };
|
||||
bind_builtin( "NORMALIZE_PATH",
|
||||
builtin_normalize_path, 0, args );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -911,6 +917,96 @@ builtin_sort( PARSE *parse, FRAME *frame )
|
||||
return list_sort(arg1);
|
||||
}
|
||||
|
||||
LIST *builtin_normalize_path( PARSE *parse, FRAME *frame )
|
||||
{
|
||||
LIST* arg1 = lol_get( frame->args, 0 );
|
||||
|
||||
/* First, we iterate over all '/'-separated elements, starting from
|
||||
the end of string. If we see '..', we remove previous path elements.
|
||||
If we see '.', we remove it.
|
||||
The removal is done by putting '\1' in the string. After all the string
|
||||
is processed, we do a second pass, removing '\1' characters.
|
||||
*/
|
||||
|
||||
string in[1], out[1], tmp[1];
|
||||
char* end; /* Last character of the part of string still to be processed. */
|
||||
char* current; /* Working pointer. */
|
||||
int dotdots = 0; /* Number of '..' elements seen and not processed yet. */
|
||||
int rooted = arg1->string[0] == '/';
|
||||
|
||||
/* Make a copy of input: we should not change it. */
|
||||
string_new(in);
|
||||
if (!rooted)
|
||||
string_push_back(in, '/');
|
||||
string_append(in, arg1->string);
|
||||
|
||||
|
||||
end = in->value + in->size - 1;
|
||||
current = end;
|
||||
|
||||
for(;end >= in->value;) {
|
||||
/* Set 'current' to the next occurence of '/', which always exists. */
|
||||
for(current = end; *current != '/'; --current)
|
||||
;
|
||||
|
||||
if (current == end && current != in->value) {
|
||||
/* Found a trailing slash. Remove it. */
|
||||
*current = '\1';
|
||||
} else if (current == end && *(current+1) == '/') {
|
||||
/* Found duplicated slash. Remove it. */
|
||||
*current = '\1';
|
||||
} else if (end - current == 1 && strncmp(current, "/.", 2) == 0) {
|
||||
/* Found '/.'. Drop them all. */
|
||||
*current = '\1';
|
||||
*(current+1) = '\1';
|
||||
} else if (end - current == 2 && strncmp(current, "/..", 3) == 0) {
|
||||
/* Found '/..' */
|
||||
*current = '\1';
|
||||
*(current+1) = '\1';
|
||||
*(current+2) = '\1';
|
||||
++dotdots;
|
||||
} else if (dotdots) {
|
||||
char* p = current;
|
||||
memset(current, '\1', end-current+1);
|
||||
--dotdots;
|
||||
}
|
||||
end = current-1;
|
||||
}
|
||||
|
||||
|
||||
string_new(tmp);
|
||||
while(dotdots--)
|
||||
string_append(tmp, "/..");
|
||||
string_append(tmp, in->value);
|
||||
string_copy(in, tmp->value);
|
||||
string_free(tmp);
|
||||
|
||||
|
||||
string_new(out);
|
||||
/* The resulting path is either empty or has '/' as the first significant
|
||||
element. If the original path was not rooted, we need to drop first '/'.
|
||||
If the original path was rooted, and we've got empty path, need to add '/'
|
||||
*/
|
||||
if (!rooted) {
|
||||
current = strchr(in->value, '/');
|
||||
if (current)
|
||||
*current = '\1';
|
||||
}
|
||||
|
||||
for (current = in->value; *current; ++current)
|
||||
if (*current != '\1')
|
||||
string_push_back(out, *current);
|
||||
|
||||
|
||||
char* result = newstr(out->size ? out->value : (rooted ? "/" : "."));
|
||||
string_free(in);
|
||||
string_free(out);
|
||||
|
||||
return list_new(0, result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void lol_build( LOL* lol, char** elements )
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@ LIST *builtin_import_module( PARSE *parse, FRAME *args );
|
||||
LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
|
||||
LIST *builtin_instance( PARSE *parse, FRAME *frame );
|
||||
LIST *builtin_sort( PARSE *parse, FRAME *frame );
|
||||
LIST *builtin_normalize_path( PARSE *parse, FRAME *frame );
|
||||
|
||||
void backtrace( FRAME *frame );
|
||||
|
||||
|
||||
@@ -200,44 +200,7 @@ local rule normalize-raw-paths ( paths * )
|
||||
local result ;
|
||||
for p in $(paths:T)
|
||||
{
|
||||
local elements ; # the simplified path elements
|
||||
local dotdots ; # a stack of .. elements we've seen
|
||||
|
||||
# consume the last path element in p until there's nothing
|
||||
# left
|
||||
while $(p)
|
||||
{
|
||||
local split = [ MATCH ^(.+)/(.*)$ : $(p) ] ;
|
||||
|
||||
if ! $(split)
|
||||
{ # no further slashes; prepend the last element
|
||||
elements = $(p) $(elements) ;
|
||||
}
|
||||
else if $(split[2]) = .
|
||||
{ # ignore the identity directory
|
||||
}
|
||||
else if $(split[2]) = ..
|
||||
{ # prepare to absorb the next named element
|
||||
dotdots += .. ; # push parent onto stack
|
||||
}
|
||||
else if $(dotdots)
|
||||
{ # absorb a named element
|
||||
dotdots = $(dotdots[2-]) ; # pop parent off stack
|
||||
}
|
||||
else if $(split[2]) # if the element was empty, ignore it
|
||||
{ # to drop a trailing slash
|
||||
elements = $(split[2]) $(elements) ;
|
||||
}
|
||||
# drop the last element of p
|
||||
p = $(split[1]) ;
|
||||
}
|
||||
|
||||
# prepend any unused parent directories
|
||||
elements = $(dotdots) $(elements) ;
|
||||
# If everything cancelled out, it's the identity directory.
|
||||
elements ?= . ;
|
||||
|
||||
result += $(elements:J=/) ;
|
||||
result += [ NORMALIZE_PATH $(p) ] ;
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
@@ -355,10 +318,12 @@ local rule __test__ ( )
|
||||
assert.result . : normalize-raw-paths . ;
|
||||
assert.result .. : normalize-raw-paths .. ;
|
||||
assert.result ../.. : normalize-raw-paths ../.. ;
|
||||
assert.result .. : normalize-raw-paths ./.. ;
|
||||
assert.result / / : normalize-raw-paths / \\ ;
|
||||
assert.result a : normalize-raw-paths a ;
|
||||
assert.result a : normalize-raw-paths a/ ;
|
||||
assert.result /a : normalize-raw-paths /a/ ;
|
||||
assert.result / : normalize-raw-paths /a/.. ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
61
new/path.jam
61
new/path.jam
@@ -140,64 +140,7 @@ rule reverse ( path )
|
||||
#
|
||||
local rule join-imp ( elements + )
|
||||
{
|
||||
local path1 = $(elements[1]) ;
|
||||
local path2 = $(elements[2]) ;
|
||||
|
||||
if $(elements[3-])
|
||||
{
|
||||
path2 = [ join $(elements[2-]) ] ;
|
||||
}
|
||||
if $(path1) = .
|
||||
{
|
||||
return $(path2) ;
|
||||
}
|
||||
else if $(path1) = /
|
||||
{
|
||||
return /$(path2) ;
|
||||
}
|
||||
else if $(path2) = .
|
||||
{
|
||||
return $(path1) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Separate the part with ".." from the rest.
|
||||
local parts = [ regex.match "(\\.\\.(/\\.\\.)*)?/?(.*)" : $(path2) : 1 3 ] ;
|
||||
|
||||
if $(parts[1])
|
||||
{
|
||||
local up_tokens = [ regex.split $(parts[1]) "/" ] ;
|
||||
for local i in $(up_tokens)
|
||||
{
|
||||
path1 = [ parent $(path1) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
if $(path1) = .
|
||||
{
|
||||
if $(parts[2])
|
||||
{
|
||||
return $(parts[2]) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return . ;
|
||||
}
|
||||
}
|
||||
else if $(path1) = /
|
||||
{
|
||||
# TODO: consider if it's possible to have empty $(parts[2]) here.
|
||||
return /$(parts[2]) ;
|
||||
}
|
||||
else if $(parts[2])
|
||||
{
|
||||
return $(path1)/$(parts[2]) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $(path1) ;
|
||||
}
|
||||
}
|
||||
return [ NORMALIZE_PATH $(elements:J="/") ] ;
|
||||
}
|
||||
|
||||
#
|
||||
@@ -405,7 +348,7 @@ rule make-UNIX ( native )
|
||||
}
|
||||
else
|
||||
{
|
||||
return [ path.join [ regex.split $(native) "/" ] ] ;
|
||||
return [ NORMALIZE_PATH $(native:T) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -200,44 +200,7 @@ local rule normalize-raw-paths ( paths * )
|
||||
local result ;
|
||||
for p in $(paths:T)
|
||||
{
|
||||
local elements ; # the simplified path elements
|
||||
local dotdots ; # a stack of .. elements we've seen
|
||||
|
||||
# consume the last path element in p until there's nothing
|
||||
# left
|
||||
while $(p)
|
||||
{
|
||||
local split = [ MATCH ^(.+)/(.*)$ : $(p) ] ;
|
||||
|
||||
if ! $(split)
|
||||
{ # no further slashes; prepend the last element
|
||||
elements = $(p) $(elements) ;
|
||||
}
|
||||
else if $(split[2]) = .
|
||||
{ # ignore the identity directory
|
||||
}
|
||||
else if $(split[2]) = ..
|
||||
{ # prepare to absorb the next named element
|
||||
dotdots += .. ; # push parent onto stack
|
||||
}
|
||||
else if $(dotdots)
|
||||
{ # absorb a named element
|
||||
dotdots = $(dotdots[2-]) ; # pop parent off stack
|
||||
}
|
||||
else if $(split[2]) # if the element was empty, ignore it
|
||||
{ # to drop a trailing slash
|
||||
elements = $(split[2]) $(elements) ;
|
||||
}
|
||||
# drop the last element of p
|
||||
p = $(split[1]) ;
|
||||
}
|
||||
|
||||
# prepend any unused parent directories
|
||||
elements = $(dotdots) $(elements) ;
|
||||
# If everything cancelled out, it's the identity directory.
|
||||
elements ?= . ;
|
||||
|
||||
result += $(elements:J=/) ;
|
||||
result += [ NORMALIZE_PATH $(p) ] ;
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
@@ -355,10 +318,12 @@ local rule __test__ ( )
|
||||
assert.result . : normalize-raw-paths . ;
|
||||
assert.result .. : normalize-raw-paths .. ;
|
||||
assert.result ../.. : normalize-raw-paths ../.. ;
|
||||
assert.result .. : normalize-raw-paths ./.. ;
|
||||
assert.result / / : normalize-raw-paths / \\ ;
|
||||
assert.result a : normalize-raw-paths a ;
|
||||
assert.result a : normalize-raw-paths a/ ;
|
||||
assert.result /a : normalize-raw-paths /a/ ;
|
||||
assert.result / : normalize-raw-paths /a/.. ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -140,64 +140,7 @@ rule reverse ( path )
|
||||
#
|
||||
local rule join-imp ( elements + )
|
||||
{
|
||||
local path1 = $(elements[1]) ;
|
||||
local path2 = $(elements[2]) ;
|
||||
|
||||
if $(elements[3-])
|
||||
{
|
||||
path2 = [ join $(elements[2-]) ] ;
|
||||
}
|
||||
if $(path1) = .
|
||||
{
|
||||
return $(path2) ;
|
||||
}
|
||||
else if $(path1) = /
|
||||
{
|
||||
return /$(path2) ;
|
||||
}
|
||||
else if $(path2) = .
|
||||
{
|
||||
return $(path1) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Separate the part with ".." from the rest.
|
||||
local parts = [ regex.match "(\\.\\.(/\\.\\.)*)?/?(.*)" : $(path2) : 1 3 ] ;
|
||||
|
||||
if $(parts[1])
|
||||
{
|
||||
local up_tokens = [ regex.split $(parts[1]) "/" ] ;
|
||||
for local i in $(up_tokens)
|
||||
{
|
||||
path1 = [ parent $(path1) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
if $(path1) = .
|
||||
{
|
||||
if $(parts[2])
|
||||
{
|
||||
return $(parts[2]) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return . ;
|
||||
}
|
||||
}
|
||||
else if $(path1) = /
|
||||
{
|
||||
# TODO: consider if it's possible to have empty $(parts[2]) here.
|
||||
return /$(parts[2]) ;
|
||||
}
|
||||
else if $(parts[2])
|
||||
{
|
||||
return $(path1)/$(parts[2]) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $(path1) ;
|
||||
}
|
||||
}
|
||||
return [ NORMALIZE_PATH $(elements:J="/") ] ;
|
||||
}
|
||||
|
||||
#
|
||||
@@ -405,7 +348,7 @@ rule make-UNIX ( native )
|
||||
}
|
||||
else
|
||||
{
|
||||
return [ path.join [ regex.split $(native) "/" ] ] ;
|
||||
return [ NORMALIZE_PATH $(native:T) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user