2
0
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:
Vladimir Prus
2003-08-04 09:29:28 +00:00
parent 5e191e6cc6
commit 9ff2227563
8 changed files with 204 additions and 194 deletions

View File

@@ -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 )
{

View File

@@ -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 );

View File

@@ -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 )
{

View File

@@ -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 );

View File

@@ -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/.. ;
}

View File

@@ -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) ] ;
}
}

View File

@@ -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/.. ;
}

View File

@@ -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) ] ;
}
}