Hello,

I was looking at Parrot_get_runtime_prefix as an example of getting
environment variable values the parrot way. The function looked
over-complicated so I tried a refactor.

The first thing to notice about the function is that it is possible to
leak memory with a call. I did not find any leaks but in checking this 
I noticed some API misfeature. This API is built to overload the return
value as either a STRING* or a char*. 

Every use in the tree is for a STRING* value, except compilers/immc/main.c
where the char* value is used in a format string right before parrot
terminates.

<snip rev-18443 compilers/imcc/main.c>
            case OPT_RUNTIME_PREFIX:
                printf("%s\n", Parrot_get_runtime_prefix(interp, NULL));
                exit(0);
                break;
</snip>

The other user outside of library.c specifically requests a leak-able
char* and then creates a string out of it which is ignorant AFAICT 
(is there a real reason for this ?)

<snip rev-18443 src/inter_misc.c>
        case RUNTIME_PREFIX:
            fullname_c = Parrot_get_runtime_prefix(interp, NULL);
            fullname = string_from_cstring(interp, fullname_c, 0);
            mem_sys_free(fullname_c);
            return fullname;
</snip>

This API function can be made alot simpler both use and implementation wise 
by having it return a STRING* every time. The overloading can be easily
replaced by helper functions nesting a call to Parrot_get_runtime_prefix.
I chose the STRING* as it is more useful and robust value to return.

-char*
-Parrot_get_runtime_prefix(Interp *interp, STRING **prefix_str)

