g_build_path() inconsistency



I was looking at bug #85928, which is:

 g_build_filename("/", "usr", NULL) returns "//usr".

And it turns out we have some problems with the definition
of g_build_path().

Right now, we have:

 g_build_filename ( "/usr", "", "share", NULL ) => /usr/share
 g_build_filename ( "/usr", "/", "share", NULL ) => /usr/share
 g_build_filename ( "" "//usr", "/share", NULL ) => usr/share
 g_build_filename ( "/" "//usr", "/share", NULL ) => //usr/share
 g_build_filename ( "//usr", "/share", NULL ) => //usr/share

Which strikes me as being really weird.

g_build_path() is documented as:

/**
 * g_build_path:
 * @separator: a string used to separator the elements of the path.
 * @first_element: the first element in the path
 * @Varargs: remaining elements in path
 * 
 * Creates a path from a series of elements using @separator as the
 * separator between elements. At the boundary between two elements,
 * any trailing occurrences of separator in the first element, or
 * leading occurrences of separator in the second element are removed
 * and exactly one copy of the separator is inserted.
 
I'd like to add to this:

  Empty elements are ignored.

  The number of leading copies of the separator on the result is
  the same as the number of leading copies of the separator on
  the first non-empty element.

  The number of trailing copies of the separator on the result is
  the same as the number of trailing copies of the separator on
  the last non-empty element.

  Other than for determination of the number of leading and trailing
  copies of the separator, elements consisting only of copies
  of the separator are ignored.

This gives:

 g_build_filename ( "/usr", "", "share", NULL ) => /usr/share
 g_build_filename ( "/usr", "/", "share", NULL ) => /usr/share
 g_build_filename ( "" "//usr", "/share", NULL ) => //usr/share
 g_build_filename ( "/" "//usr", "/share", NULL ) => /usr/share
 g_build_filename ( "//usr", "/share", NULL ) => //usr/share

Can anybody think of a more concise description of this process?
As an algorithm it is:

 1) Set L to be the number of leading copies of the separator in
    the first non-empty element.

 2) Set T to be the number of trailing copies of the separator in
    the last non-empty element.

 3) Remove all elements that are empty or consist only of copies
    of the separator.

 4) Join the remaining elements together, inserting L copies of 
    the separator before the first element, 1 copy of the separator
    between each pair of elements, and T copies of the separator
    after the last element.

The other possibility for the algorithm would be:

 1) Set L to be 1 if the first non-empty element starts with the
    separator, otherwise set L to be 0.
 2) Set T to be 1 if the first non-empty element ends with the
    separator, otherwise 0.
 3) As before
 4) As before

Giving:

 g_build_filename ( "/usr", "", "share", NULL ) => /usr/share
 g_build_filename ( "/usr", "/", "share", NULL ) => /usr/share
 g_build_filename ( "" "//usr", "/share", NULL ) => /usr/share
 g_build_filename ( "/" "//usr", "/share", NULL ) => /usr/share
 g_build_filename ( "//usr", "/share", NULL ) => /usr/share

But I worry that this will break Windows network paths that
(as I recall) start with \\.


The other subtlety is the definition of trailing copies of the
separator. Using the first verison of the algorithm, does:

 g_build_path ("::", "C", ":::") give 

  "C" "::" ":" => "C:::" or C "::" ":" "::" => "C::::"

I think the first one is right - that is, the number of trailing
copies of the separator in an element is determined after stripping 
off all leading copies of the separator.

Regards,
                                        Owen



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]