| 1515 | |
| 1516 | |
| 1517 | LIST * builtin_normalize_path( FRAME * frame, int flags ) |
| 1518 | { |
| 1519 | LIST * arg = lol_get( frame->args, 0 ); |
| 1520 | |
| 1521 | /* First, we iterate over all '/'-separated elements, starting from the end |
| 1522 | * of string. If we see a '..', we remove a preceeding path element. If we |
| 1523 | * see '.', we remove it. Removal is done by overwriting data using '\1' |
| 1524 | * characters. After the whole string has been processed, we do a second |
| 1525 | * pass, removing any entered '\1' characters. |
| 1526 | */ |
| 1527 | |
| 1528 | string in[ 1 ]; |
| 1529 | string out[ 1 ]; |
| 1530 | /* Last character of the part of string still to be processed. */ |
| 1531 | char * end; |
| 1532 | /* Working pointer. */ |
| 1533 | char * current; |
| 1534 | /* Number of '..' elements seen and not processed yet. */ |
| 1535 | int dotdots = 0; |
| 1536 | int rooted = 0; |
| 1537 | OBJECT * result = 0; |
| 1538 | LISTITER arg_iter = list_begin( arg ); |
| 1539 | LISTITER arg_end = list_end( arg ); |
| 1540 | |
| 1541 | /* Make a copy of input: we should not change it. Prepend a '/' before it as |
| 1542 | * a guard for the algorithm later on and remember whether it was originally |
| 1543 | * rooted or not. |
| 1544 | */ |
| 1545 | string_new( in ); |
| 1546 | string_push_back( in, '/' ); |
| 1547 | for ( ; arg_iter != arg_end; arg_iter = list_next( arg_iter ) ) |
| 1548 | { |
| 1549 | if ( object_str( list_item( arg_iter ) )[ 0 ] != '\0' ) |
| 1550 | { |
| 1551 | if ( in->size == 1 ) |
| 1552 | rooted = ( object_str( list_item( arg_iter ) )[ 0 ] == '/' ) || |
| 1553 | ( object_str( list_item( arg_iter ) )[ 0 ] == '\\' ); |
| 1554 | else |
| 1555 | string_append( in, "/" ); |
| 1556 | string_append( in, object_str( list_item( arg_iter ) ) ); |
| 1557 | } |
| 1558 | } |
| 1559 | |
| 1560 | /* Convert \ into /. On Windows, paths using / and \ are equivalent, and we |
| 1561 | * want this function to obtain a canonic representation. |
| 1562 | */ |
| 1563 | for ( current = in->value, end = in->value + in->size; |
| 1564 | current < end; ++current ) |
| 1565 | if ( *current == '\\' ) |
| 1566 | *current = '/'; |
| 1567 | |
| 1568 | /* Now we remove any extra path elements by overwriting them with '\1' |
| 1569 | * characters and cound how many more unused '..' path elements there are |
| 1570 | * remaining. Note that each remaining path element with always starts with |
| 1571 | * a '/' character. |
| 1572 | */ |
| 1573 | for ( end = in->value + in->size - 1; end >= in->value; ) |
| 1574 | { |
nothing calls this directly
no test coverage detected