# New Ticket Created by  Mike Mattie 
# Please include the string:  [perl #42944]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=42944 >


Hello,

This is a patch, and two new files:

parrot/include/path.h
src/path.c

These changes move the static path handling utilities out of library.c into 
their own translation unit.
This allows all of the parrot code to use a single implementation of common 
path handling functions.

slight modifications were made to the win32 specific portions that need to be 
re-tested on that
platform.

I modified the config/gen/makefiles/root.in to get it compiling properly , but 
I might have missed
something as this is my first change to the makefile.

I get two harness failures I haven't figured out yet:

t/op/sprintf.....................................ok 1/308parrot:
src/string.c:727: string_str_index: Assertion `s->encoding &&
s->charset && !(((s)->obj.flags) & b_PObj_on_free_list_FLAG)' failed.

This may be because I modified the functions in path.c to use more of the 
string API instead of
bypassing it. Someone else may be able to decode this assertion failure so I 
can pinpoint
where it is coming from. I suspect that it is coming from path.c:217 .

In fact that entire function needs to be reviewed, I don't have the unicode 
experience
to understand it's string manipulation. beyond the change on 217 I haven't 
touched
that code with a cleanup yet.

#     Failed test (t/perl/Parrot_IO.t at line 159)
t/perl/Parrot_IO.................................NOK 51/57# Looks like you 
failed 1 test of 57.

This one I don't get at all. This could be random.

Other than those two failures the test-suite passed on i686-pc-gnu-linux

Failed Test        Stat Wstat Total Fail  List of Failed
-------------------------------------------------------------------------------
t/op/sprintf.t        0     6   308  234  192-308
t/perl/Parrot_IO.t    1   256    57    1  51
9 tests and 512 subtests skipped.
Failed 2/304 test scripts. 118/7217 subtests failed.
Files=304, Tests=7217, 575 wallclock secs (288.14 cusr + 46.41 csys =
334.55 CPU)
Failed 2/304 test programs. 118/7217 subtests failed.

Cheers,
Mike Mattie

/*
Copyright (C) 2004-2007, The Perl Foundation.

=head1 NAME

src/path.c

=head1 DESCRIPTION

This file contains a C functions for parrot's platform independent
path handling.

=head2 Functions

=over 6

=cut

*/

#include "parrot/parrot.h"
#include "parrot/path.h"
#include "path.str"

static const char parrot_path_separator = '/';

#ifdef WIN32
static const char platform_path_separator = '\\';


/*
 * Converts a path with forward slashes to one with backward slashes.
 */
static void
cnv_to_platform_filesep (STRING *path) {
    char* cnv;

    assert(path->encoding == Parrot_fixed_8_encoding_ptr ||
        path->encoding == Parrot_utf8_encoding_ptr);

    cnv = Parrot_string_cstring(path);

    while ((cnv = strchr(cnv, parrot_path_separator)) != NULL)
        *cnv = platform_path_seperator;
}

#else

static const char platform_path_separator = '/';

#endif


/*

=item C<STRING *
parrot_path_is_abs(Interp*, STRING *path)>

return true if the given file is an absolute path, false if relative.

=cut

*/

int
parrot_path_is_abs(Interp* interp, STRING *path)
{
    const char *file_name;

    if ( !string_length(interp, path) )
        return 0;

    assert(path->encoding == Parrot_fixed_8_encoding_ptr
           || path->encoding == Parrot_utf8_encoding_ptr);

    file_name = Parrot_string_cstring(interp,path);

    return (file_name[0] == parrot_path_separator

#ifdef WIN32
            || file_name[0] == platform_path_seperator
            || (isalpha(file_name[0])
                && string_length(file) > 2
                && (strncmp(file_name+1, ":\\", 2) == 0
                    || strncmp(file_name+1, ":/",  2) == 0))
#endif
      ) ? 1 : 0;
}

/*

=item C<STRING *
parrot_path_trailing_separator(Interp*, STRING *path)>

Ensure that the given path has a trailing path separator.
A new string may be returned.

=cut

*/

STRING*
parrot_path_trailing_separator(Interp *interp, STRING *path)
{
    STRING *path_separator_string = string_chr(interp, platform_path_separator);

    /* make sure the path has a trailing slash before appending the file */
    if (string_index(interp, path , string_length(interp,path) - 1)
         != string_index(interp, path_separator_string, 0))
        path = string_append(interp, path , path_separator_string);

    return path;
}

/*

=item C<STRING *
parrot_path_platform_localize(Interp*, STRING *path)>

Localize a path to the platform by converting the parrot path
seperator to the platform seperator if necessary.  Also a "hidden
zero" is appended to the path making it suitable for use by C API's
such as platform file/IO.

=cut

*/

STRING*
parrot_path_platform_localize(Interp *interp, STRING *path)
{

#ifdef WIN32
      cnv_to_platform_filesep(path);
#endif

    /* TODO create a string API that just does that
     *      a lot of ICU lib functions also need 0-terminated strings
     *      the goal is just to have for sure an invisible 0 at end
     */

    STRING *nul = string_chr(interp, '\0');

    path = string_append(interp, path, nul);
    path->bufused--;
    path->strlen--;


    return path;
}

/*

=item C<STRING *
parrot_path_append(Interp*, STRING *orig, STRING *append)>

Concatenate two paths with the platform specific path seperator.  The
result may be a new string.

=cut

*/

STRING*
parrot_path_append(Interp *interp, STRING *orig, STRING *append)
{
    orig = parrot_path_trailing_separator(interp, orig);
    return string_append(interp, orig, append);
}

/*

=item C<STRING *
parrot_path_concat(Interp*, STRING *orig, STRING *append)>

Concatenate two paths with the platform specific path seperator.
The result is garunteed to be a new string.

=cut

*/

STRING*
parrot_path_concat(Interp *interp, STRING *orig, STRING *append)
{
    STRING* join;

    join = string_copy(interp, orig);
    join = parrot_path_trailing_separator(interp, join);
    return string_append(interp, join , append);
}

/*

=item C<STRING *
parrot_split_path_ext(Interp*, STRING *in, STRING **wo_ext, STRING **ext)>

Split the pathstring C<in> into <path><filestem><ext>. Return the
C<filestem> of the pathstring. Set C<wo_ext> to the part without
extension and C<ext> to the extension or NULL.

=cut

*/

STRING *
parrot_split_path_ext(Interp* interp, STRING *in,
                      STRING **wo_ext, STRING **ext)
{
    STRING *slash1, *slash2, *dot, *stem;
    INTVAL pos_sl, pos_dot, len;

    slash1 = CONST_STRING(interp, "/");
    slash2 = CONST_STRING(interp, "\\");

    dot    = CONST_STRING(interp, ".");
    len = string_length(interp, in);

    pos_sl = CHARSET_RINDEX(interp, in, slash1, len);
    if (pos_sl == -1)
        pos_sl = CHARSET_RINDEX(interp, in, slash2, len);
    pos_dot = CHARSET_RINDEX(interp, in, dot, len);

    /* XXX directory parrot-0.4.1 or such */
    if (pos_dot != -1 && isdigit(((char*)in->strstart)[pos_dot+1]))
        pos_dot = -1;

    ++pos_dot;
    ++pos_sl;
    if (pos_sl && pos_dot) {
        stem = string_substr(interp, in, pos_sl, pos_dot - pos_sl - 1,
                NULL, 0);
        *wo_ext = string_substr(interp, in, 0, pos_dot - 1, NULL, 0);
        *ext = string_substr(interp, in, pos_dot, len - pos_dot, NULL, 0);
    }
    else if (pos_dot) {
        stem = string_substr(interp, in, 0, pos_dot - 1, NULL, 0);
        *wo_ext = stem;
        *ext = string_substr(interp, in, pos_dot, len - pos_dot, NULL, 0);
    }
    else if (pos_sl) {
        stem = string_substr(interp, in, pos_sl, len - pos_sl, NULL, 0);
        *wo_ext = string_copy(interp, in);
        *ext = 0;
    }
    else {
        stem = string_copy(interp, in);
        *wo_ext = stem;
        *ext = NULL;
    }
    return stem;
}

/*

=back

=head1 SEE ALSO

F<include/parrot/path.h>

=cut

*/


/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
/* path.h
 *  Copyright (C) 2007, The Perl Foundation.
 *
 *  Overview:
 *      Contains functions for handling paths in a platform
 *      independent manner, similar to Path::Spec from perl5
 *
 *  Data Structure and Algorithms:
 *  History:
 *  Notes:
 *  References:
 */

#ifndef PARROT_PATH_H_GUARD
#define PARROT_PATH_H_GUARD

int
parrot_path_is_abs(Interp* interp, STRING *path);

STRING*
parrot_path_trailing_separator(Interp *interp, STRING *path);

STRING*
parrot_path_platform_localize(Interp *interp, STRING *path);

STRING*
parrot_path_append(Interp *interp, STRING *orig, STRING *append);

STRING*
parrot_path_concat(Interp *interp, STRING *orig, STRING *append);

STRING * parrot_split_path_ext(Interp* , STRING *in,
                               STRING **wo_ext, STRING **ext);
#endif /* PARROT_PATH_H_GUARD */

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
--- HEAD/src/dynext.c	2007-05-12 04:26:05.000000000 -0700
+++ path-api/src/dynext.c	2007-05-14 04:02:41.000000000 -0700
@@ -18,6 +18,7 @@
 
 #include "parrot/parrot.h"
 #include "parrot/dynext.h"
+#include "parrot/path.h"
 
 /* _PARROTLIB is now the default */
 /*#define _PARROTLIB not working: "make testr" */
--- HEAD/src/library.c	2007-05-12 15:41:34.000000000 -0700
+++ path-api/src/library.c	2007-05-14 03:58:26.000000000 -0700
@@ -19,10 +19,12 @@
 */
 
 #include "parrot/parrot.h"
-#include "parrot/dynext.h"
-#include <assert.h>
+#include "parrot/path.h"
+
 #include "library.str"
 
+#include <assert.h>
+
 /*
 
 =item C<void parrot_init_library_paths(Interp *)>
@@ -136,126 +138,6 @@
     return VTABLE_get_pmc_keyed_int(interp, lib_paths, which);
 }
 
-static int
-is_abs_path(Interp* interp, STRING *file)
-{
-    char *file_name;
-
-    file_name = file->strstart;
-    if (file->strlen <= 1)
-        return 0;
-    assert(file->encoding == Parrot_fixed_8_encoding_ptr ||
-            file->encoding == Parrot_utf8_encoding_ptr);
-#ifdef WIN32
-    if (file_name[0] == '\\' || file_name[0] == '/' ||
-            (isalpha(file_name[0]) && file->strlen > 2 &&
-             (strncmp(file_name+1, ":\\", 2) == 0 ||
-              strncmp(file_name+1, ":/",  2) == 0)))
-#else
-        if (file_name[0] == '/')     /* XXX  ../foo, ./bar */
-#endif
-        {
-            return 1;
-        }
-    return 0;
-}
-
-static const char path_separator = '/';
-
-#ifdef WIN32
-
-static const char win32_path_separator = '\\';
-
-/*
-   Converts a path with forward slashes to one with backward slashes.
-*/
-static void
-cnv_to_win32_filesep (STRING *path) {
-    char* cnv;
-
-    assert(path->encoding == Parrot_fixed_8_encoding_ptr ||
-        path->encoding == Parrot_utf8_encoding_ptr);
-
-    cnv = path->strstart;
-    while ((cnv = strchr(cnv, path_separator)) != NULL)
-        *cnv = win32_path_separator;
-}
-
-#endif
-
-static STRING*
-path_finalize(Interp *interp, STRING *path)
-{
-
-    /* TODO create a string API that just does that
-     *      a lot of ICU lib functions also need 0-terminated strings
-     *      the goal is just to have for sure an invisible 0 at end
-     */
-
-    STRING *nul = string_chr(interp, '\0');
-
-    path = string_append(interp, path, nul);
-    path->bufused--;
-    path->strlen--;
-
-#ifdef WIN32
-    cnv_to_win32_filesep(path);
-#endif
-
-    return path;
-}
-
-/*
-  unary path argument. the path string will have a
-  trailing path-separator appended if it is not
-  there already.
- */
-
-static STRING*
-path_guarantee_trailing_separator(Interp *interp, STRING *path)
-{
-    STRING *path_separator_string = string_chr(interp, path_separator);
-
-    /* make sure the path has a trailing slash before appending the file */
-    if (string_index(interp, path , path->strlen - 1)
-         != string_index(interp, path_separator_string, 0))
-        path = string_append(interp, path , path_separator_string);
-
-    return path;
-}
-
-/*
-  binary path arguments, the left arg is modified.
-  a trailing separator is guaranteed for the left
-  argument and the right argument is appended
- */
-
-static STRING*
-path_append(Interp *interp, STRING *l_path, STRING *r_path)
-{
-    l_path = path_guarantee_trailing_separator(interp, l_path);
-    l_path = string_append(interp, l_path , r_path);
-
-    return l_path;
-}
-
-/*
-  binary path arguments. A new string is created
-  that is the concatenation of the two path components
-  with a path-separator.
- */
-
-static STRING*
-path_concat(Interp *interp, STRING *l_path, STRING *r_path)
-{
-    STRING* join;
-
-    join = string_copy(interp, l_path);
-    join = path_guarantee_trailing_separator(interp, join);
-    join = string_append(interp, join , r_path);
-
-    return join;
-}
 
 #define LOAD_EXT_CODE_LAST 3
 
@@ -280,7 +162,7 @@
            string_to_cstring(interp, final ));
 #endif
 
-    final = path_finalize(interp, final );
+    final = parrot_path_platform_localize(interp, final );
 
     if (Parrot_stat_info_intval(interp, final , STAT_EXISTS)) {
         return final;
@@ -368,7 +250,7 @@
 #endif
 
     /* if this is an absolute path return it as is */
-    if (is_abs_path(interp, file))
+    if (parrot_path_is_abs(interp, file))
         return file;
 
     if (type & PARROT_RUNTIME_FT_DYNEXT)
@@ -383,13 +265,13 @@
     for (i = 0; i < n; ++i) {
         path = VTABLE_get_string_keyed_int(interp, paths, i);
         if (string_length(interp, prefix) &&
-           !is_abs_path(interp,path)) {
-            full_name = path_concat(interp, prefix , path);
+           !parrot_path_is_abs(interp,path)) {
+            full_name = parrot_path_concat(interp, prefix , path);
         }
         else
             full_name = string_copy(interp, path);
 
-        full_name = path_append(interp, full_name , file);
+        full_name = parrot_path_append(interp, full_name , file);
 
         full_name = ( type & PARROT_RUNTIME_FT_DYNEXT )
             ? try_load_path(interp, full_name)
@@ -484,63 +366,6 @@
 
 /*
 
-=item C<STRING *
-parrot_split_path_ext(Interp*, STRING *in, STRING **wo_ext, STRING **ext)>
-
-Split the pathstring C<in> into <path><filestem><ext>. Return the
-C<filestem> of the pathstring. Set C<wo_ext> to the part without
-extension and C<ext> to the extension or NULL.
-
-=cut
-
-*/
-
-STRING *
-parrot_split_path_ext(Interp* interp, STRING *in,
-        STRING **wo_ext, STRING **ext)
-{
-    STRING *slash1, *slash2, *dot, *stem;
-    INTVAL pos_sl, pos_dot, len;
-    slash1 = CONST_STRING(interp, "/");
-    slash2 = CONST_STRING(interp, "\\");
-    dot    = CONST_STRING(interp, ".");
-    len = string_length(interp, in);
-    pos_sl = CHARSET_RINDEX(interp, in, slash1, len);
-    if (pos_sl == -1)
-        pos_sl = CHARSET_RINDEX(interp, in, slash2, len);
-    pos_dot = CHARSET_RINDEX(interp, in, dot, len);
-
-    /* XXX directory parrot-0.4.1 or such */
-    if (pos_dot != -1 && isdigit(((char*)in->strstart)[pos_dot+1]))
-        pos_dot = -1;
-
-    ++pos_dot;
-    ++pos_sl;
-    if (pos_sl && pos_dot) {
-        stem = string_substr(interp, in, pos_sl, pos_dot - pos_sl - 1,
-                NULL, 0);
-        *wo_ext = string_substr(interp, in, 0, pos_dot - 1, NULL, 0);
-        *ext = string_substr(interp, in, pos_dot, len - pos_dot, NULL, 0);
-    }
-    else if (pos_dot) {
-        stem = string_substr(interp, in, 0, pos_dot - 1, NULL, 0);
-        *wo_ext = stem;
-        *ext = string_substr(interp, in, pos_dot, len - pos_dot, NULL, 0);
-    }
-    else if (pos_sl) {
-        stem = string_substr(interp, in, pos_sl, len - pos_sl, NULL, 0);
-        *wo_ext = string_copy(interp, in);
-        *ext = 0;
-    }
-    else {
-        stem = string_copy(interp, in);
-        *wo_ext = stem;
-        *ext = NULL;
-    }
-    return stem;
-}
-/*
-
 =back
 
 =head1 SEE ALSO
--- HEAD/include/parrot/library.h	2007-05-12 04:26:20.000000000 -0700
+++ path-api/include/parrot/library.h	2007-05-14 03:21:46.000000000 -0700
@@ -40,8 +40,6 @@
 
 PARROT_API char* Parrot_get_runtime_prefix(Interp *, STRING **prefix);
 void parrot_init_library_paths(Interp *);
-STRING * parrot_split_path_ext(Interp* , STRING *in,
-        STRING **wo_ext, STRING **ext);
 
 #endif /* PARROT_LIBRARY_H_GUARD */
 
--- HEAD/config/gen/makefiles/root.in	2007-05-12 15:41:35.000000000 -0700
+++ path-api/config/gen/makefiles/root.in	2007-05-14 03:50:54.000000000 -0700
@@ -483,6 +483,7 @@
     $(PF_DIR)/pf_items$(O) \
     $(SRC_DIR)/stm/backend$(O) \
     $(SRC_DIR)/stm/waitlist$(O) \
+    $(SRC_DIR)/path$(O) \
     @TEMP_gc_o@
 
 O_FILES = \
@@ -609,6 +610,7 @@
     $(SRC_DIR)/global.str \
     $(SRC_DIR)/global_setup.str \
     $(SRC_DIR)/library.str \
+    $(SRC_DIR)/path.str \
     $(SRC_DIR)/mmd.str \
     $(SRC_DIR)/pmc.str \
     $(SRC_DIR)/objects.str \

Attachment: signature.asc
Description: PGP signature

Reply via email to