+STRING*
+Parrot_get_runtime_prefix (Interp *interp ) {

I am inlining the patch for discussion. It is based against
rev-18443 with a rebase of #41908 applied. If This API
change is acceptable I will rebase it against HEAD clean.

Segway: I mentioned this on #parrot, jisom created a patch that returns
        char* instead of STRING*.

It passed the test-suite functionally, I tweaked it a little to pass codingstd
so it is not 100% verified. the Docs test is broken , I haven't played with the
docs yet so they are still out of sync with this prototype of the patch.

--- HEAD/src/library.c  2007-05-06 17:58:47.000000000 -0700
+++ rev-18443/src/library.c     2007-05-07 01:10:27.000000000 -0700
@@ -300,7 +377,7 @@
     else
         paths = get_search_paths(interp, PARROT_LIB_PATH_INCLUDE);
 
-    Parrot_get_runtime_prefix(interp, &prefix);
+    prefix = Parrot_get_runtime_prefix(interp);
     n = VTABLE_elements(interp, paths);
     for (i = 0; i < n; ++i) {
         path = VTABLE_get_string_keyed_int(interp, paths, i);
@@ -344,60 +425,90 @@
      */
     return string_to_cstring(interp, result);
 }
-/*
-
-=item C<char* Parrot_get_runtime_prefix(Interp *, STRING **prefix_str)>
 
-If C<prefix_str> is not NULL, set it to the prefix, else return a malloced
-c-string for the runtime prefix.  Remember to free the string with
-C<string_cstring_free()>.
+static STRING*
+query_runtime_prefix ( Interp* interp ) {
 
-=cut
-
-*/
+    STRING* prefix;
 
-char*
-Parrot_get_runtime_prefix(Interp *interp, STRING **prefix_str)
-{
-    STRING *s, *key;
-    PMC *config_hash;
     int free_it;
     char *env;
 
     env = Parrot_getenv("PARROT_RUNTIME", &free_it);
+
     if (env) {
-        if (prefix_str) {
-            *prefix_str = string_from_cstring(interp, env, 0);
-            if (free_it)
-                free(env);
-            return NULL;
-        }
-        if (!free_it)
-            env = strdup(env);
-        return env;
+        prefix = string_from_cstring(interp, env, 0);
+        if (free_it)
+            free(env);
+
+        return prefix;
     }
 
+    return NULL;
+}
+
+static STRING*
+default_runtime_prefix ( Interp* interp ) {
+
+    /* should this be a call to getcwd() ? */
+    const char *pwd = ".";
+
+    return const_string(interp, pwd);
+}
+
+/*
+
+=item C<STRING* Parrot_get_runtime_prefix(Interp * )>
+
+return the runtime prefix in the PMC string C<prefix>. The
+config hash is consulted first, then the environment variable
+PARROT_RUNTIME, and finally a hardcoded internal value is
+returned if that fails.
+=cut
+
+*/
+
+STRING*
+Parrot_get_runtime_prefix (Interp *interp ) {
+
+    PMC *config_hash;
+
+    STRING *key, *can_fail; /* can_fail , for storing string pointers from
+                               functions that may fail to return a prefix value
+                      */
+
+    /* first look in the config hash for a user specified path */
+
     config_hash = VTABLE_get_pmc_keyed_int(interp, interp->iglobals,
             (INTVAL) IGLOBALS_CONFIG_HASH);
-    key = CONST_STRING(interp, "prefix");
-    if (!VTABLE_elements(interp, config_hash)) {
-        const char *pwd = ".";
-        char *ret;
-
-        if (prefix_str) {
-            *prefix_str = const_string(interp, pwd);
-            return NULL;
+
+    if (VTABLE_elements(interp, config_hash)) {
+        key = CONST_STRING(interp, "prefix");
+        can_fail = VTABLE_get_string_keyed_str(interp, config_hash, key);
+
+        if ( can_fail ) {
+            /*
+              TODO:
+              shouldn't we do some sanity here ?  , assuming this can be
+              set by random code/input we should see if it even exists.
+            */
+
+            return can_fail;
         }
-        ret = (char *)mem_sys_allocate(3);
-        strcpy(ret, pwd);
-        return ret;
-    }
-    s = VTABLE_get_string_keyed_str(interp, config_hash, key);
-    if (prefix_str) {
-        *prefix_str = s;
-        return NULL;
     }
-    return string_to_cstring(interp, s);
+
+    /*
+      fallback:
+
+      no value was found in the config hash so try a system query, if
+      that fails as well return the default.
+    */
+
+    can_fail = query_runtime_prefix(interp);
+
+    return (can_fail)
+        ? can_fail
+        : default_runtime_prefix(interp);
 }
 
 /*
--- HEAD/include/parrot/library.h       2007-05-06 17:58:48.000000000 -0700
+++ rev-18443/include/parrot/library.h  2007-05-07 00:15:09.000000000 -0700
@@ -38,7 +38,7 @@
 PARROT_API STRING* Parrot_locate_runtime_file_str(Interp *, STRING *file_name,
         enum_runtime_ft);
 
-PARROT_API char* Parrot_get_runtime_prefix(Interp *, STRING **prefix);
+PARROT_API STRING* Parrot_get_runtime_prefix(Interp *);
 void parrot_init_library_paths(Interp *);
 STRING * parrot_split_path_ext(Interp* , STRING *in,
         STRING **wo_ext, STRING **ext);
--- HEAD/compilers/imcc/main.c  2007-04-21 06:34:57.000000000 -0700
+++ rev-18443/compilers/imcc/main.c     2007-05-07 01:10:49.000000000 -0700
@@ -272,7 +273,8 @@
                 exit(EX_USAGE);
                 break;
             case OPT_RUNTIME_PREFIX:
-                printf("%s\n", Parrot_get_runtime_prefix(interp, NULL));
+                printf("%s\n", string_to_cstring(interp,
+                                                 
Parrot_get_runtime_prefix(interp)) );
                 exit(0);
                 break;
             case 'V':
--- HEAD/src/inter_misc.c       2007-04-27 07:00:47.000000000 -0700
+++ rev-18443/src/inter_misc.c  2007-05-07 00:42:27.000000000 -0700
@@ -341,10 +342,7 @@
             return basename;
 
         case RUNTIME_PREFIX:
-            fullname_c = Parrot_get_runtime_prefix(interp, NULL);
-            fullname = string_from_cstring(interp, fullname_c, 0);
-            mem_sys_free(fullname_c);
-            return fullname;
+            return Parrot_get_runtime_prefix( interp );
 
         default:        /* or a warning only? */
             internal_exception(UNIMPLEMENTED,




Attachment: signature.asc
Description: PGP signature

Reply via email to