[88376] trunk/base

cal at macports.org cal at macports.org
Thu Dec 29 16:17:51 PST 2011


Revision: 88376
          http://trac.macports.org/changeset/88376
Author:   cal at macports.org
Date:     2011-12-29 16:17:49 -0800 (Thu, 29 Dec 2011)
Log Message:
-----------
Merge from ^/branches/gsoc11-rev-upgrade

Modified Paths:
--------------
    trunk/base/configure
    trunk/base/configure.ac
    trunk/base/doc/port.1
    trunk/base/src/Makefile.in
    trunk/base/src/cregistry/Makefile
    trunk/base/src/cregistry/entry.c
    trunk/base/src/cregistry/entry.h
    trunk/base/src/cregistry/registry.c
    trunk/base/src/cregistry/registry.h
    trunk/base/src/cregistry/sql.c
    trunk/base/src/cregistry/sql.h
    trunk/base/src/macports1.0/macports.tcl
    trunk/base/src/pextlib1.0/Pextlib.c
    trunk/base/src/port/port.tcl
    trunk/base/src/port1.0/port_autoconf.tcl.in
    trunk/base/src/registry2.0/Makefile
    trunk/base/src/registry2.0/entry.c
    trunk/base/src/registry2.0/portimage.tcl
    trunk/base/src/registry2.0/portuninstall.tcl
    trunk/base/src/registry2.0/receipt_flat.tcl
    trunk/base/src/registry2.0/registry.c
    trunk/base/src/registry2.0/registry.tcl
    trunk/base/src/registry2.0/util.c
    trunk/base/src/registry2.0/util.h

Added Paths:
-----------
    trunk/base/src/cregistry/file.c
    trunk/base/src/cregistry/file.h
    trunk/base/src/cregistry/util.c
    trunk/base/src/cregistry/util.h
    trunk/base/src/machista1.0/
    trunk/base/src/registry2.0/file.c
    trunk/base/src/registry2.0/file.h
    trunk/base/src/registry2.0/fileobj.c
    trunk/base/src/registry2.0/fileobj.h
    trunk/base/tests/test/svn-and-patchsites/

Removed Paths:
-------------
    trunk/base/tests/test/svn-and-patchsites/

Property Changed:
----------------
    trunk/base/
    trunk/base/portmgr/fedora/macports.spec
    trunk/base/src/machista1.0/tests/
    trunk/base/src/pextlib1.0/sha2.c
    trunk/base/src/pextlib1.0/sha2.h
    trunk/base/src/pextlib1.0/sha256cmd.c
    trunk/base/src/pextlib1.0/sha256cmd.h
    trunk/base/src/registry2.0/receipt_sqlite.tcl


Property changes on: trunk/base
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/gsoc08-privileges/base:37343-46937
/branches/gsoc09-logging/base:51231-60371
/branches/universal-sanity/base:51872-52323
/branches/variant-descs-14482/base:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes:45682-46060
/users/perry/base-select:44044-44692
   + /branches/gsoc08-privileges/base:37343-46937
/branches/gsoc09-logging/base:51231-60371
/branches/gsoc11-rev-upgrade/base:78828-88375
/branches/universal-sanity/base:51872-52323
/branches/variant-descs-14482/base:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes:45682-46060
/users/perry/base-select:44044-44692

Modified: trunk/base/configure
===================================================================
--- trunk/base/configure	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/configure	2011-12-30 00:17:49 UTC (rev 88376)
@@ -679,6 +679,7 @@
 TAR_CMD
 TAR_Q
 SED_EXT
+SWIG
 OPEN
 XAR
 PAX
@@ -844,6 +845,7 @@
 XZ
 XAR
 OPEN
+SWIG
 OBJCPP
 CPP'
 ac_subdirs_all='src/thread2.6'
@@ -1530,6 +1532,7 @@
   XZ          path to xz command
   XAR         path to xar command
   OPEN        path to open command
+  SWIG        path to swig command
   OBJCPP      Objective C preprocessor
   CPP         C preprocessor
 
@@ -5784,7 +5787,48 @@
 fi
 
 
+# Extract the first word of "swig", so it can be a program name with args.
+set dummy swig; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_SWIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $SWIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SWIG="$SWIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_SWIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
+  test -z "$ac_cv_path_SWIG" && ac_cv_path_SWIG="$PATH:/usr/local/bin"
+  ;;
+esac
+fi
+SWIG=$ac_cv_path_SWIG
+if test -n "$SWIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SWIG" >&5
+$as_echo "$SWIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
 # Define some precious variables allowing user to override PATH for some programs
 
 
@@ -5804,6 +5848,7 @@
 
 
 
+
 	# Extract the first word of "sed", so it can be a program name with args.
 set dummy sed; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
@@ -9740,7 +9785,7 @@
 
 
 # Output
-ac_config_files="$ac_config_files Doxyfile Makefile Mk/macports.autoconf.mk doc/base.mtree doc/prefix.mtree doc/macosx.mtree doc/macports.conf doc/pubkeys.conf portmgr/freebsd/Makefile src/Makefile src/macports1.0/macports_autoconf.tcl src/port1.0/port_autoconf.tcl src/registry2.0/registry_autoconf.tcl src/programs/Makefile src/macports1.0/macports_fastload.tcl setupenv.bash"
+ac_config_files="$ac_config_files Doxyfile Makefile Mk/macports.autoconf.mk doc/base.mtree doc/prefix.mtree doc/macosx.mtree doc/macports.conf doc/pubkeys.conf portmgr/freebsd/Makefile src/Makefile src/machista1.0/Makefile src/macports1.0/macports_autoconf.tcl src/port1.0/port_autoconf.tcl src/registry2.0/registry_autoconf.tcl src/programs/Makefile src/macports1.0/macports_fastload.tcl setupenv.bash"
 
 
 ac_config_files="$ac_config_files src/pkg_mkindex.sh"
@@ -10460,6 +10505,7 @@
     "doc/pubkeys.conf") CONFIG_FILES="$CONFIG_FILES doc/pubkeys.conf" ;;
     "portmgr/freebsd/Makefile") CONFIG_FILES="$CONFIG_FILES portmgr/freebsd/Makefile" ;;
     "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+    "src/machista1.0/Makefile") CONFIG_FILES="$CONFIG_FILES src/machista1.0/Makefile" ;;
     "src/macports1.0/macports_autoconf.tcl") CONFIG_FILES="$CONFIG_FILES src/macports1.0/macports_autoconf.tcl" ;;
     "src/port1.0/port_autoconf.tcl") CONFIG_FILES="$CONFIG_FILES src/port1.0/port_autoconf.tcl" ;;
     "src/registry2.0/registry_autoconf.tcl") CONFIG_FILES="$CONFIG_FILES src/registry2.0/registry_autoconf.tcl" ;;

Modified: trunk/base/configure.ac
===================================================================
--- trunk/base/configure.ac	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/configure.ac	2011-12-30 00:17:49 UTC (rev 88376)
@@ -126,6 +126,7 @@
 AC_PATH_PROG(PAX, [pax], [])
 AC_PATH_PROG(XAR, [xar], [])
 AC_PATH_PROG(OPEN, [open], [])
+AC_PATH_PROG(SWIG, [swig], [$PATH:/usr/local/bin])
 
 # Define some precious variables allowing user to override PATH for some programs
 AC_ARG_VAR(MTREE, [path to mtree command])
@@ -144,6 +145,7 @@
 AC_ARG_VAR(XZ, [path to xz command])
 AC_ARG_VAR(XAR, [path to xar command])
 AC_ARG_VAR(OPEN, [path to open command])
+AC_ARG_VAR(SWIG, [path to swig command])
 
 MP_SED_EXTENDED_REGEXP
 MP_TAR_FAST_READ
@@ -368,6 +370,7 @@
 	doc/pubkeys.conf
 	portmgr/freebsd/Makefile
 	src/Makefile
+	src/machista1.0/Makefile
 	src/macports1.0/macports_autoconf.tcl
 	src/port1.0/port_autoconf.tcl
 	src/registry2.0/registry_autoconf.tcl

Modified: trunk/base/doc/port.1
===================================================================
--- trunk/base/doc/port.1	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/doc/port.1	2011-12-30 00:17:49 UTC (rev 88376)
@@ -492,6 +492,24 @@
 upgrade will not normally rebuild a port only to change the selected 
 variants; you can either specify --enforce-variants, or deactivate the port and reinstall it 
 with different variants. 
+.Pp
+After the upgrade MacPorts will automatically run \fBrev-upgrade\fP to check for
+broken ports that need to be rebuilt. If there are known problems with
+\fBrev-upgrade\fP or other reasons why you would want to avoid running this
+step, you can disable it by running \fBport upgrade\fP with the
+\fB--no-rev-upgrade\fP switch:
+.Pp
+.Dl "port upgrade --no-rev-upgrade outdated"
+.Ss rev-upgrade
+Manually check for broken binaries and rebuild ports containing broken binaries.
+\fBrev-upgrade\fP is usually automatically run after each upgrade, unless you
+specify the \fB--no-rev-upgrade\fP option.
+.Pp
+\fBrev-upgrade\fP can run more checks against a special loadcommand in Mach-O
+binaries that should always be referencing the file itself. This check is most
+helpful for maintainers to check whether their ports have been built correctly.
+It is disabled by default and can be enabled by passing \fB--id-loadcmd-check\fP
+to \fBrev-upgrade\fP.
 .Ss clean
 Clean the files used for building
 .Ar portname .


Property changes on: trunk/base/portmgr/fedora/macports.spec
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/gsoc08-privileges/base/portmgr/fedora/macports.spec:37343-46937
/branches/universal-sanity/base/portmgr/fedora/macports.spec:51872-52323
/branches/variant-descs-14482/base/portmgr/fedora/macports.spec:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/trunk/base/portmgr/fedora/macports.spec.in:30388-57826
/users/perry/base-bugs_and_notes/portmgr/fedora/macports.spec:45682-46060
/users/perry/base-select/portmgr/fedora/macports.spec:44044-44692
   + /branches/gsoc08-privileges/base/portmgr/fedora/macports.spec:37343-46937
/branches/gsoc11-rev-upgrade/base/portmgr/fedora/macports.spec:78828-88375
/branches/universal-sanity/base/portmgr/fedora/macports.spec:51872-52323
/branches/variant-descs-14482/base/portmgr/fedora/macports.spec:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/trunk/base/portmgr/fedora/macports.spec.in:30388-57826
/users/perry/base-bugs_and_notes/portmgr/fedora/macports.spec:45682-46060
/users/perry/base-select/portmgr/fedora/macports.spec:44044-44692

Modified: trunk/base/src/Makefile.in
===================================================================
--- trunk/base/src/Makefile.in	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/Makefile.in	2011-12-30 00:17:49 UTC (rev 88376)
@@ -5,7 +5,8 @@
 			package1.0 \
 			pextlib1.0 \
 			registry2.0 \
-			darwintracelib1.0
+			darwintracelib1.0 \
+			machista1.0
 SUBDIR=		${TCLPKG} port programs
 
 all::

Modified: trunk/base/src/cregistry/Makefile
===================================================================
--- trunk/base/src/cregistry/Makefile	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/cregistry/Makefile	2011-12-30 00:17:49 UTC (rev 88376)
@@ -1,6 +1,6 @@
 # $Id$
 
-OBJS = registry.o entry.o sql.o vercomp.o
+OBJS = registry.o entry.o sql.o vercomp.o util.o file.o
 STLIB_NAME = cregistry.a
 RANLIB = ranlib
 

Modified: trunk/base/src/cregistry/entry.c
===================================================================
--- trunk/base/src/cregistry/entry.c	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/cregistry/entry.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -34,10 +34,11 @@
 #include "entry.h"
 #include "registry.h"
 #include "sql.h"
+#include "util.h"
 
-#include <string.h>
-#include <stdlib.h>
 #include <sqlite3.h>
+#include <stdlib.h>
+#include <string.h>
 
 /*
  * TODO: possibly, allow reg_entry_search to take different matching strategies
@@ -53,9 +54,6 @@
  *       always have very discrete values. These could be more efficiently dealt
  *       with as integers.
  *
- * TODO: move the utility functions to util.h or something. Not important until
- *       there are more types in the registry than entry, though.
- *
  * TODO: considering a "weak" flag in registry.files. The meaning of this would
  *       be "I wish for my version of this file to be activated when I am, but
  *       not to be deactivated when I am; nor should other ports be prevented
@@ -69,85 +67,6 @@
  */
 
 /**
- * Concatenates `src` to string `dst`. Simple concatenation. Only guaranteed to
- * work with strings that have been allocated with `malloc`. Amortizes cost of
- * expanding string buffer for O(N) concatenation and such. Uses `memcpy` in
- * favor of `strcpy` in hopes it will perform a bit better.
- *
- * @param [in,out] dst       a reference to a null-terminated string
- * @param [in,out] dst_len   number of characters currently in `dst`
- * @param [in,out] dst_space number of characters `dst` can hold
- * @param [in] src           string to concatenate to `dst`
- */
-static int reg_strcat(char** dst, size_t* dst_len, size_t* dst_space, char* src) {
-    size_t src_len = strlen(src);
-    size_t result_len = *dst_len + src_len;
-    if (result_len > *dst_space) {
-        char* new_dst;
-        *dst_space *= 2;
-        if (*dst_space < result_len) {
-            *dst_space = result_len;
-        }
-        new_dst = realloc(*dst, *dst_space * sizeof(char) + 1);
-        if (!new_dst)
-            return 0;
-        else
-            *dst = new_dst;
-    }
-    memcpy(*dst + *dst_len, src, src_len+1);
-    *dst_len = result_len;
-    return 1;
-}
-
-/**
- * Appends element `src` to the list `dst`. It's like `reg_strcat`, except `src`
- * represents a single element and not a sequence of `char`s.
- *
- * @param [in,out] dst       a reference to a list of pointers
- * @param [in,out] dst_len   number of elements currently in `dst`
- * @param [in,out] dst_space number of elements `dst` can hold
- * @param [in] src           elements to append to `dst`
- */
-static int reg_listcat(void*** dst, int* dst_len, int* dst_space, void* src) {
-    if (*dst_len == *dst_space) {
-        void** new_dst;
-        *dst_space *= 2;
-        new_dst = realloc(*dst, *dst_space * sizeof(void*));
-        if (!new_dst)
-            return 0;
-        else
-            *dst = new_dst;
-    }
-    (*dst)[*dst_len] = src;
-    (*dst_len)++;
-    return 1;
-}
-
-/**
- * Returns an expression to use for the given strategy. This should be passed as
- * the `fmt` argument of `sqlite3_mprintf`, with the key and value following.
- *
- * @param [in] strategy a strategy (one of the `reg_strategy_*` constants)
- * @param [out] errPtr  on error, a description of the error that occurred
- * @return              a sqlite3 expression if success; NULL if failure
- */
-static char* reg_strategy_op(reg_strategy strategy, reg_error* errPtr) {
-    switch (strategy) {
-        case reg_strategy_exact:
-            return "%q = '%q'";
-        case reg_strategy_glob:
-            return "%q GLOB '%q'";
-        case reg_strategy_regexp:
-            return "REGEXP(%q, '%q')";
-        default:
-            errPtr->code = REG_INVALID;
-            errPtr->description = "invalid matching strategy specified";
-            errPtr->free = NULL;
-            return NULL;
-    }
-}
-
-/**
  * Converts a `sqlite3_stmt` into a `reg_entry`. The first column of the stmt's
  * row must be the id of an entry; the second either `SQLITE_NULL` or the
  * address of the entry in memory.
@@ -159,7 +78,7 @@
  * @return              true if success; false if failure
  */
 static int reg_stmt_to_entry(void* userdata, void** entry, void* stmt,
-        reg_error* errPtr UNUSED) {
+        void* calldata UNUSED, reg_error* errPtr UNUSED) {
     int is_new;
     reg_registry* reg = (reg_registry*)userdata;
     sqlite_int64 id = sqlite3_column_int64(stmt, 0);
@@ -262,6 +181,7 @@
         char* revision, char* variants, char* epoch, reg_error* errPtr) {
     sqlite3_stmt* stmt = NULL;
     reg_entry* entry = NULL;
+    int lower_bound = 0;
     char* query;
     if (strlen(epoch) > 0) {
         query = "SELECT id FROM registry.ports WHERE name=? AND version=? "
@@ -286,7 +206,7 @@
             r = sqlite3_step(stmt);
             switch (r) {
                 case SQLITE_ROW:
-                    reg_stmt_to_entry(reg, (void**)&entry, stmt, errPtr);
+                    reg_stmt_to_entry(reg, (void**)&entry, stmt, &lower_bound, errPtr);
                     break;
                 case SQLITE_DONE:
                     errPtr->code = REG_NOT_FOUND;
@@ -416,72 +336,6 @@
 }
 
 /**
- * Convenience method for returning all objects of a given type from the
- * registry.
- *
- * @param [in] reg       registry to select objects from
- * @param [in] query     the select query to execute
- * @param [in] query_len length of the query (or -1 for automatic)
- * @param [out] objects  the objects selected
- * @param [in] fn        a function to convert sqlite3_stmts to the desired type
- * @param [in] del       a function to delete the desired type of object
- * @param [out] errPtr   on error, a description of the error that occurred
- * @return               the number of objects if success; negative if failure
- */
-static int reg_all_objects(reg_registry* reg, char* query, int query_len,
-        void*** objects, cast_function* fn, free_function* del,
-        reg_error* errPtr) {
-    void** results = malloc(10*sizeof(void*));
-    int result_count = 0;
-    int result_space = 10;
-    sqlite3_stmt* stmt = NULL;
-    if (!results || !fn) {
-        return -1;
-    }
-    if (sqlite3_prepare(reg->db, query, query_len, &stmt, NULL) == SQLITE_OK) {
-        int r;
-        reg_entry* entry;
-        do {
-            r = sqlite3_step(stmt);
-            switch (r) {
-                case SQLITE_ROW:
-                    if (fn(reg, (void**)&entry, stmt, errPtr)) {
-                        if (!reg_listcat(&results, &result_count, &result_space, entry)) {
-                            r = SQLITE_ERROR;
-                        }
-                    } else {
-                        r = SQLITE_ERROR;
-                    }
-                    break;
-                case SQLITE_DONE:
-                case SQLITE_BUSY:
-                    break;
-                default:
-                    reg_sqlite_error(reg->db, errPtr, query);
-                    break;
-            }
-        } while (r == SQLITE_ROW || r == SQLITE_BUSY);
-        sqlite3_finalize(stmt);
-        if (r == SQLITE_DONE) {
-            *objects = results;
-            return result_count;
-        } else if (del) {
-            int i;
-            for (i=0; i<result_count; i++) {
-                del(NULL, results[i]);
-            }
-        }
-    } else {
-        if (stmt) {
-            sqlite3_finalize(stmt);
-        }
-        reg_sqlite_error(reg->db, errPtr, query);
-    }
-    free(results);
-    return -1;
-}
-
-/**
  * Type-safe version of `reg_all_objects` for `reg_entry`.
  *
  * @param [in] reg       registry to select entries from
@@ -493,8 +347,9 @@
  */
 static int reg_all_entries(reg_registry* reg, char* query, int query_len,
         reg_entry*** objects, reg_error* errPtr) {
+    int lower_bound = 0;
     return reg_all_objects(reg, query, query_len, (void***)objects,
-            reg_stmt_to_entry, NULL, errPtr);
+            reg_stmt_to_entry, &lower_bound, NULL, errPtr);
 }
 
 /**
@@ -640,6 +495,7 @@
     int result = 0;
     sqlite3_stmt* stmt = NULL;
     char* query = "SELECT id FROM registry.files WHERE actual_path=? AND active";
+    int lower_bound = 0;
     if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
             && (sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC)
                 == SQLITE_OK)) {
@@ -649,7 +505,7 @@
             switch (r) {
                 case SQLITE_ROW:
                     result = reg_stmt_to_entry(reg, (void**)entry, stmt,
-                            errPtr);
+                            &lower_bound, errPtr);
                     break;
                 case SQLITE_DONE:
                     *entry = NULL;

Modified: trunk/base/src/cregistry/entry.h
===================================================================
--- trunk/base/src/cregistry/entry.h	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/cregistry/entry.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -36,12 +36,6 @@
 
 #include <sqlite3.h>
 
-typedef enum {
-    reg_strategy_exact = 1,
-    reg_strategy_glob = 2,
-    reg_strategy_regexp = 3
-} reg_strategy;
-
 typedef struct {
     sqlite_int64 id; /* rowid in database */
     reg_registry* reg; /* associated registry */

Copied: trunk/base/src/cregistry/file.c (from rev 88375, branches/gsoc11-rev-upgrade/base/src/cregistry/file.c)
===================================================================
--- trunk/base/src/cregistry/file.c	                        (rev 0)
+++ trunk/base/src/cregistry/file.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,353 @@
+/*
+ * file.c
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2011 Clemens Lang <cal at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "file.h"
+#include "util.h"
+#include "registry.h"
+#include "sql.h"
+
+#include <sqlite3.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Converts a `sqlite3_stmt` into a `reg_file`. The first column of the stmt's
+ * row must be the id of a file; the second column must be the path of a file;
+ * the third either `SQLITE_NULL` or the address of the entry in memory.
+ *
+ * @param [in] userdata sqlite3 database
+ * @param [out] file    file described by `stmt`
+ * @param [in] stmt     `sqlite3_stmt` with appropriate columns
+ * @param [out] errPtr  unused
+ * @return              true if success; false if failure
+ */
+static int reg_stmt_to_file(void* userdata, void** file, void* stmt,
+        void* calldata UNUSED, reg_error* errPtr UNUSED) {
+    int is_new;
+    reg_registry* reg = (reg_registry*)userdata;
+    reg_file_pk key;
+    Tcl_HashEntry* hash;
+    char* hashkey;
+
+    key.id = sqlite3_column_int64(stmt, 0);
+    key.path = strdup((const char*) sqlite3_column_text(stmt, 1));
+    if (!key.path) {
+        return 0;
+    }
+
+    hashkey = sqlite3_mprintf("%lld:%s", key.id, key.path);
+    if (!hashkey) {
+        free(key.path);
+        return 0;
+    }
+    hash = Tcl_CreateHashEntry(&reg->open_files,
+            hashkey, &is_new);
+    sqlite3_free(hashkey);
+
+    if (is_new) {
+        reg_file* f = malloc(sizeof(reg_file));
+        if (!f) {
+            free(key.path);
+            return 0;
+        }
+        f->reg = reg;
+        f->key = key;
+        f->proc = NULL;
+        *file = f;
+        Tcl_SetHashValue(hash, f);
+    } else {
+        free(key.path);
+        *file = Tcl_GetHashValue(hash);
+    }
+    return 1;
+}
+
+/**
+ * Opens an existing file in the registry.
+ *
+ * @param [in] reg      registry to open entry in
+ * @param [in] id       port id in the dabatase
+ * @param [in] path     file path in the database
+ * @param [out] errPtr  on error, a description of the error that occures
+ * @return              the file if success, NULL if failure
+ */
+reg_file* reg_file_open(reg_registry* reg, char* id, char* name,
+        reg_error* errPtr) {
+    sqlite3_stmt* stmt = NULL;
+    reg_file* file = NULL;
+    char* query = "SELECT id, path FROM registry.files WHERE id=? AND path=?";
+    int lower_bound = 0;
+
+    if ((sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
+            && (sqlite3_bind_text(stmt, 1, id, -1, SQLITE_STATIC)
+                == SQLITE_OK)
+            && (sqlite3_bind_text(stmt, 2, name, -1, SQLITE_STATIC)
+                == SQLITE_OK)) {
+        int r;
+        do {
+            r = sqlite3_step(stmt);
+            switch (r) {
+                case SQLITE_ROW:
+                    reg_stmt_to_file(reg, (void**)&file, stmt, &lower_bound,
+                            errPtr);
+                    break;
+                case SQLITE_DONE:
+                    errPtr->code = REG_NOT_FOUND;
+                    errPtr->description = sqlite3_mprintf("no matching file found for: "
+                            "id=%s, name=%s", id, name);
+                    errPtr->free = (reg_error_destructor*) sqlite3_free;
+                    break;
+                case SQLITE_BUSY:
+                    continue;
+                default:
+                    reg_sqlite_error(reg->db, errPtr, query);
+                    break;
+            }
+        } while (r == SQLITE_BUSY);
+    } else {
+        reg_sqlite_error(reg->db, errPtr, query);
+    }
+    if (stmt) {
+        sqlite3_finalize(stmt);
+    }
+    return file;
+}
+
+/**
+ * Type-safe version of `reg_all_objects` for `reg_file`.
+ *
+ * @param [in] reg       registry to select entries from
+ * @param [in] query     the select query to execute
+ * @param [in] query_len length of the query (or -1 for automatic)
+ * @param [out] objects  the files selected
+ * @param [out] errPtr   on error, a description of the error that occurred
+ * @return               the number of entries if success; negative if failure
+ */
+static int reg_all_files(reg_registry* reg, char* query, int query_len,
+        reg_file*** objects, reg_error* errPtr) {
+    int lower_bound = 0;
+    return reg_all_objects(reg, query, query_len, (void***)objects,
+            reg_stmt_to_file, &lower_bound, NULL, errPtr);
+}
+
+/**
+ * Searches the registry for files for which each key's value is equal to the
+ * given value. To find all files, pass a key_count of 0.
+ *
+ * Bad keys should cause sqlite3 errors but not permit SQL injection attacks.
+ * Pass it good keys anyway.
+ *
+ * @param [in] reg       registry to search in
+ * @param [in] keys      a list of keys to search by
+ * @param [in] vals      a list of values to search by, matching keys
+ * @param [in] strats    a list of strategies to use when searching
+ * @param [in] key_count the number of key/value pairs passed
+ * @param [out] files    a list of matching files
+ * @param [out] errPtr   on error, a description of the error that occurred
+ * @return               the number of entries if success; false if failure
+ */
+int reg_file_search(reg_registry* reg, char** keys, char** vals, int* strats,
+        int key_count, reg_file*** files, reg_error* errPtr) {
+    int i;
+    char* kwd = " WHERE ";
+    char* query;
+    size_t query_len, query_space;
+    int result;
+
+    /* build the query */
+    query = strdup("SELECT id, path FROM registry.files");
+    if (!query) {
+        return -1;
+    }
+    query_len = query_space = strlen(query);
+
+    for (i = 0; i < key_count; i++) {
+        char* op;
+        char* cond;
+
+        /* get the strategy */
+        if ((op = reg_strategy_op(strats[i], errPtr)) == NULL) {
+            free(query);
+            return -1;
+        }
+
+        cond = sqlite3_mprintf(op, keys[i], vals[i]);
+        if (!cond || !reg_strcat(&query, &query_len, &query_space, kwd)
+            || !reg_strcat(&query, &query_len, &query_space, cond)) {
+            free(query);
+            return -1;
+        }
+        sqlite3_free(cond);
+        kwd = " AND ";
+    }
+
+    /* do the query */
+    result = reg_all_files(reg, query, -1, files, errPtr);
+    free(query);
+    return result;
+}
+
+/**
+ * Gets a named property of a file. That property can be set using
+ * `reg_file_propset`. The property named must be one that exists in the table
+ * and must not be one with internal meaning such as `id`.
+ *
+ * @param [in] file    file to get property from
+ * @param [in] key     property to get
+ * @param [out] value  the value of the property
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return             true if success; false if failure
+ */
+int reg_file_propget(reg_file* file, char* key, char** value,
+        reg_error* errPtr) {
+    reg_registry* reg = file->reg;
+    int result = 0;
+    sqlite3_stmt* stmt = NULL;
+    char* query;
+    const char *text;
+    query = sqlite3_mprintf("SELECT %q FROM registry.files WHERE id=%lld "
+            "AND path='%q'", key, file->key.id, file->key.path);
+    if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
+        int r;
+        do {
+            r = sqlite3_step(stmt);
+            switch (r) {
+                case SQLITE_ROW:
+                    text = (const char*)sqlite3_column_text(stmt, 0);
+                    if (text) {
+                        *value = strdup(text);
+                        result = 1;
+                    } else {
+                        reg_sqlite_error(reg->db, errPtr, query);
+                    }
+                    break;
+                case SQLITE_DONE:
+                    errPtr->code = REG_INVALID;
+                    errPtr->description = "an invalid file was passed";
+                    errPtr->free = NULL;
+                    break;
+                case SQLITE_BUSY:
+                    continue;
+                default:
+                    reg_sqlite_error(reg->db, errPtr, query);
+                    break;
+            }
+        } while (r == SQLITE_BUSY);
+    } else {
+        reg_sqlite_error(reg->db, errPtr, query);
+    }
+    if (stmt) {
+        sqlite3_finalize(stmt);
+    }
+    sqlite3_free(query);
+    return result;
+}
+
+/**
+ * Sets a named property of a file. That property can be later retrieved using
+ * `reg_file_propget`. The property named must be one that exists in the table
+ * and must not be one with internal meaning such as `id`.
+ *
+ * @param [in] file    file to set property for
+ * @param [in] key     property to set
+ * @param [in] value   the desired value of the property
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return             true if success; false if failure
+ */
+int reg_file_propset(reg_file* file, char* key, char* value,
+        reg_error* errPtr) {
+    reg_registry* reg = file->reg;
+    int result = 0;
+    sqlite3_stmt* stmt = NULL;
+    char* query;
+    query = sqlite3_mprintf("UPDATE registry.files SET %q = '%q' WHERE id=%lld "
+            "AND path='%q'", key, value, file->key.id, file->key.path);
+    if (sqlite3_prepare(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
+        int r;
+        do {
+            r = sqlite3_step(stmt);
+            switch (r) {
+                case SQLITE_DONE:
+                    result = 1;
+                    break;
+                case SQLITE_BUSY:
+                    continue;
+                default:
+                    if (sqlite3_reset(stmt) == SQLITE_CONSTRAINT) {
+                        errPtr->code = REG_CONSTRAINT;
+                        errPtr->description = "a constraint was disobeyed";
+                        errPtr->free = NULL;
+                    } else {
+                        reg_sqlite_error(reg->db, errPtr, query);
+                    }
+                    break;
+            }
+        } while (r == SQLITE_BUSY);
+    } else {
+        reg_sqlite_error(reg->db, errPtr, query);
+    }
+    if (stmt) {
+        sqlite3_finalize(stmt);
+    }
+    sqlite3_free(query);
+    return result;
+}
+
+/**
+ * Fetches a list of all open files
+ *
+ * @param [in] reg      registry to fetch files from
+ * @param [out] files   a list of open files
+ * @return              the number of open entries, -1 on error
+ */
+int reg_all_open_files(reg_registry* reg, reg_file*** files) {
+    reg_file* file;
+    int file_count = 0;
+    int file_space = 10;
+    Tcl_HashEntry* hash;
+    Tcl_HashSearch search;
+    *files = malloc(10 * sizeof(void*));
+    if (!*files) {
+        return -1;
+    }
+    for (hash = Tcl_FirstHashEntry(&reg->open_files, &search); hash != NULL;
+            hash = Tcl_NextHashEntry(&search)) {
+        file = Tcl_GetHashValue(hash);
+        if (!reg_listcat((void***)files, &file_count, &file_space, file)) {
+            free(*files);
+            return -1;
+        }
+    }
+    return file_count;
+}
+

Copied: trunk/base/src/cregistry/file.h (from rev 88375, branches/gsoc11-rev-upgrade/base/src/cregistry/file.h)
===================================================================
--- trunk/base/src/cregistry/file.h	                        (rev 0)
+++ trunk/base/src/cregistry/file.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,66 @@
+/*
+ * file.h
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2011 Clemens Lang <cal at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _CFILE_H
+#define _CFILE_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "registry.h"
+
+#include <sqlite3.h>
+
+typedef struct {
+    /* rowid and path form the primary key */
+    /* unfortunately, we don't have a surrogate key in this db */
+    sqlite_int64 id; /* rowid in the database */
+    char* path; /* path in the database */
+} reg_file_pk;
+
+typedef struct {
+    reg_file_pk key;
+    reg_registry* reg; /* associated registry */
+    char* proc; /* name of Tcl proc, if using Tcl */
+} reg_file;
+
+reg_file* reg_file_open(reg_registry* reg, char* id, char* path,
+        reg_error* errPtr);
+
+int reg_file_search(reg_registry* reg, char** keys, char** vals, int* strats,
+        int key_count, reg_file*** files, reg_error* errPtr);
+
+int reg_file_propget(reg_file* file, char* key, char** value,
+        reg_error* errPtr);
+int reg_file_propset(reg_file* file, char* key, char* value,
+        reg_error* errPtr);
+
+int reg_all_open_files(reg_registry* reg, reg_file*** files);
+
+#endif /* _CFILE_H */

Modified: trunk/base/src/cregistry/registry.c
===================================================================
--- trunk/base/src/cregistry/registry.c	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/cregistry/registry.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -1,6 +1,7 @@
 /*
  * registry.c
  * $Id$
+ * vim:expandtab:tw=80
  *
  * Copyright (c) 2007 Chris Pickel <sfiera at macports.org>
  * All rights reserved.
@@ -31,6 +32,7 @@
 #endif
 
 #include "entry.h"
+#include "file.h"
 #include "sql.h"
 
 #include <stdio.h>
@@ -214,6 +216,8 @@
                         if (initialized || (create_tables(reg->db, errPtr))) {
                             Tcl_InitHashTable(&reg->open_entries,
                                     sizeof(sqlite_int64)/sizeof(int));
+                            Tcl_InitHashTable(&reg->open_files,
+                                    TCL_STRING_KEYS);
                             reg->status |= reg_attached;
                             result = 1;
                         }
@@ -224,6 +228,10 @@
                         reg_sqlite_error(reg->db, errPtr, query);
                 }
             } while (r == SQLITE_BUSY);
+
+            if (result) {
+                result &= update_db(reg->db, errPtr);
+            }
         } else {
             reg_sqlite_error(reg->db, errPtr, query);
         }
@@ -275,6 +283,15 @@
                         free(entry);
                     }
                     Tcl_DeleteHashTable(&reg->open_entries);
+                    for (curr = Tcl_FirstHashEntry(&reg->open_files, &search);
+                            curr != NULL; curr = Tcl_NextHashEntry(&search)) {
+                        reg_file* file = Tcl_GetHashValue(curr);
+
+                        free(file->proc);
+                        free(file->key.path);
+                        free(file);
+                    }
+                    Tcl_DeleteHashTable(&reg->open_files);
                     reg->status &= ~reg_attached;
                     result = 1;
                     break;

Modified: trunk/base/src/cregistry/registry.h
===================================================================
--- trunk/base/src/cregistry/registry.h	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/cregistry/registry.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -1,5 +1,6 @@
 /*
  * registry.h
+ * vim:tw=80:expandtab
  * $Id$
  *
  * Copyright (c) 2007 Chris Pickel <sfiera at macports.org>
@@ -56,7 +57,7 @@
 void reg_throw(reg_error* errPtr, char* code, char* fmt, ...);
 
 typedef int (cast_function)(void* userdata, void** dst, void* src,
-        reg_error* errPtr);
+        void* calldata, reg_error* errPtr);
 typedef void (free_function)(void* userdata, void* item);
 
 enum {
@@ -70,6 +71,7 @@
     sqlite3* db;
     int status;
     Tcl_HashTable open_entries;
+    Tcl_HashTable open_files;
 } reg_registry;
 
 int reg_open(reg_registry** regPtr, reg_error* errPtr);

Modified: trunk/base/src/cregistry/sql.c
===================================================================
--- trunk/base/src/cregistry/sql.c	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/cregistry/sql.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -34,8 +34,9 @@
 #include "sql.h"
 #include "vercomp.h"
 
+#include <sqlite3.h>
+#include <string.h>
 #include <tcl.h>
-#include <sqlite3.h>
 #include <time.h>
 
 /**
@@ -108,7 +109,7 @@
 
         /* metadata table */
         "CREATE TABLE registry.metadata (key UNIQUE, value)",
-        "INSERT INTO registry.metadata (key, value) VALUES ('version', 1.000)",
+        "INSERT INTO registry.metadata (key, value) VALUES ('version', 1.100)",
         "INSERT INTO registry.metadata (key, value) VALUES ('created', strftime('%s', 'now'))",
 
         /* ports table */
@@ -130,11 +131,12 @@
 
         /* file map */
         "CREATE TABLE registry.files (id INTEGER, path TEXT, actual_path TEXT, "
-            "active INT, mtime DATETIME, md5sum TEXT, editable INT, "
+            "active INT, mtime DATETIME, md5sum TEXT, editable INT, binary BOOL, "
             "FOREIGN KEY(id) REFERENCES ports(id))",
         "CREATE INDEX registry.file_port ON files (id)",
         "CREATE INDEX registry.file_path ON files(path)",
         "CREATE INDEX registry.file_actual ON files(actual_path)",
+        "CREATE INDEX registry.file_binary ON files(binary)",
 
         /* dependency map */
         "CREATE TABLE registry.dependencies (id INTEGER, name TEXT, variants TEXT, "
@@ -148,6 +150,57 @@
 }
 
 /**
+ * Updates the database if necessary. This function queries the current database version
+ * from the metadata table and executes SQL to update the schema to newer versions if needed.
+ * After that, this function updates the database version number
+ *
+ * @param [in] db      database to update
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return             true if success; false if failure
+ */
+int update_db(sqlite3* db, reg_error* errPtr) {
+    const char* version;
+    char* query = "SELECT value FROM registry.metadata WHERE key = 'version'";
+    sqlite3_stmt *stmt = NULL;
+
+    if ((sqlite3_prepare(db, query, -1, &stmt, NULL) != SQLITE_OK)
+            || (sqlite3_step(stmt) != SQLITE_ROW)) {
+        goto reg_err_out;
+    }
+    if (NULL == (version = (const char *)sqlite3_column_text(stmt, 0))) {
+        goto reg_err_out;
+    }
+    /* can't call rpm_vercomp directly, because it is static, but can call sql_version */
+    if (sql_version(NULL, strlen(version), version, strlen("1.1"), "1.1") < 0) {
+        /* conversion necessary, add binary field and index to files table */
+        static char* version_1_1_queries[] = {
+            "BEGIN",
+
+            "ALTER TABLE registry.files ADD COLUMN binary BOOL",
+            "CREATE INDEX registry.file_binary ON files(binary)",
+
+            "UPDATE registry.metadata SET value = '1.100' WHERE key = 'version'",
+
+            "COMMIT"
+        };
+
+        if (!do_queries(db, version_1_1_queries, errPtr)) {
+            goto err_out;
+        }
+
+        /* TODO: Walk the file tree and set the binary field */
+    }
+    sqlite3_finalize(stmt);
+    return 1;
+
+reg_err_out:
+    reg_sqlite_error(db, errPtr, query);
+err_out:
+    sqlite3_finalize(stmt);
+    return 0;
+}
+
+/**
  * Initializes database connection. This function creates all the temporary
  * tables used by the registry. It also registers the user functions and
  * collations declared here, making them available.

Modified: trunk/base/src/cregistry/sql.h
===================================================================
--- trunk/base/src/cregistry/sql.h	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/cregistry/sql.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -38,5 +38,6 @@
 
 int create_tables(sqlite3* db, reg_error* errPtr);
 int init_db(sqlite3* db, reg_error* errPtr);
+int update_db(sqlite3* db, reg_error* errPtr);
 
 #endif /* _SQL_H */

Copied: trunk/base/src/cregistry/util.c (from rev 88375, branches/gsoc11-rev-upgrade/base/src/cregistry/util.c)
===================================================================
--- trunk/base/src/cregistry/util.c	                        (rev 0)
+++ trunk/base/src/cregistry/util.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,182 @@
+/*
+ * util.c
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2007 Chris Pickel <sfiera at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "util.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Concatenates `src` to string `dst`. Simple concatenation. Only guaranteed to
+ * work with strings that have been allocated with `malloc`. Amortizes cost of
+ * expanding string buffer for O(N) concatenation and such. Uses `memcpy` in
+ * favor of `strcpy` in hopes it will perform a bit better.
+ *
+ * @param [in,out] dst       a reference to a null-terminated string
+ * @param [in,out] dst_len   number of characters currently in `dst`
+ * @param [in,out] dst_space number of characters `dst` can hold
+ * @param [in] src           string to concatenate to `dst`
+ */
+int reg_strcat(char** dst, size_t* dst_len, size_t* dst_space, char* src) {
+    size_t src_len = strlen(src);
+    size_t result_len = *dst_len + src_len;
+    if (result_len > *dst_space) {
+        char* new_dst;
+        *dst_space *= 2;
+        if (*dst_space < result_len) {
+            *dst_space = result_len;
+        }
+        new_dst = realloc(*dst, *dst_space * sizeof(char) + 1);
+        if (!new_dst)
+            return 0;
+        else
+            *dst = new_dst;
+    }
+    memcpy(*dst + *dst_len, src, src_len+1);
+    *dst_len = result_len;
+    return 1;
+}
+
+/**
+ * Appends element `src` to the list `dst`. It's like `reg_strcat`, except `src`
+ * represents a single element and not a sequence of `char`s.
+ *
+ * @param [in,out] dst       a reference to a list of pointers
+ * @param [in,out] dst_len   number of elements currently in `dst`
+ * @param [in,out] dst_space number of elements `dst` can hold
+ * @param [in] src           elements to append to `dst`
+ */
+int reg_listcat(void*** dst, int* dst_len, int* dst_space, void* src) {
+    if (*dst_len == *dst_space) {
+        void** new_dst;
+        *dst_space *= 2;
+        new_dst = realloc(*dst, *dst_space * sizeof(void*));
+        if (!new_dst)
+            return 0;
+        else
+            *dst = new_dst;
+    }
+    (*dst)[*dst_len] = src;
+    (*dst_len)++;
+    return 1;
+}
+
+/**
+ * Returns an expression to use for the given strategy. This should be passed as
+ * the `fmt` argument of `sqlite3_mprintf`, with the key and value following.
+ *
+ * @param [in] strategy a strategy (one of the `reg_strategy_*` constants)
+ * @param [out] errPtr  on error, a description of the error that occurred
+ * @return              a sqlite3 expression if success; NULL if failure
+ */
+char* reg_strategy_op(reg_strategy strategy, reg_error* errPtr) {
+    switch (strategy) {
+        case reg_strategy_exact:
+            return "%q = '%q'";
+        case reg_strategy_glob:
+            return "%q GLOB '%q'";
+        case reg_strategy_regexp:
+            return "REGEXP(%q, '%q')";
+        case reg_strategy_null:
+            return "%q IS NULL";
+        default:
+            errPtr->code = REG_INVALID;
+            errPtr->description = "invalid matching strategy specified";
+            errPtr->free = NULL;
+            return NULL;
+    }
+}
+
+/**
+ * Convenience method for returning all objects of a given type from the
+ * registry.
+ *
+ * @param [in] reg       registry to select objects from
+ * @param [in] query     the select query to execute
+ * @param [in] query_len length of the query (or -1 for automatic)
+ * @param [out] objects  the objects selected
+ * @param [in] fn        a function to convert sqlite3_stmts to the desired type
+ * @param [in] del       a function to delete the desired type of object
+ * @param [out] errPtr   on error, a description of the error that occurred
+ * @return               the number of objects if success; negative if failure
+ */
+int reg_all_objects(reg_registry* reg, char* query, int query_len,
+        void*** objects, cast_function* fn, void* castcalldata,
+        free_function* del, reg_error* errPtr) {
+    void** results = malloc(10*sizeof(void*));
+    int result_count = 0;
+    int result_space = 10;
+    sqlite3_stmt* stmt = NULL;
+    if (!results || !fn) {
+        return -1;
+    }
+    if (sqlite3_prepare(reg->db, query, query_len, &stmt, NULL) == SQLITE_OK) {
+        int r;
+        void* row;
+        do {
+            r = sqlite3_step(stmt);
+            switch (r) {
+                case SQLITE_ROW:
+                    if (fn(reg, &row, stmt, castcalldata, errPtr)) {
+                        if (!reg_listcat(&results, &result_count, &result_space, row)) {
+                            r = SQLITE_ERROR;
+                        }
+                    } else {
+                        r = SQLITE_ERROR;
+                    }
+                    break;
+                case SQLITE_DONE:
+                    break;
+                case SQLITE_BUSY:
+                    continue;
+                default:
+                    reg_sqlite_error(reg->db, errPtr, query);
+                    break;
+            }
+        } while (r == SQLITE_ROW || r == SQLITE_BUSY);
+        sqlite3_finalize(stmt);
+        if (r == SQLITE_DONE) {
+            *objects = results;
+            return result_count;
+        } else if (del) {
+            int i;
+            for (i=0; i<result_count; i++) {
+                del(NULL, results[i]);
+            }
+        }
+    } else {
+        if (stmt) {
+            sqlite3_finalize(stmt);
+        }
+        reg_sqlite_error(reg->db, errPtr, query);
+    }
+    free(results);
+    return -1;
+}
+

Copied: trunk/base/src/cregistry/util.h (from rev 88375, branches/gsoc11-rev-upgrade/base/src/cregistry/util.h)
===================================================================
--- trunk/base/src/cregistry/util.h	                        (rev 0)
+++ trunk/base/src/cregistry/util.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,53 @@
+/*
+ * util.h
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2011 Clemens Lang <cal at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _CUTIL_H
+#define _CUTIL_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "registry.h"
+
+typedef enum {
+    reg_strategy_exact = 1,
+    reg_strategy_glob = 2,
+    reg_strategy_regexp = 3,
+    reg_strategy_null = 4
+} reg_strategy;
+
+int reg_strcat(char** dst, size_t* dst_len, size_t* dst_space, char* src);
+int reg_listcat(void*** dst, int* dst_len, int* dst_space, void* src);
+int reg_all_objects(reg_registry* reg, char* query, int query_len,
+        void*** objects, cast_function* fn, void* castcalldata,
+        free_function* del, reg_error* errPtr);
+char* reg_strategy_op(reg_strategy strategy, reg_error* errPtr);
+
+#endif /* _CUTIL_H */
+


Property changes on: trunk/base/src/machista1.0
___________________________________________________________________
Added: svn:ignore
   + machista.dylib
pkgIndex.tcl
Makefile


Modified: trunk/base/src/macports1.0/macports.tcl
===================================================================
--- trunk/base/src/macports1.0/macports.tcl	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/macports1.0/macports.tcl	2011-12-30 00:17:49 UTC (rev 88376)
@@ -37,6 +37,7 @@
 package require macports_dlist 1.0
 package require macports_index 1.0
 package require macports_util 1.0
+package require machista 1.0
 
 namespace eval macports {
     namespace export bootstrap_options user_options portinterp_options open_mports ui_priorities port_phases 
@@ -69,6 +70,8 @@
     variable ui_priorities "error warn msg notice info debug any"
     variable port_phases "any fetch checksum"
     variable current_phase "main"
+
+    variable ui_prefix "---> "
 }
 
 # Provided UI instantiations
@@ -1702,7 +1705,7 @@
             }
         }
 
-        ui_msg -nonewline "--->  Computing dependencies for [_mportkey $mport subport]"
+        ui_msg -nonewline "$macports::ui_prefix Computing dependencies for [_mportkey $mport subport]"
         if {[macports::ui_isset ports_debug]} {
             # play nice with debug messages
             ui_msg ""
@@ -1722,7 +1725,7 @@
         
         # print the dep list
         if {[llength $dlist] > 0} {
-            set depstring "--->  Dependencies to be installed:"
+            set depstring "$macports::ui_prefix Dependencies to be installed:"
             foreach ditem $dlist {
                 append depstring " [ditem_key $ditem provides]"
             }
@@ -2969,7 +2972,7 @@
     ui_debug "MacPorts sources location: $mp_source_path"
 
     # sync the MacPorts sources
-    ui_msg "--->  Updating MacPorts base sources using rsync"
+    ui_msg "$macports::ui_prefix Updating MacPorts base sources using rsync"
     if { [catch { system "$rsync_path $rsync_options rsync://${rsync_server}/${rsync_dir} $mp_source_path" } result ] } {
        return -code error "Error synchronizing MacPorts sources: $result"
     }
@@ -3042,7 +3045,7 @@
 
     # syncing ports tree.
     if {![info exists options(ports_selfupdate_nosync)] || $options(ports_selfupdate_nosync) != "yes"} {
-        ui_msg "--->  Updating the ports tree"
+        ui_msg "$macports::ui_prefix Updating the ports tree"
         if {$comp > 0} {
             # updated portfiles potentially need new base to parse - tell sync to try to 
             # use prefabricated PortIndex files and signal if it couldn't
@@ -3055,9 +3058,9 @@
 
     if {$use_the_force_luke == "yes" || $comp > 0} {
         if {[info exists options(ports_dryrun)] && $options(ports_dryrun) == "yes"} {
-            ui_msg "--->  MacPorts base is outdated, selfupdate would install $macports_version_new (dry run)"
+            ui_msg "$macports::ui_prefix MacPorts base is outdated, selfupdate would install $macports_version_new (dry run)"
         } else {
-            ui_msg "--->  MacPorts base is outdated, installing new version $macports_version_new"
+            ui_msg "$macports::ui_prefix MacPorts base is outdated, installing new version $macports_version_new"
 
             # get installation user/group and permissions
             set owner [file attributes ${prefix} -owner]
@@ -3107,9 +3110,9 @@
             }
         }
     } elseif {$comp < 0} {
-        ui_msg "--->  MacPorts base is probably trunk or a release candidate"
+        ui_msg "$macports::ui_prefix MacPorts base is probably trunk or a release candidate"
     } else {
-        ui_msg "--->  MacPorts base is already the latest version"
+        ui_msg "$macports::ui_prefix MacPorts base is already the latest version"
     }
 
     # set the MacPorts sources to the right owner
@@ -3158,6 +3161,7 @@
     if {!$orig_nodeps} {
         unset -nocomplain macports::global_options(ports_nodeps)
     }
+
     return $status
 }
 
@@ -3176,6 +3180,16 @@
         set is_dryrun yes
     }
 
+    # Is this a rev-upgrade-called run?
+    set is_revupgrade no
+    if {[macports::global_option_isset ports_revupgrade]} {
+        set is_revupgrade yes
+    }
+    set is_revupgrade_second_run no
+    if {[macports::global_option_isset ports_revupgrade_second_run]} {
+        set is_revupgrade_second_run yes
+    }
+
     # check if the port is in tree
     if {[catch {mportlookup $portname} result]} {
         global errorInfo
@@ -3369,7 +3383,7 @@
     
     # at this point we need to check if a different port will be replacing this one
     if {[info exists portinfo(replaced_by)] && ![info exists options(ports_upgrade_no-replace)]} {
-        ui_msg "--->  $portname is replaced by $portinfo(replaced_by)"
+        ui_msg "$macports::ui_prefix $portname is replaced by $portinfo(replaced_by)"
         if {[catch {mportlookup $portinfo(replaced_by)} result]} {
             global errorInfo
             ui_debug "$errorInfo"
@@ -3431,6 +3445,11 @@
                   || [_mportkey $workername "{os.major}"] != $os_major_installed)} {
             ui_debug "platform mismatch ... upgrading!"
             set build_override 1
+        } elseif {$is_revupgrade_second_run} {
+            set build_override 1
+        } elseif {$is_revupgrade} {
+            # in the first run of rev-upgrade, only activate possibly already existing files and check for missing dependencies
+            set will_install yes
         } else {
             if {[info exists portinfo(canonical_active_variants)] && $portinfo(canonical_active_variants) != $oldvariant} {
                 if {[llength $variationslist] > 0} {
@@ -3447,13 +3466,15 @@
 
     set will_build no
     # avoid building again unnecessarily
-    if {$will_install && ([info exists options(ports_upgrade_force)] || $build_override == 1
-        || ![registry::entry_exists $newname $version_in_tree $revision_in_tree $portinfo(canonical_active_variants)])} {
+    if {$will_install &&
+        ([info exists options(ports_upgrade_force)]
+            || $build_override == 1
+            || ![registry::entry_exists $newname $version_in_tree $revision_in_tree $portinfo(canonical_active_variants)])} {
         set will_build yes
     }
 
     # first upgrade dependencies
-    if {![info exists options(ports_nodeps)]} {
+    if {![info exists options(ports_nodeps)] && !$is_revupgrade} {
         set status [_upgrade_dependencies portinfo depscache variationslist options $will_build]
         if {$status != 0 && $status != 2 && ![ui_isset ports_processall]} {
             catch {mportclose $workername}
@@ -3810,3 +3831,406 @@
         return "/tmp"
     }
 }
+
+proc macports::revupgrade {opts} {
+    set run_loop 1
+    array set broken_port_counts {}
+    while {$run_loop == 1} {
+        set run_loop [revupgrade_scanandrebuild broken_port_counts $opts]
+    }
+    return 0;
+}
+
+# returns 1 if ports were rebuilt and revupgrade_scanandrebuild should be called again
+proc revupgrade_scanandrebuild {broken_port_counts_name opts} {
+    upvar $broken_port_counts_name broken_port_counts
+    array set options $opts
+
+    set files [registry::file search active 1 binary -null]
+    if {[llength $files] > 0} {
+        set files_count [llength $files]
+        registry::write {
+            try {
+                ui_msg -nonewline "$macports::ui_prefix Updating database of binaries"
+                set i 1
+                foreach f $files {
+                    if {![macports::ui_isset ports_debug]} {
+                        ui_msg -nonewline "\r$macports::ui_prefix Updating database of binaries: [expr $i * 100 / $files_count]%"
+                        flush stdout
+                    }
+                    ui_debug "Updating binary flag for file $i of [llength $files]: [$f path]"
+                    incr i
+                    $f binary [fileIsBinary [$f path]]
+                }
+            } catch {*} {
+                ui_error "Updating database of binaries failed"
+                throw
+            }
+        }
+        ui_msg ""
+    }
+
+    set broken_files {};
+    set binaries [registry::file search active 1 binary 1]
+    ui_msg -nonewline "$macports::ui_prefix Scanning binaries for linking errors"
+    if {[llength $binaries] > 0} {
+        set handle [machista::create_handle]
+        if {$handle == "NULL"} {
+            error "Error creating libmachista handle"
+        }
+        array unset files_warned_about
+        array set files_warned_about [list]
+
+        set i 1
+        set binary_count [llength $binaries]
+        foreach b $binaries {
+            if {![macports::ui_isset ports_debug]} {
+                ui_msg -nonewline "\r$macports::ui_prefix Scanning binaries for linking errors: [expr $i * 100 / $binary_count]%"
+                flush stdout
+            }
+            #ui_debug "$i/[llength $binaries]: [$b path]"
+            incr i
+
+            set resultlist [machista::parse_file $handle [$b path]]
+            set returncode [lindex $resultlist 0]
+            set result     [lindex $resultlist 1]
+
+            if {$returncode != $machista::SUCCESS} {
+                if {$returncode == $machista::EMAGIC} {
+                    # not a Mach-O file
+                    # ignore silently, these are only static libs anyway
+                    #ui_debug "Error parsing file [$b path]: [machista::strerror $returncode]"
+                } else {
+                    if {![macports::ui_isset ports_debug]} {
+                        ui_msg ""
+                    }
+                    ui_warn "Error parsing file [$b path]: [machista::strerror $returncode]"
+                }
+                continue;
+            }
+
+            set architecture [$result cget -mt_archs]
+            while {$architecture != "NULL"} {
+                if {[info exists options(ports_rev-upgrade_id-loadcmd-check)] && $options(ports_rev-upgrade_id-loadcmd-check) == "yes"} {
+                    if {[$architecture cget -mat_install_name] != "NULL" && [$architecture cget -mat_install_name] != ""} {
+                        # check if this lib's install name actually refers to this file itself
+                        # if this is not the case software linking against this library might have erroneous load commands
+                        if {0 == [catch {set idloadcmdpath [revupgrade_handle_special_paths [$b path] [$architecture cget -mat_install_name]]}]} {
+                            if {[string index $idloadcmdpath 0] != "/"} {
+                                set port [registry::entry owner [$b path]]
+                                if {$port != ""} {
+                                    set portname [$port name]
+                                } else {
+                                    set portname "<unknown-port>"
+                                }
+                                if {![macports::ui_isset ports_debug]} {
+                                    ui_msg ""
+                                }
+                                ui_warn "ID load command in [$b path], arch [machista::get_arch_name [$architecture cget -mat_arch]] (belonging to port $portname) contains relative path"
+                            } elseif {![file exists $idloadcmdpath]} {
+                                set port [registry::entry owner [$b path]]
+                                if {$port != ""} {
+                                    set portname [$port name]
+                                } else {
+                                    set portname "<unknown-port>"
+                                }
+                                if {![macports::ui_isset ports_debug]} {
+                                    ui_msg ""
+                                }
+                                ui_warn "ID load command in [$b path], arch [machista::get_arch_name [$architecture cget -mat_arch]] refers to non-existant file $idloadcmdpath"
+                                ui_warn "This is probably a bug in the $portname port and might cause problems in libraries linking against this file"
+                            } else {
+    
+                                set hash_this [sha256 file [$b path]]
+                                set hash_idloadcmd [sha256 file $idloadcmdpath]
+    
+                                if {$hash_this != $hash_idloadcmd} {
+                                    set port [registry::entry owner [$b path]]
+                                    if {$port != ""} {
+                                        set portname [$port name]
+                                    } else {
+                                        set portname "<unknown-port>"
+                                    }
+                                    if {![macports::ui_isset ports_debug]} {
+                                        ui_msg ""
+                                    }
+                                    ui_warn "ID load command in [$b path], arch [machista::get_arch_name [$architecture cget -mat_arch]] refers to file $idloadcmdpath, which is a different file"
+                                    ui_warn "This is probably a bug in the $portname port and might cause problems in libraries linking against this file"
+                                }
+                            }
+                        }
+                    }
+                }
+                set loadcommand [$architecture cget -mat_loadcmds]
+
+                while {$loadcommand != "NULL"} {
+                    if {0 != [catch {set filepath [revupgrade_handle_special_paths [$b path] [$loadcommand cget -mlt_install_name]]}]} {
+                        set loadcommand [$loadcommand cget -next]
+                        continue;
+                    }
+
+                    set libresultlist [machista::parse_file $handle $filepath]
+                    set libreturncode [lindex $libresultlist 0]
+                    set libresult     [lindex $libresultlist 1]
+
+                    if {$libreturncode != $machista::SUCCESS} {
+                        if {![info exists files_warned_about($filepath)]} {
+                            if {![macports::ui_isset ports_debug]} {
+                                ui_msg ""
+                            }
+                            ui_warn "Could not open $filepath: [machista::strerror $libreturncode]"
+                            set files_warned_about($filepath) yes
+                        }
+                        if {$libreturncode == $machista::EFILE} {
+                            ui_debug "Marking [$b path] as broken"
+                            lappend broken_files [$b path]
+                        }
+                        set loadcommand [$loadcommand cget -next]
+                        continue;
+                    }
+
+                    set libarchitecture [$libresult cget -mt_archs]
+                    set libarch_found false;
+                    while {$libarchitecture != "NULL"} {
+                        if {[$architecture cget -mat_arch] != [$libarchitecture cget -mat_arch]} {
+                            set libarchitecture [$libarchitecture cget -next]
+                            continue;
+                        }
+
+                        if {[$loadcommand cget -mlt_version] != [$libarchitecture cget -mat_version] && [$loadcommand cget -mlt_comp_version] > [$libarchitecture cget -mat_comp_version]} {
+                            if {![macports::ui_isset ports_debug]} {
+                                ui_msg ""
+                            }
+                            ui_warn "Incompatible library version of file [$loadcommand cget -mlt_install_name]: Expected [$loadcommand cget -mlt_comp_version], but got [$libarchitecture cget -mat_comp_version]"
+                            ui_debug "Marking [$b path] as broken"
+                            lappend broken_files [$b path]
+                        }
+
+                        set libarch_found true;
+                        break;
+                    }
+
+                    if {$libarch_found == false} {
+                        ui_debug "Missing architecture [machista::get_arch_name [$architecture cget -mat_arch]] in file $filepath"
+                        if {[path_is_in_prefix $filepath]} {
+                            ui_debug "Marking [$b path] as broken"
+                            lappend broken_files [$b path]
+                        } else {
+                            ui_debug "Missing architecture [machista::get_arch_name [$architecture cget -mat_arch]] in file outside prefix referenced from [$b path]"
+                            # ui_debug "   How did you get that compiled anyway?"
+                        }
+                    }
+                    set loadcommand [$loadcommand cget -next]
+                }
+
+                set architecture [$architecture cget -next]
+            }
+        }
+        ui_msg ""
+
+        machista::destroy_handle $handle
+
+        if {[llength $broken_files] == 0} {
+            ui_msg "$macports::ui_prefix No broken files found. :)"
+            return 0;
+        }
+        ui_msg "$macports::ui_prefix Found [llength $broken_files] broken file(s), matching files to ports"
+        set broken_ports {}
+        set broken_files [lsort -unique $broken_files]
+        foreach file $broken_files {
+            set port [registry::entry owner $file]
+            if {$port == ""} {
+                ui_error "Broken file $file doesn't belong to any port."
+            }
+            lappend broken_ports $port
+        }
+        set broken_ports [lsort -unique $broken_ports]
+
+        foreach port $broken_ports {
+            if {![info exists broken_port_counts([$port name])]} {
+                set broken_port_counts([$port name]) 0
+            }
+            incr broken_port_counts([$port name])
+            if {$broken_port_counts([$port name]) > 3} {
+                ui_error "Port [$port name] is still broken after rebuiling it more than 3 times. You might want to file a bug for this."
+                error "Port [$port name] still broken after rebuilding [expr $broken_port_counts([$port name]) - 1] time(s)"
+            }
+        }
+
+        ui_msg "$macports::ui_prefix Found [llength $broken_ports] broken port(s), determining rebuild order"
+        # broken_ports are the nodes in our graph
+        # now we need adjacents
+        foreach port $broken_ports {
+            # initialize with empty list
+            set adjlist($port) {}
+            set revadjlist($port) {}
+        }
+
+        array set visited {}
+        foreach port $broken_ports {
+            # stack of broken nodes we've come across
+            set stack {}
+            lappend stack $port
+
+            # build graph
+            if {![info exists visited($port)]} {
+                revupgrade_buildgraph $port stack adjlist revadjlist visited
+            }
+        }
+
+        set unsorted_ports $broken_ports
+        set topsort_ports {}
+        while {[llength $unsorted_ports] > 0} {
+            foreach port $unsorted_ports {
+                if {[llength $adjlist($port)] == 0} {
+                    # this node has no further dependencies
+                    # add it to topsorted list
+                    lappend topsort_ports $port
+                    # remove from unsorted list
+                    set index [lsearch -exact $unsorted_ports $port]
+                    set unsorted_ports [lreplace $unsorted_ports $index $index]
+
+                    # remove edges 
+                    foreach target $revadjlist($port) {
+                        set index [lsearch -exact $adjlist($target) $port]
+                        set adjlist($target) [lreplace $adjlist($target) $index $index]
+                    }
+                }
+            }
+        }
+
+        ui_msg "$macports::ui_prefix Rebuilding in order"
+        foreach port $topsort_ports {
+            ui_msg "     [$port name] @[$port version] [$port variants][$port negated_variants]"
+        }
+
+        # shared depscache for all ports that are going to be rebuilt
+        array set depscache {}
+        set status 0
+        foreach port $topsort_ports {
+            if {![info exists depscache(port:[$port name])]} {
+
+                # convert variations into the format macports::upgrade needs
+                set minusvariant [lrange [split [$port negated_variants] "-"] 1 end]
+                set plusvariant  [lrange [split [$port variants]         "+"] 1 end]
+                set variants     [list]
+                foreach v $minusvariant {
+                    lappend variants $v "-"
+                }
+                foreach v $plusvariant {
+                    lappend variants $v "+"
+                }
+                array unset variations
+                array set variations $variants
+
+                # set rev-upgrade options and nodeps if this is not the first run
+                set macports::global_options(ports_revupgrade) "yes"
+                unset -nocomplain macports::global_options(ports_nodeps)
+                unset -nocomplain macports::global_options(ports_revupgrade_second_run)
+                unset -nocomplain macports::global_options(ports_source_only)
+                if {$broken_port_counts([$port name]) > 1} {
+                    set macports::global_options(ports_revupgrade_second_run) yes
+                    set macports::global_options(ports_nodeps) yes
+                    # build from source only until the buildbot has some method of rev-upgrade, too
+                    set macports::global_options(ports_source_only) yes
+                }
+
+                # call macports::upgrade with ports_revupgrade option to rebuild the port
+                set status [macports::upgrade [$port name] "port:[$port name]" \
+                    [array get variations] [array get macports::global_options] depscache]
+                if {$status != 0} {
+                    error "Error rebuilding [$port name]"
+                }
+            }
+        }
+
+        if {[info exists options(ports_dryrun)] && $options(ports_dryrun) == "yes"} {
+            ui_warn "If this was no dry run, rev-upgrade would now run the checks again to find unresolved and newly created problems"
+            return 0
+        }
+        return 1
+    }
+
+    return 0
+}
+
+# Return whether a path is in the macports prefix
+# Usage: path_is_in_prefix path_to_test
+# Returns true if the path is in the prefix, false otherwise
+proc path_is_in_prefix {path} {
+    if {[string first $macports::prefix $path] == 0} {
+        return yes
+    }
+    if {[string first $macports::applications_dir $path] == 0} {
+        return yes
+    }
+    return no
+}
+
+# Function to replace macros in loadcommand paths with their proper values (which are usually determined at load time)
+# Usage: revupgrade_handle_special_paths name_of_file path_from_loadcommand
+# Returns the corrected path on success or an error in case of failure.
+# Note that we can't reliably replace @executable_path, because it's only clear when executing a file where it was executed from.
+# Replacing @rpath does not work yet, but it might be possible to get it working using the rpath attribute in the file containing the
+# loadcommand
+proc revupgrade_handle_special_paths {fname path} {
+    set corrected_path $path
+
+    set loaderpath_idx [string first "@loader_path" $corrected_path]
+    if {$loaderpath_idx != -1} {
+        set corrected_path [string replace $corrected_path $loaderpath_idx $loaderpath_idx+11 [file dirname $fname]]
+    }
+
+    set executablepath_idx [string first "@executable_path" $corrected_path]
+    if {$executablepath_idx != -1} {
+        ui_debug "Ignoring loadcommand containing @exectuable_path in $fname"
+        error "@exectuable_path in loadcommand"
+    }
+
+    set rpath_idx [string first "@rpath" $corrected_path]
+    if {$rpath_idx != -1} {
+        ui_debug "Ignoring loadcommand containing @rpath in $fname"
+        error "@rpath in loadcommand"
+    }
+
+    return $corrected_path
+}
+
+# Recursively build the dependency graph between broken ports
+# Usage: revupgrade_buildgraph start_port name_of_stack name_of_adjacency_list name_of_reverse_adjacency_list name_of_visited_map
+proc revupgrade_buildgraph {port stackname adjlistname revadjlistname visitedname} {
+    upvar $stackname stack
+    upvar $adjlistname adjlist
+    upvar $revadjlistname revadjlist
+    upvar $visitedname visited
+
+    ui_debug "Processing port [$port name] @[$port epoch]:[$port version]_[$port revision] [$port variants] [$port negated_variants]"
+    set dependent_ports [$port dependents]
+    foreach dep $dependent_ports {
+        if {[info exists visited($dep)]} {
+            continue
+        }
+        set visited($dep) true
+        set is_broken_port false
+
+        if {[info exists adjlist($dep)]} {
+            #ui_debug "Dependency [$dep name] is broken, adding edge from [[lindex $stack 0] name] to [$dep name]"
+            #ui_debug "Making [$dep name] new head of stack"
+            # $dep is one of the broken ports
+            # add an edge to the last broken port in the DFS
+            lappend revadjlist([lindex $stack 0]) $dep
+            lappend adjlist($dep) [lindex $stack 0]
+            # make this port the new last broken port by prepending it to the stack
+            set stack [linsert $stack 0 $dep]
+            
+            set is_broken_port true
+        }
+        revupgrade_buildgraph $dep stack adjlist revadjlist visited
+        if {$is_broken_port} {
+            #ui_debug "Removing [$dep name] from stack"
+            # remove $dep from the stack
+            set stack [lrange $stack 1 end]
+        }
+    }
+}
+

Modified: trunk/base/src/pextlib1.0/Pextlib.c
===================================================================
--- trunk/base/src/pextlib1.0/Pextlib.c	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/pextlib1.0/Pextlib.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -46,6 +46,7 @@
 #include <grp.h>
 #include <limits.h>
 #include <pwd.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -53,6 +54,11 @@
 #include <strings.h>
 #include <unistd.h>
 
+#ifdef __MACH__
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#endif
+
 #include <tcl.h>
 
 #include "Pextlib.h"
@@ -93,147 +99,147 @@
 static char *
 ui_escape(const char *source)
 {
-	char *d, *dest;
-	const char *s;
-	size_t dlen;
+    char *d, *dest;
+    const char *s;
+    size_t dlen;
 
-	s = source;
-	dlen = strlen(source) * 2 + 1;
-	d = dest = malloc(dlen);
-	if (dest == NULL) {
-		return NULL;
-	}
-	while(*s != '\0') {
-		switch(*s) {
-			case '\\':
-			case '}':
-			case '{':
-				*d = '\\';
-				d++;
-				*d = *s;
-				d++;
-				s++;
-				break;
-			case '\n':
-				s++;
-				break;
-			default:
-				*d = *s;
-				d++;
-				s++;
-				break;
-		}
-	}
-	*d = '\0';
-	return dest;
+    s = source;
+    dlen = strlen(source) * 2 + 1;
+    d = dest = malloc(dlen);
+    if (dest == NULL) {
+        return NULL;
+    }
+    while(*s != '\0') {
+        switch(*s) {
+            case '\\':
+            case '}':
+            case '{':
+                *d = '\\';
+                d++;
+                *d = *s;
+                d++;
+                s++;
+                break;
+            case '\n':
+                s++;
+                break;
+            default:
+                *d = *s;
+                d++;
+                s++;
+                break;
+        }
+    }
+    *d = '\0';
+    return dest;
 }
 
 int
 ui_info(Tcl_Interp *interp, char *mesg)
 {
-	const char ui_proc_start[] = "ui_info [subst -nocommands -novariables {";
-	const char ui_proc_end[] = "}]";
-	char *script, *string;
-	size_t scriptlen, len, remaining;
-	int rval;
+    const char ui_proc_start[] = "ui_info [subst -nocommands -novariables {";
+    const char ui_proc_end[] = "}]";
+    char *script, *string;
+    size_t scriptlen, len, remaining;
+    int rval;
 
-	string = ui_escape(mesg);
-	if (string == NULL)
-		return TCL_ERROR;
+    string = ui_escape(mesg);
+    if (string == NULL)
+        return TCL_ERROR;
 
-	len = strlen(string);
-	scriptlen = sizeof(ui_proc_start) + len + sizeof(ui_proc_end) - 1;
-	script = malloc(scriptlen);
-	if (script == NULL)
-		return TCL_ERROR;
+    len = strlen(string);
+    scriptlen = sizeof(ui_proc_start) + len + sizeof(ui_proc_end) - 1;
+    script = malloc(scriptlen);
+    if (script == NULL)
+        return TCL_ERROR;
 
-	memcpy(script, ui_proc_start, sizeof(ui_proc_start));
-	remaining = scriptlen - sizeof(ui_proc_start);
-	strncat(script, string, remaining);
-	remaining -= len;
-	strncat(script, ui_proc_end, remaining);
-	free(string);
-	rval = Tcl_EvalEx(interp, script, -1, 0);
-	free(script);
-	return rval;
+    memcpy(script, ui_proc_start, sizeof(ui_proc_start));
+    remaining = scriptlen - sizeof(ui_proc_start);
+    strncat(script, string, remaining);
+    remaining -= len;
+    strncat(script, ui_proc_end, remaining);
+    free(string);
+    rval = Tcl_EvalEx(interp, script, -1, 0);
+    free(script);
+    return rval;
 }
 
 int StrsedCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	char *pattern, *string, *res;
-	int range[2];
-	Tcl_Obj *tcl_result;
+    char *pattern, *string, *res;
+    int range[2];
+    Tcl_Obj *tcl_result;
 
-	if (objc != 3) {
-		Tcl_WrongNumArgs(interp, 1, objv, "string pattern");
-		return TCL_ERROR;
-	}
+    if (objc != 3) {
+        Tcl_WrongNumArgs(interp, 1, objv, "string pattern");
+        return TCL_ERROR;
+    }
 
-	string = Tcl_GetString(objv[1]);
-	pattern = Tcl_GetString(objv[2]);
-	res = strsed(string, pattern, range);
-	if (!res) {
-		Tcl_SetResult(interp, "strsed failed", TCL_STATIC);
-		return TCL_ERROR;
-	}
-	tcl_result = Tcl_NewStringObj(res, -1);
-	Tcl_SetObjResult(interp, tcl_result);
-	free(res);
-	return TCL_OK;
+    string = Tcl_GetString(objv[1]);
+    pattern = Tcl_GetString(objv[2]);
+    res = strsed(string, pattern, range);
+    if (!res) {
+        Tcl_SetResult(interp, "strsed failed", TCL_STATIC);
+        return TCL_ERROR;
+    }
+    tcl_result = Tcl_NewStringObj(res, -1);
+    Tcl_SetObjResult(interp, tcl_result);
+    free(res);
+    return TCL_OK;
 }
 
 int ExistsuserCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *tcl_result;
-	struct passwd *pwent;
-	char *user;
+    Tcl_Obj *tcl_result;
+    struct passwd *pwent;
+    char *user;
 
-	if (objc != 2) {
-		Tcl_WrongNumArgs(interp, 1, objv, "user");
-		return TCL_ERROR;
-	}
+    if (objc != 2) {
+        Tcl_WrongNumArgs(interp, 1, objv, "user");
+        return TCL_ERROR;
+    }
 
-	user = strdup(Tcl_GetString(objv[1]));
-	if (isdigit(*(user)))
-		pwent = getpwuid(strtol(user, 0, 0));
-	else
-		pwent = getpwnam(user);
-	free(user);
+    user = strdup(Tcl_GetString(objv[1]));
+    if (isdigit(*(user)))
+        pwent = getpwuid(strtol(user, 0, 0));
+    else
+        pwent = getpwnam(user);
+    free(user);
 
-	if (pwent == NULL)
-		tcl_result = Tcl_NewIntObj(0);
-	else
-		tcl_result = Tcl_NewIntObj(pwent->pw_uid);
+    if (pwent == NULL)
+        tcl_result = Tcl_NewIntObj(0);
+    else
+        tcl_result = Tcl_NewIntObj(pwent->pw_uid);
 
-	Tcl_SetObjResult(interp, tcl_result);
-	return TCL_OK;
+    Tcl_SetObjResult(interp, tcl_result);
+    return TCL_OK;
 }
 
 int ExistsgroupCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
 {
-	Tcl_Obj *tcl_result;
-	struct group *grent;
-	char *group;
+    Tcl_Obj *tcl_result;
+    struct group *grent;
+    char *group;
 
-	if (objc != 2) {
-		Tcl_WrongNumArgs(interp, 1, objv, "groupname");
-		return TCL_ERROR;
-	}
+    if (objc != 2) {
+        Tcl_WrongNumArgs(interp, 1, objv, "groupname");
+        return TCL_ERROR;
+    }
 
-	group = strdup(Tcl_GetString(objv[1]));
-	if (isdigit(*(group)))
-		grent = getgrgid(strtol(group, 0, 0));
-	else
-		grent = getgrnam(group);
-	free(group);
+    group = strdup(Tcl_GetString(objv[1]));
+    if (isdigit(*(group)))
+        grent = getgrgid(strtol(group, 0, 0));
+    else
+        grent = getgrnam(group);
+    free(group);
 
-	if (grent == NULL)
-		tcl_result = Tcl_NewIntObj(0);
-	else
-		tcl_result = Tcl_NewIntObj(grent->gr_gid);
+    if (grent == NULL)
+        tcl_result = Tcl_NewIntObj(0);
+    else
+        tcl_result = Tcl_NewIntObj(grent->gr_gid);
 
-	Tcl_SetObjResult(interp, tcl_result);
-	return TCL_OK;
+    Tcl_SetObjResult(interp, tcl_result);
+    return TCL_OK;
 }
 
 /* Find the first unused UID > 500
@@ -241,81 +247,81 @@
    but UIDs < 500 are reserved by Apple */
 int NextuidCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc UNUSED, Tcl_Obj *CONST objv[] UNUSED)
 {
-	Tcl_Obj *tcl_result;
-	int cur;
+    Tcl_Obj *tcl_result;
+    int cur;
 
-	cur = MIN_USABLE_UID;
+    cur = MIN_USABLE_UID;
 
-	while (getpwuid(cur) != NULL) {
-		cur++;
-	}
+    while (getpwuid(cur) != NULL) {
+        cur++;
+    }
 
-	tcl_result = Tcl_NewIntObj(cur);
-	Tcl_SetObjResult(interp, tcl_result);
-	return TCL_OK;
+    tcl_result = Tcl_NewIntObj(cur);
+    Tcl_SetObjResult(interp, tcl_result);
+    return TCL_OK;
 }
 
 /* Just as with NextuidCmd, return the first unused gid > 500 */
 int NextgidCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc UNUSED, Tcl_Obj *CONST objv[] UNUSED)
 {
-	Tcl_Obj *tcl_result;
-	int cur;
+    Tcl_Obj *tcl_result;
+    int cur;
 
-	cur = MIN_USABLE_GID;
+    cur = MIN_USABLE_GID;
 
-	while (getgrgid(cur) != NULL) {
-		cur++;
-	}
+    while (getgrgid(cur) != NULL) {
+        cur++;
+    }
 
-	tcl_result = Tcl_NewIntObj(cur);
-	Tcl_SetObjResult(interp, tcl_result);
-	return TCL_OK;
+    tcl_result = Tcl_NewIntObj(cur);
+    Tcl_SetObjResult(interp, tcl_result);
+    return TCL_OK;
 }
 
 int UmaskCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc UNUSED, Tcl_Obj *CONST objv[] UNUSED)
 {
-	Tcl_Obj *tcl_result;
-	char *tcl_mask, *p;
-	const size_t stringlen = 5; /* 4 digits & \0 */
-	int i;
-	mode_t *set;
-	mode_t newmode;
-	mode_t oldmode;
+    Tcl_Obj *tcl_result;
+    char *tcl_mask, *p;
+    const size_t stringlen = 5; /* 4 digits & \0 */
+    int i;
+    mode_t *set;
+    mode_t newmode;
+    mode_t oldmode;
 
-	if (objc != 2) {
-		Tcl_WrongNumArgs(interp, 1, objv, "mode");
-		return TCL_ERROR;
-	}
+    if (objc != 2) {
+        Tcl_WrongNumArgs(interp, 1, objv, "mode");
+        return TCL_ERROR;
+    }
 
-	tcl_mask = Tcl_GetString(objv[1]);
-	if ((set = setmode(tcl_mask)) == NULL) {
-		Tcl_SetResult(interp, "Invalid umask mode", TCL_STATIC);
-		return TCL_ERROR;
-	}
+    tcl_mask = Tcl_GetString(objv[1]);
+    if ((set = setmode(tcl_mask)) == NULL) {
+        Tcl_SetResult(interp, "Invalid umask mode", TCL_STATIC);
+        return TCL_ERROR;
+    }
 
-	newmode = getmode(set, 0);
-	free(set);
+    newmode = getmode(set, 0);
+    free(set);
 
-	oldmode = umask(newmode);
+    oldmode = umask(newmode);
 
-	tcl_mask = calloc(1, stringlen); /* 4 digits & \0 */
-	if (!tcl_mask) {
-		return TCL_ERROR;
-	}
+    tcl_mask = calloc(1, stringlen); /* 4 digits & \0 */
+    if (!tcl_mask) {
+        return TCL_ERROR;
+    }
 
-	/* Totally gross and cool */
-	p = tcl_mask + stringlen - 1;
-	for (i = stringlen - 1; i > 0; i--) {
-		p--;
-		*p = (oldmode & 7) + '0';
-		oldmode >>= 3;
-	}
+    /* Totally gross and cool */
+    p = tcl_mask + stringlen - 1;
+    for (i = stringlen - 1; i > 0; i--) {
+        p--;
+        *p = (oldmode & 7) + '0';
+        oldmode >>= 3;
+    }
 
-	tcl_result = Tcl_NewStringObj(p, -1);
-	free(tcl_mask);
+    tcl_result = Tcl_NewStringObj(p, -1);
+    free(tcl_mask);
 
-	Tcl_SetObjResult(interp, tcl_result);
-	return TCL_OK;
+    Tcl_SetObjResult(interp, tcl_result);
+    return TCL_OK;
 }
 
 /**
@@ -464,10 +470,107 @@
     return TCL_OK;
 }
 
+#ifdef __MACH__
+/**
+ * Tcl function to determine whether a file given by path is binary (in terms of being Mach-O)
+ * Defined on Mac-Systems only, because the necessary headers are only available there.
+ *
+ * Synopsis: fileIsBinary filename
+ */
+static int fileIsBinaryCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
+    const char *path;
+    FILE *file;
+    uint32_t magic;
+    struct stat st;
+
+    if (objc != 2) {
+        Tcl_WrongNumArgs(interp, 1, objv, "filename");
+        return TCL_ERROR;
+    }
+
+    path = Tcl_GetString(objv[1]);
+    if (-1 == lstat(path, &st)) {
+        /* an error occured */
+        Tcl_SetErrno(errno);
+        Tcl_ResetResult(interp);
+        Tcl_AppendResult(interp, "lstat(", path, "):", (char *)Tcl_PosixError(interp), NULL);
+        return TCL_ERROR;
+    }
+    if (!S_ISREG(st.st_mode)) {
+        /* not a regular file, haven't seen directories which are binaries yet */
+        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(false));
+        return TCL_OK;
+    }
+    if (NULL == (file = fopen(path, "r"))) {
+        Tcl_SetErrno(errno);
+        Tcl_ResetResult(interp);
+        Tcl_AppendResult(interp, "fopen(", path, "): ", (char *)Tcl_PosixError(interp), NULL);
+        return TCL_ERROR;
+    }
+    if (1 != fread(&magic, sizeof(uint32_t), 1, file)) {
+        if (feof(file)) {
+            fclose(file);
+            /* file is shorter than 4 byte, probably not a binary */
+            Tcl_SetObjResult(interp, Tcl_NewBooleanObj(false));
+            return TCL_OK;
+        }
+        /* error while reading */
+        Tcl_SetErrno(errno);
+        Tcl_ResetResult(interp);
+        Tcl_AppendResult(interp, "fread(&magic, 4, 1, ", path, "): ", (char *)Tcl_PosixError(interp), NULL);
+        fclose(file);
+        return TCL_ERROR;
+    }
+    if (magic == MH_MAGIC || magic == MH_MAGIC_64) {
+        fclose(file);
+        /* this is a mach-o file */
+        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(true));
+        return TCL_OK;
+    }
+    if (magic == htonl(FAT_MAGIC)) {
+        uint32_t archcount;
+        /* either universal binary or java class (FAT_MAGIC == 0xcafebabe)
+           see /use/share/file/magic/cafebabe for an explanation of what I'm doing here */
+        if (1 != fread(&archcount, sizeof(uint32_t), 1, file)) {
+            if (feof(file)) {
+                fclose(file);
+                /* file shorter than 8 byte, probably not a binary either */
+                Tcl_SetObjResult(interp, Tcl_NewBooleanObj(false));
+                return TCL_OK;
+            }
+            /* error while reading */
+            Tcl_SetErrno(errno);
+            Tcl_ResetResult(interp);
+            Tcl_AppendResult(interp, "fread(&archcount, 4, 1, ", path, "): ", (char *)Tcl_PosixError(interp), NULL);
+            fclose(file);
+            return TCL_ERROR;
+        }
+
+        /* universal binary header is always big endian */
+        archcount = ntohl(archcount);
+        if (archcount > 0 && archcount < 20) {
+            fclose(file);
+            /* universal binary */
+            Tcl_SetObjResult(interp, Tcl_NewBooleanObj(true));
+            return TCL_OK;
+        }
+
+        fclose(file);
+        /* probably java class */
+        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(false));
+        return TCL_OK;
+    }
+    fclose(file);
+
+    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(false));
+    return TCL_OK;
+}
+#endif
+
 int Pextlib_Init(Tcl_Interp *interp)
 {
-	if (Tcl_InitStubs(interp, "8.4", 0) == NULL)
-		return TCL_ERROR;
+    if (Tcl_InitStubs(interp, "8.4", 0) == NULL)
+        return TCL_ERROR;
 
 	Tcl_CreateObjCommand(interp, "system", SystemCmd, NULL, NULL);
 	Tcl_CreateObjCommand(interp, "flock", FlockCmd, NULL, NULL);
@@ -501,30 +604,33 @@
 	Tcl_CreateObjCommand(interp, "unsetenv", UnsetEnvCmd, NULL, NULL);
 	Tcl_CreateObjCommand(interp, "lchown", lchownCmd, NULL, NULL);
 	Tcl_CreateObjCommand(interp, "realpath", RealpathCmd, NULL, NULL);
+#ifdef __MACH__
+    Tcl_CreateObjCommand(interp, "fileIsBinary", fileIsBinaryCmd, NULL, NULL);
+#endif
 
-	Tcl_CreateObjCommand(interp, "readline", ReadlineCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "rl_history", RLHistoryCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "readline", ReadlineCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "rl_history", RLHistoryCmd, NULL, NULL);
 
-	Tcl_CreateObjCommand(interp, "getuid", getuidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "geteuid", geteuidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "getgid", getgidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "getegid", getegidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "setuid", setuidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "seteuid", seteuidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "setgid", setgidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "setegid", setegidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "name_to_uid", name_to_uidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "uid_to_name", uid_to_nameCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "uname_to_gid", uname_to_gidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "name_to_gid", name_to_gidCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "gid_to_name", gid_to_nameCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "getuid", getuidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "geteuid", geteuidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "getgid", getgidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "getegid", getegidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "setuid", setuidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "seteuid", seteuidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "setgid", setgidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "setegid", setegidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "name_to_uid", name_to_uidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "uid_to_name", uid_to_nameCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "uname_to_gid", uname_to_gidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "name_to_gid", name_to_gidCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "gid_to_name", gid_to_nameCmd, NULL, NULL);
 
-	Tcl_CreateObjCommand(interp, "tracelib", TracelibCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "isatty", IsattyCmd, NULL, NULL);
-	Tcl_CreateObjCommand(interp, "term_get_size", TermGetSizeCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "tracelib", TracelibCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "isatty", IsattyCmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "term_get_size", TermGetSizeCmd, NULL, NULL);
 
-	if (Tcl_PkgProvide(interp, "Pextlib", "1.0") != TCL_OK)
-		return TCL_ERROR;
+    if (Tcl_PkgProvide(interp, "Pextlib", "1.0") != TCL_OK)
+        return TCL_ERROR;
 
-	return TCL_OK;
+    return TCL_OK;
 }


Property changes on: trunk/base/src/pextlib1.0/sha2.c
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/gsoc08-privileges/base/src/pextlib1.0/sha2.c:37343-46937
/branches/universal-sanity/base/src/pextlib1.0/sha2.c:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/sha2.c:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/sha2.c:45682-46060
/users/perry/base-select/src/pextlib1.0/sha2.c:44044-44692
   + /branches/gsoc08-privileges/base/src/pextlib1.0/sha2.c:37343-46937
/branches/gsoc11-rev-upgrade/base/src/pextlib1.0/sha2.c:78828-88375
/branches/universal-sanity/base/src/pextlib1.0/sha2.c:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/sha2.c:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/sha2.c:45682-46060
/users/perry/base-select/src/pextlib1.0/sha2.c:44044-44692


Property changes on: trunk/base/src/pextlib1.0/sha2.h
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/gsoc08-privileges/base/src/pextlib1.0/sha2.h:37343-46937
/branches/universal-sanity/base/src/pextlib1.0/sha2.h:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/sha2.h:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/sha2.h:45682-46060
/users/perry/base-select/src/pextlib1.0/sha2.h:44044-44692
   + /branches/gsoc08-privileges/base/src/pextlib1.0/sha2.h:37343-46937
/branches/gsoc11-rev-upgrade/base/src/pextlib1.0/sha2.h:78828-88375
/branches/universal-sanity/base/src/pextlib1.0/sha2.h:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/sha2.h:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/sha2.h:45682-46060
/users/perry/base-select/src/pextlib1.0/sha2.h:44044-44692


Property changes on: trunk/base/src/pextlib1.0/sha256cmd.c
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/gsoc08-privileges/base/src/pextlib1.0/rmd160cmd.c:37343-46937
/branches/gsoc09-logging/base/src/pextlib1.0/sha256cmd.c:51231-60371
/branches/universal-sanity/base/src/pextlib1.0/rmd160cmd.c:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/rmd160cmd.c:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/rmd160cmd.c:45682-46060
/users/perry/base-select/src/pextlib1.0/rmd160cmd.c:44044-44692
   + /branches/gsoc08-privileges/base/src/pextlib1.0/rmd160cmd.c:37343-46937
/branches/gsoc09-logging/base/src/pextlib1.0/sha256cmd.c:51231-60371
/branches/gsoc11-rev-upgrade/base/src/pextlib1.0/sha256cmd.c:78828-88375
/branches/universal-sanity/base/src/pextlib1.0/rmd160cmd.c:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/rmd160cmd.c:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/rmd160cmd.c:45682-46060
/users/perry/base-select/src/pextlib1.0/rmd160cmd.c:44044-44692


Property changes on: trunk/base/src/pextlib1.0/sha256cmd.h
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/gsoc08-privileges/base/src/pextlib1.0/rmd160cmd.h:37343-46937
/branches/gsoc09-logging/base/src/pextlib1.0/sha256cmd.h:51231-60371
/branches/universal-sanity/base/src/pextlib1.0/rmd160cmd.h:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/rmd160cmd.h:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/rmd160cmd.h:45682-46060
/users/perry/base-select/src/pextlib1.0/rmd160cmd.h:44044-44692
   + /branches/gsoc08-privileges/base/src/pextlib1.0/rmd160cmd.h:37343-46937
/branches/gsoc09-logging/base/src/pextlib1.0/sha256cmd.h:51231-60371
/branches/gsoc11-rev-upgrade/base/src/pextlib1.0/sha256cmd.h:78828-88375
/branches/universal-sanity/base/src/pextlib1.0/rmd160cmd.h:51872-52323
/branches/variant-descs-14482/base/src/pextlib1.0/rmd160cmd.h:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/pextlib1.0/rmd160cmd.h:45682-46060
/users/perry/base-select/src/pextlib1.0/rmd160cmd.h:44044-44692

Modified: trunk/base/src/port/port.tcl
===================================================================
--- trunk/base/src/port/port.tcl	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/port/port.tcl	2011-12-30 00:17:49 UTC (rev 88376)
@@ -2572,6 +2572,7 @@
     if {[require_portlist portlist] || ([prefix_unwritable] && ![macports::global_option_isset ports_dryrun])} {
         return 1
     }
+
     # shared depscache for all ports in the list
     array set depscache {}
     set status 0
@@ -2587,12 +2588,25 @@
     
     if {$status != 0} {
         print_tickets_url
+    } else {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
     }
 
     return $status
 }
 
+proc action_revupgrade { action portlist opts } {
+    set status [macports::revupgrade $opts]
+    if {$status != 0} {
+        print_tickets_url
+    }
+    return $status
+}
 
+
 proc action_version { action portlist opts } {
     puts "Version: [macports::version]"
     return 0
@@ -3984,6 +3998,7 @@
     unsetrequested [list action_setrequested  [ACTION_ARGS_PORTS]] \
     \
     upgrade     [list action_upgrade        [ACTION_ARGS_PORTS]] \
+    rev-upgrade [list action_revupgrade     [ACTION_ARGS_NONE]] \
     \
     version     [list action_version        [ACTION_ARGS_NONE]] \
     platform    [list action_platform       [ACTION_ARGS_NONE]] \
@@ -4146,13 +4161,14 @@
     lint        {nitpick}
     select      {list set show}
     log         {{phase 1} {level 1}}
-    upgrade     {force enforce-variants no-replace}
+    upgrade     {force enforce-variants no-replace no-rev-upgrade}
+    rev-upgrade {id-loadcmd-check}
 }
 
 ##
 # Checks whether the given option is valid
 #
-# œparam action for which action
+# @param action for which action
 # @param option the prefix of the option to check
 # @return list of pairs {name argc} for all matching options
 proc cmd_option_matches {action option} {

Modified: trunk/base/src/port1.0/port_autoconf.tcl.in
===================================================================
--- trunk/base/src/port1.0/port_autoconf.tcl.in	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/port1.0/port_autoconf.tcl.in	2011-12-30 00:17:49 UTC (rev 88376)
@@ -68,6 +68,7 @@
 	variable tar_path "@TAR@"
 	variable tar_q "@TAR_Q@"
 	variable hdiutil_path "@HDIUTIL@"
+	variable swig_path "@SIWG@"
 	variable have_launchd "@HAVE_LAUNCHD@"
 	variable launchctl_path "@LAUNCHCTL@"
 	variable install_command "@INSTALL@"

Modified: trunk/base/src/registry2.0/Makefile
===================================================================
--- trunk/base/src/registry2.0/Makefile	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/Makefile	2011-12-30 00:17:49 UTC (rev 88376)
@@ -3,6 +3,7 @@
 SRCS = registry.tcl registry_autoconf.tcl registry_util.tcl receipt_flat.tcl receipt_sqlite.tcl portimage.tcl portuninstall.tcl
 OBJS = registry.o util.o \
 	entry.o entryobj.o \
+	file.o fileobj.o \
 	../cregistry/cregistry.a
 	#graph.o graphobj.o
 

Modified: trunk/base/src/registry2.0/entry.c
===================================================================
--- trunk/base/src/registry2.0/entry.c	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/entry.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -35,6 +35,8 @@
 #include <tcl.h>
 #include <sqlite3.h>
 
+#include <cregistry/util.h>
+
 #include "entry.h"
 #include "entryobj.h"
 #include "registry.h"
@@ -112,7 +114,7 @@
                 variants, epoch, &error);
         if (entry != NULL) {
             Tcl_Obj* result;
-            if (entry_to_obj(interp, &result, entry, &error)) {
+            if (entry_to_obj(interp, &result, entry, NULL, &error)) {
                 Tcl_SetObjResult(interp, result);
                 return TCL_OK;
             }
@@ -192,7 +194,7 @@
                 variants, epoch, &error);
         if (entry != NULL) {
             Tcl_Obj* result;
-            if (entry_to_obj(interp, &result, entry, &error)) {
+            if (entry_to_obj(interp, &result, entry, NULL, &error)) {
                 Tcl_SetObjResult(interp, result);
                 return TCL_OK;
             }
@@ -209,7 +211,7 @@
  */
 static int entry_close(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
     if (objc != 3) {
-        Tcl_WrongNumArgs(interp, 1, objv, "delete entry");
+        Tcl_WrongNumArgs(interp, 1, objv, "close entry");
         return TCL_ERROR;
     } else {
         reg_error error;
@@ -455,7 +457,7 @@
                 return TCL_OK;
             } else {
                 Tcl_Obj* result;
-                if (entry_to_obj(interp, &result, entry, &error)) {
+                if (entry_to_obj(interp, &result, entry, NULL, &error)) {
                     Tcl_SetObjResult(interp, result);
                     return TCL_OK;
                 }

Copied: trunk/base/src/registry2.0/file.c (from rev 88375, branches/gsoc11-rev-upgrade/base/src/registry2.0/file.c)
===================================================================
--- trunk/base/src/registry2.0/file.c	                        (rev 0)
+++ trunk/base/src/registry2.0/file.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,292 @@
+/*
+ * file.c
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2011 Clemens Lang <cal at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sqlite3.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tcl.h>
+
+#include <cregistry/file.h>
+#include <cregistry/util.h>
+
+#include "file.h"
+#include "fileobj.h"
+#include "registry.h"
+#include "util.h"
+
+/**
+ * Converts a command name into a `reg_file`.
+ *
+ * @param [in] interp  Tcl interpreter to check within
+ * @param [in] name    name of file to get
+ * @param [out] errPtr description of error if the file can't be found
+ * @return             a file, or NULL if one couldn't be found
+ * @see get_object
+ */
+static reg_file* get_file(Tcl_Interp* interp, char* name, reg_error* errPtr) {
+    return (reg_file*)get_object(interp, name, "file", file_obj_cmd, errPtr);
+}
+
+/**
+ * Removes the file from the Tcl interpreter. Doesn't actually delete it since
+ * that's the registry's job. This is written to be used as the
+ * `Tcl_CmdDeleteProc` for an file object command.
+ *
+ * @param [in] clientData address of a reg_file to remove
+ */
+void delete_file(ClientData clientData) {
+    reg_file* file = (reg_file*)clientData;
+    free(file->proc);
+    free(file->key.path);
+    file->proc = NULL;
+}
+
+/**
+ * registry::file open portid path
+ *
+ * Opens a file matching the given parameters.
+ */
+static int file_open(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
+	reg_registry* reg = registry_for(interp, reg_attached);
+	if (objc != 4) {
+		Tcl_WrongNumArgs(interp, 1, objv, "open portid path");
+		return TCL_ERROR;
+	} else if (reg == NULL) {
+		return TCL_ERROR;
+	} else {
+		char* id = Tcl_GetString(objv[2]);
+		char* path = Tcl_GetString(objv[3]);
+		reg_error error;
+		reg_file* file = reg_file_open(reg, id, path, &error);
+		if (file != NULL) {
+			Tcl_Obj* result;
+			if (file_to_obj(interp, &result, file, NULL, &error)) {
+				Tcl_SetObjResult(interp, result);
+				return TCL_OK;
+			}
+		}
+		return registry_failed(interp, &error);
+	}
+	return TCL_ERROR;
+}
+
+/**
+ * registry::file close file
+ *
+ * Closes a file. It will remain in the registry.
+ */
+static int file_close(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
+	if (objc != 3) {
+		Tcl_WrongNumArgs(interp, 1, objv, "close file");
+		return TCL_ERROR;
+	} else {
+		reg_error error;
+		char* proc = Tcl_GetString(objv[2]);
+		reg_file* file = get_file(interp, proc, &error);
+		if (file == NULL) {
+			return registry_failed(interp, &error);
+		} else {
+			Tcl_DeleteCommand(interp, proc);
+			return TCL_OK;
+		}
+	}
+}
+
+typedef struct {
+    char* name;
+    reg_strategy strategy;
+} strategy_type;
+
+static strategy_type strategies[] = {
+    { "-exact",  reg_strategy_exact },
+    { "-glob",   reg_strategy_glob },
+    { "-regexp", reg_strategy_regexp },
+    { "-null",   reg_strategy_null },
+    { "--",      reg_strategy_exact },
+    { NULL, 0 }
+};
+
+/*
+ * registry::file search ?key value ...?
+ *
+ * Searches the registry for files for which each key's value is equal to the
+ * given value. To find all files, call `file search` with no key-value pairs.
+ * For each key, can be given an option of -exact, -glob, -regexp or -null to
+ * specify the matching strategy; defaults to exact.
+ */
+static int file_search(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
+    int i, j;
+    reg_registry* reg = registry_for(interp, reg_attached);
+    if (reg == NULL) {
+        return TCL_ERROR;
+    } else {
+        char** keys;
+        char** vals;
+        int* strats;
+        int key_count = 0;
+        reg_file** files;
+        reg_error error;
+        int file_count;
+        for (i = 2; i < objc;) {
+            int index, strat_index, val_length;
+            if (Tcl_GetIndexFromObj(interp, objv[i], file_props, "search key",
+                        0, &index) != TCL_OK) {
+                return TCL_ERROR;
+            }
+
+            /* we ate the key value */
+            i++;
+
+            /* check whether there's a strategy */
+            if (Tcl_GetString(objv[i])[0] == '-'
+                    && Tcl_GetIndexFromObjStruct(interp, objv[i], strategies,
+                        sizeof(strategy_type), "option", 0, &strat_index)
+                    != TCL_ERROR) {
+                /* this key has a strategy specified, eat the strategy parameter */
+                i++;
+
+                if (strategies[strat_index].strategy != reg_strategy_null) {
+                    /* this key must also have a value */
+
+                    if (Tcl_GetStringFromObj(objv[i], &val_length) == NULL
+                            || val_length == 0) {
+                        Tcl_WrongNumArgs(interp, 2, objv,
+                                "search ?key ?options? value ...?");
+                        return TCL_ERROR;
+                    }
+
+                    i++;
+                }
+            } else {
+                /* this key must also have a value */
+
+                if (Tcl_GetStringFromObj(objv[i], &val_length) == NULL
+                        || val_length == 0) {
+                    Tcl_WrongNumArgs(interp, 2, objv,
+                            "search ?key ?options? value ...?");
+                    return TCL_ERROR;
+                }
+
+                i++;
+            }
+
+            key_count++;
+        }
+
+        keys = malloc(key_count * sizeof(char*));
+        vals = malloc(key_count * sizeof(char*));
+        strats = malloc(key_count * sizeof(int));
+        if (!keys || !vals || !strats) {
+            return TCL_ERROR;
+        }
+        for (i = 2, j = 0; i < objc && j < key_count; j++) {
+            int strat_index;
+
+            keys[j] = Tcl_GetString(objv[i++]);
+
+            /* try to get the strategy */
+            if (Tcl_GetString(objv[i])[0] == '-'
+                    && Tcl_GetIndexFromObjStruct(interp, objv[i], strategies,
+                        sizeof(strategy_type), "option", 0, &strat_index)
+                    != TCL_ERROR) {
+                /* this key has a strategy specified */
+                i++;
+
+                strats[j] = strategies[strat_index].strategy;
+            } else {
+                /* use default strategy */
+                strats[j] = reg_strategy_exact;
+            }
+
+            if (strats[j] != reg_strategy_null) {
+                vals[j] = Tcl_GetString(objv[i++]);
+            } else {
+                vals[j] = NULL;
+            }
+        }
+        file_count = reg_file_search(reg, keys, vals, strats, key_count,
+                &files, &error);
+        free(keys);
+        free(vals);
+        free(strats);
+        if (file_count >= 0) {
+            int retval;
+            Tcl_Obj* resultObj;
+            Tcl_Obj** objs;
+            if (list_file_to_obj(interp, &objs, files, file_count, &error)){
+                resultObj = Tcl_NewListObj(file_count, objs);
+                Tcl_SetObjResult(interp, resultObj);
+                free(objs);
+                retval = TCL_OK;
+            } else {
+                retval = registry_failed(interp, &error);
+            }
+            free(files);
+            return retval;
+        }
+        return registry_failed(interp, &error);
+    }
+}
+
+typedef struct {
+    char* name;
+    int (*function)(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);
+} file_cmd_type;
+
+static file_cmd_type file_cmds[] = {
+    /* Global commands */
+    { "open", file_open },
+    { "close", file_close },
+    { "search", file_search },
+    { NULL, NULL }
+};
+
+/*
+ * registry::file cmd ?arg ...?
+ *
+ * Commands manipulating file entries in the registry. This can be called `registry::file`
+ */
+int file_cmd(ClientData clientData UNUSED, Tcl_Interp* interp, int objc,
+        Tcl_Obj* CONST objv[]) {
+    int cmd_index;
+    if (objc < 2) {
+        Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
+        return TCL_ERROR;
+    }
+    if (Tcl_GetIndexFromObjStruct(interp, objv[1], file_cmds,
+                sizeof(file_cmd_type), "cmd", 0, &cmd_index) == TCL_OK) {
+        file_cmd_type* cmd = &file_cmds[cmd_index];
+        return cmd->function(interp, objc, objv);
+    }
+    return TCL_ERROR;
+}

Copied: trunk/base/src/registry2.0/file.h (from rev 88375, branches/gsoc11-rev-upgrade/base/src/registry2.0/file.h)
===================================================================
--- trunk/base/src/registry2.0/file.h	                        (rev 0)
+++ trunk/base/src/registry2.0/file.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,44 @@
+/*
+ * file.h
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2011 Clemens Lang <cal at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _FILE_H
+#define _FILE_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tcl.h>
+
+void delete_file(ClientData clientData);
+
+int file_cmd(ClientData clientData UNUSED, Tcl_Interp* interp, int objc,
+        Tcl_Obj* CONST objv[]);
+
+#endif /* _FILE_H */
+

Copied: trunk/base/src/registry2.0/fileobj.c (from rev 88375, branches/gsoc11-rev-upgrade/base/src/registry2.0/fileobj.c)
===================================================================
--- trunk/base/src/registry2.0/fileobj.c	                        (rev 0)
+++ trunk/base/src/registry2.0/fileobj.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,142 @@
+/*
+ * fileobj.c
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2011 Clemens Lang <cal at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <tcl.h>
+#include <sqlite3.h>
+
+#include "fileobj.h"
+#include "registry.h"
+#include "util.h"
+
+const char* file_props[] = {
+    "path",
+    "actual_path",
+    "active",
+    "mtime",
+    "md5sum",
+    "editable",
+    "binary",
+    NULL
+};
+
+/* ${file} prop ?value? */
+static int file_obj_prop(Tcl_Interp* interp, reg_file* file, int objc,
+        Tcl_Obj* CONST objv[]) {
+    int index;
+    if (objc > 3) {
+        Tcl_WrongNumArgs(interp, 2, objv, "?value?");
+        return TCL_ERROR;
+    }
+    if (objc == 2) {
+        /* ${file} prop; return the current value */
+        reg_registry* reg = registry_for(interp, reg_attached);
+        if (reg == NULL) {
+            return TCL_ERROR;
+        }
+        if (Tcl_GetIndexFromObj(interp, objv[1], file_props, "prop", 0, &index)
+                == TCL_OK) {
+            char* key = Tcl_GetString(objv[1]);
+            char* value;
+            reg_error error;
+            if (reg_file_propget(file, key, &value, &error)) {
+                Tcl_Obj* result = Tcl_NewStringObj(value, -1);
+                Tcl_SetObjResult(interp, result);
+                free(value);
+                return TCL_OK;
+            }
+            return registry_failed(interp, &error);
+        }
+        return TCL_ERROR;
+    } else {
+        /* ${file} prop name value; set a new value */
+        reg_registry* reg = registry_for(interp, reg_attached);
+        if (reg == NULL) {
+            return TCL_ERROR;
+        }
+        if (Tcl_GetIndexFromObj(interp, objv[1], file_props, "prop", 0, &index)
+                == TCL_OK) {
+            char* key = Tcl_GetString(objv[1]);
+            char* value = Tcl_GetString(objv[2]);
+            reg_error error;
+            if (reg_file_propset(file, key, value, &error)) {
+                return TCL_OK;
+            }
+            return registry_failed(interp, &error);
+        }
+        return TCL_ERROR;
+    }
+}
+
+typedef struct {
+    char* name;
+    int (*function)(Tcl_Interp* interp, reg_file* file, int objc,
+            Tcl_Obj* CONST objv[]);
+} file_obj_cmd_type;
+
+static file_obj_cmd_type file_cmds[] = {
+    /* keys */
+    { "path", file_obj_prop },
+    { "actual_path", file_obj_prop },
+    { "active", file_obj_prop },
+    { "mtime", file_obj_prop },
+    { "md5sum", file_obj_prop },
+    { "editable", file_obj_prop },
+    { "binary", file_obj_prop },
+    { NULL, NULL }
+};
+
+/* ${file} cmd ?arg ...? */
+/* This function implements the command that will be called when a file
+ * created by `registry::file` is used as a procedure. Since all data is kept
+ * in a temporary sqlite3 database that is created for the current interpreter,
+ * none of the sqlite3 functions used have any error checking. That should be a
+ * safe assumption, since nothing outside of registry:: should ever have the
+ * chance to touch it.
+ */
+int file_obj_cmd(ClientData clientData, Tcl_Interp* interp, int objc,
+        Tcl_Obj* CONST objv[]) {
+    int cmd_index;
+    if (objc < 2) {
+        Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
+        return TCL_ERROR;
+    }
+    if (Tcl_GetIndexFromObjStruct(interp, objv[1], file_cmds,
+                sizeof(file_obj_cmd_type), "cmd", 0, &cmd_index) == TCL_OK) {
+        file_obj_cmd_type* cmd = &file_cmds[cmd_index];
+        return cmd->function(interp, (reg_file*)clientData, objc, objv);
+    }
+    return TCL_ERROR;
+}
+

Copied: trunk/base/src/registry2.0/fileobj.h (from rev 88375, branches/gsoc11-rev-upgrade/base/src/registry2.0/fileobj.h)
===================================================================
--- trunk/base/src/registry2.0/fileobj.h	                        (rev 0)
+++ trunk/base/src/registry2.0/fileobj.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -0,0 +1,44 @@
+/*
+ * fileobj.h
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2011 Clemens Lang <cal at macports.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _FILE_OBJ_CMD_H
+#define _FILE_OBJ_CMD_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tcl.h>
+#include <sqlite3.h>
+
+extern const char* file_props[];
+
+int file_obj_cmd(ClientData clientData, Tcl_Interp* interp, int objc,
+        Tcl_Obj* CONST objv[]);
+
+#endif /* _FILE_OBJ_CMD_H */

Modified: trunk/base/src/registry2.0/portimage.tcl
===================================================================
--- trunk/base/src/registry2.0/portimage.tcl	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/portimage.tcl	2011-12-30 00:17:49 UTC (rev 88376)
@@ -88,7 +88,7 @@
         set noexec $options(ports_activate_no-exec)
     }
     if {![info exists registry_open]} {
-        registry::open [file join ${macports::registry.path} registry registry.db]
+        registry::open [::file join ${macports::registry.path} registry registry.db]
         set registry_open yes
     }
     set todeactivate [list]
@@ -116,7 +116,7 @@
         if { ![string equal [$requested installtype] "image"] } {
             return -code error "Image error: ${name} @${specifier} not installed as an image."
         }
-        if {![file isfile $location]} {
+        if {![::file isfile $location]} {
             return -code error "Image error: Can't find image file $location"
         }
         if { [string equal [$requested state] "installed"] } {
@@ -158,7 +158,7 @@
         set force 0
     }
     if {![info exists registry_open]} {
-        registry::open [file join ${macports::registry.path} registry registry.db]
+        registry::open [::file join ${macports::registry.path} registry registry.db]
         set registry_open yes
     }
 
@@ -249,7 +249,7 @@
 ## @param [in] dstfile path to activate file to
 ## @return 1 if file needs to be explicitly deleted if we have to roll back, 0 otherwise
 proc _activate_file {srcfile dstfile} {
-    if {[catch {set filetype [file type $srcfile]} result]} {
+    if {[catch {set filetype [::file type $srcfile]} result]} {
         # this can happen if the archive was built on case-sensitive and we're case-insensitive
         # we know any existing dstfile is ours because we checked for conflicts earlier
         if {![catch {file type $dstfile}]} {
@@ -264,23 +264,23 @@
             # Don't recursively copy directories
             ui_debug "activating directory: $dstfile"
             # Don't do anything if the directory already exists.
-            if { ![file isdirectory $dstfile] } {
-                file mkdir $dstfile
+            if { ![::file isdirectory $dstfile] } {
+                ::file mkdir $dstfile
                 # fix attributes on the directory.
                 if {[getuid] == 0} {
-                    eval file attributes {$dstfile} [file attributes $srcfile]
+                    eval ::file attributes {$dstfile} [::file attributes $srcfile]
                 } else {
                     # not root, so can't set owner/group
-                    eval file attributes {$dstfile} -permissions [file attributes $srcfile -permissions]
+                    eval ::file attributes {$dstfile} -permissions [::file attributes $srcfile -permissions]
                 }
                 # set mtime on installed element
-                file mtime $dstfile [file mtime $srcfile]
+                ::file mtime $dstfile [::file mtime $srcfile]
             }
             return 0
         }
         default {
             ui_debug "activating file: $dstfile"
-            file rename $srcfile $dstfile
+            ::file rename $srcfile $dstfile
             return 1
         }
     }
@@ -290,7 +290,7 @@
 # returns: path to the extracted directory
 proc extract_archive_to_tmpdir {location} {
     global macports::registry.path
-    set extractdir [mkdtemp [file dirname $location]/mpextractXXXXXXXX]
+    set extractdir [mkdtemp [::file dirname $location]/mpextractXXXXXXXX]
     set startpwd [pwd]
 
     try {
@@ -305,7 +305,7 @@
         set unarchive.pre_args {}
         set unarchive.args {}
         set unarchive.pipe_cmd ""
-        set unarchive.type [file extension $location]
+        set unarchive.type [::file extension $location]
         switch -regex ${unarchive.type} {
             cp(io|gz) {
                 set pax "pax"
@@ -413,7 +413,7 @@
         }
         system $cmdstring
     } catch {*} {
-        file delete -force $extractdir
+        ::file delete -force $extractdir
         throw
     } finally {
         cd $startpwd
@@ -451,7 +451,7 @@
                 # To be able to install links, we test if we can lstat the file to
                 # figure out if the source file exists (file exists will return
                 # false for symlinks on files that do not exist)
-                if { [catch {file lstat $srcfile dummystatvar}] } {
+                if { [catch {::file lstat $srcfile dummystatvar}] } {
                     throw registry::image-error "Image error: Source file $srcfile does not appear to exist (cannot lstat it).  Unable to activate port [$port name]."
                 }
 
@@ -474,10 +474,10 @@
                         # if we're forcing the activation, then we move any existing
                         # files to a backup file, both in the filesystem and in the
                         # registry
-                        if { ![catch {file type $file}] } {
+                        if { ![catch {::file type $file}] } {
                             set bakfile "${file}${baksuffix}"
                             ui_warn "File $file already exists.  Moving to: $bakfile."
-                            file rename -force -- $file $bakfile
+                            ::file rename -force -- $file $bakfile
                             lappend backups $file
                         }
                         if { $owner != {} } {
@@ -490,7 +490,7 @@
                         # the registry
                         if { $owner != {} && $owner != $port } {
                             throw registry::image-error "Image error: $file is being used by the active [$owner name] port.  Please deactivate this port first, or use 'port -f activate [$port name]' to force the activation."
-                        } elseif { $owner == {} && ![catch {file type $file}] } {
+                        } elseif { $owner == {} && ![catch {::file type $file}] } {
                             throw registry::image-error "Image error: $file already exists and does not belong to a registered port.  Unable to activate port [$port name]. Use 'port -f activate [$port name]' to force the activation."
                         }
                     }
@@ -504,10 +504,10 @@
                 # subpaths. We do need, nevertheless, all sub paths to make sure
                 # we'll set the directory attributes properly for all
                 # directories.
-                set directory [file dirname $file]
+                set directory [::file dirname $file]
                 while { [lsearch -exact $files $directory] == -1 } {
                     lappend files $directory
-                    set directory [file dirname $directory]
+                    set directory [::file dirname $directory]
                 }
 
                 # Also add the filename to the imagefile list.
@@ -555,7 +555,7 @@
         # locations, then rethrow the error. Transaction rollback will take care
         # of this in the registry.
         foreach file $backups {
-            file rename -force -- "${file}${baksuffix}" $file
+            ::file rename -force -- "${file}${baksuffix}" $file
         }
         # reactivate deactivated ports
         foreach entry [array names todeactivate] {
@@ -564,10 +564,10 @@
             }
         }
         # remove temp image dir
-        file delete -force $extracted_dir
+        ::file delete -force $extracted_dir
         throw
     }
-    file delete -force $extracted_dir
+    ::file delete -force $extracted_dir
 }
 
 # These directories should not be removed during deactivation even if they are empty.
@@ -576,7 +576,7 @@
 array set precious_dirs { /Library/LaunchDaemons 1 /Library/LaunchAgents 1 }
 
 proc _deactivate_file {dstfile} {
-    if {[catch {file type $dstfile} filetype]} {
+    if {[catch {::file type $dstfile} filetype]} {
         ui_debug "$dstfile does not exist"
         return
     }
@@ -589,7 +589,7 @@
             variable precious_dirs
             if {![info exists precious_dirs($dstfile)]} {
                 ui_debug "deactivating directory: $dstfile"
-                file delete -- $dstfile
+                ::file delete -- $dstfile
             } else {
                 ui_debug "directory $dstfile does not belong to us"
             }
@@ -598,7 +598,7 @@
         }
     } else {
         ui_debug "deactivating file: $dstfile"
-        file delete -- $dstfile
+        ::file delete -- $dstfile
     }
 }
 
@@ -606,7 +606,7 @@
     set files [list]
 
     foreach file $imagefiles {
-        if { [file exists $file] || (![catch {file type $file}] && [file type $file] == "link") } {
+        if { [::file exists $file] || (![catch {::file type $file}] && [::file type $file] == "link") } {
             # Normalize the file path to avoid removing the intermediate
             # symlinks (remove the empty directories instead)
             # Remark: paths in the registry may be not normalized.
@@ -617,14 +617,14 @@
             # belong to any port.
             # The custom realpath proc is necessary because file normalize
             # does not resolve symlinks on OS X < 10.6
-            set directory [realpath [file dirname $file]]
-            lappend files [file join $directory [file tail $file]]
+            set directory [realpath [::file dirname $file]]
+            lappend files [::file join $directory [::file tail $file]]
 
             # Split out the filename's subpaths and add them to the image list
             # as well.
             while { [lsearch -exact $files $directory] == -1 } {
                 lappend files $directory
-                set directory [file dirname $directory]
+                set directory [::file dirname $directory]
             }
         } else {
             ui_debug "$file does not exist."

Modified: trunk/base/src/registry2.0/portuninstall.tcl
===================================================================
--- trunk/base/src/registry2.0/portuninstall.tcl	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/portuninstall.tcl	2011-12-30 00:17:49 UTC (rev 88376)
@@ -215,7 +215,7 @@
         file delete $imagefile
         # Try to delete the port's image dir; will fail if there are more image
         # files so just ignore the failure
-        catch {file delete [file dirname $imagefile]}
+        catch {file delete [::file dirname $imagefile]}
 
         registry::entry delete $port
     }

Modified: trunk/base/src/registry2.0/receipt_flat.tcl
===================================================================
--- trunk/base/src/registry2.0/receipt_flat.tcl	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/receipt_flat.tcl	2011-12-30 00:17:49 UTC (rev 88376)
@@ -75,7 +75,7 @@
 
     # regex match case
     if {$portversion == 0} {
-	set x [glob -nocomplain -directory [file join ${macports::registry.path} receipts] -- ${portname}-*]
+	set x [glob -nocomplain -directory [::file join ${macports::registry.path} receipts] -- ${portname}-*]
 	if {[string length $x]} {
 	    set matchfile [lindex $x 0]
 		# Remove trailing .bz2, if any.
@@ -84,7 +84,7 @@
 	    set matchfile ""
 	}
     } else {
-	set matchfile [file join ${macports::registry.path} receipts ${portname}-${portversion}]
+	set matchfile [::file join ${macports::registry.path} receipts ${portname}-${portversion}]
     }
 
     # Might as well bail out early if no file to match
@@ -92,7 +92,7 @@
 		return ""
     }
 
-    if {[file exists $matchfile] || [file exists ${matchfile}.bz2]} {
+    if {[::file exists $matchfile] || [::file exists ${matchfile}.bz2]} {
 		return $matchfile
     }
     return ""
@@ -110,11 +110,11 @@
 	    return $ref_index($name,$version,$revision,$variants)
 	}
 
-	set receipt_path [file join ${macports::registry.path} receipts ${name}]
+	set receipt_path [::file join ${macports::registry.path} receipts ${name}]
 
 	# If the receipt path ${name} doesn't exist, then the receipt probably is
 	# in the old HEAD format.
-	if { ![file isdirectory $receipt_path] } {
+	if { ![::file isdirectory $receipt_path] } {
 		set receipt_file [get_head_entry_receipt_path $name $version]
 		
 		if {![string length $receipt_file]} {
@@ -127,7 +127,7 @@
 		
 		# Extract the version from the path.
 		if { $version == "" } {
-			set theFileName [file tail $receipt_file]
+			set theFileName [::file tail $receipt_file]
 			regexp "^$name-(.*)\$" $theFileName match version
 		}
 	} else {
@@ -137,7 +137,7 @@
 			# version given to us.  How should we handle this?
 			set x [glob -nocomplain -directory ${receipt_path} *]
 			if { [string length $x] } {
-				set v [lindex [file split [lindex $x 0]] end]
+				set v [lindex [::file split [lindex $x 0]] end]
 				regexp {([-_a-zA-Z0-9\.]+)_([0-9]*)([+-_a-zA-Z0-9]*)$} $v match version revision variants
 			} else {
 				return -code error "Registry error: ${name} not registered as installed."
@@ -148,15 +148,15 @@
 			return -code error "Registry error: ${name} @${version}_${revision}${variants} not registered as installed."
 		}
 	
-		set receipt_path [file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
+		set receipt_path [::file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
 	
-		set receipt_file [file join ${receipt_path} receipt]
+		set receipt_file [::file join ${receipt_path} receipt]
 	}
 
-	if { [file exists ${receipt_file}.bz2] && [file exists ${registry::autoconf::bzip2_path}] } {
+	if { [::file exists ${receipt_file}.bz2] && [::file exists ${registry::autoconf::bzip2_path}] } {
 		set receipt_file ${receipt_file}.bz2
 		set receipt_contents [exec ${registry::autoconf::bzip2_path} -d -c ${receipt_file}]
-	} elseif { [file exists ${receipt_file}] } {
+	} elseif { [::file exists ${receipt_file}] } {
 		set receipt_handle [open ${receipt_file} r]
 		set receipt_contents [read $receipt_handle]
 		close $receipt_handle
@@ -177,7 +177,7 @@
 		convert_entry_from_HEAD $name $version $revision $variants $receipt_contents $ref
 		
 		# move the old receipt
-		set convertedDirPath [file join ${macports::registry.path} receipts_converted]
+		set convertedDirPath [::file join ${macports::registry.path} receipts_converted]
 		file mkdir $convertedDirPath
 		file rename -- $receipt_file $convertedDirPath
 	} elseif {[string match "# Version: *" $receipt_contents]} {
@@ -274,15 +274,15 @@
 	foreach file $contents {
 		if {[llength $file]} {
 			set theFilePath [lindex $file 0]
-			if {[file isfile $theFilePath]} {
-				set previousPort [file_registered $theFilePath]
+			if {[::file isfile $theFilePath]} {
+				set previousPort [::file_registered $theFilePath]
 				if {$previousPort != 0} {
 					ui_warn "Conflict detected for file $theFilePath between $previousPort and $name."
 				}
 				if {[catch {register_file $theFilePath $name}]} {
 					ui_warn "An error occurred while adding $theFilePath to the file_map database."
 				}
-			} elseif {![file exists $theFilePath]} {
+			} elseif {![::file exists $theFilePath]} {
 				ui_warn "Port $name refers to $theFilePath which doesn't exist."
 			}
 			lappend theActualContents $file
@@ -314,10 +314,10 @@
 
 	set receipt_contents [array get receipt_$ref]
 
-	set receipt_path [file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
-	set receipt_file [file join ${receipt_path} receipt]
+	set receipt_path [::file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
+	set receipt_file [::file join ${receipt_path} receipt]
 
-	if { ![file isdirectory ${receipt_path}] } {
+	if { ![::file isdirectory ${receipt_path}] } {
 		file mkdir ${receipt_path}
 	}
 
@@ -326,15 +326,15 @@
 	puts $receipt_handle $receipt_contents
 	close $receipt_handle
 
-	if { [file exists ${receipt_file}] } {
+	if { [::file exists ${receipt_file}] } {
 		file delete -force -- "${receipt_file}"
-	} elseif { [file exists ${receipt_file}.bz2] } {
+	} elseif { [::file exists ${receipt_file}.bz2] } {
 		file delete -force -- "${receipt_file}.bz2"
 	}
 
 	file rename -force -- "${receipt_file}.tmp" "${receipt_file}"
 
-	if { [file exists ${receipt_file}] && [file exists ${registry::autoconf::bzip2_path}] && ![info exists registry.nobzip] } {
+	if { [::file exists ${receipt_file}] && [::file exists ${registry::autoconf::bzip2_path}] && ![info exists registry.nobzip] } {
 		system "${registry::autoconf::bzip2_path} -f ${receipt_file}"
 	}
 
@@ -345,12 +345,12 @@
 proc entry_exists {name version {revision 0} {variants ""}} {
 	global macports::registry.path
 
-	set receipt_path [file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
-	set receipt_file [file join ${receipt_path} receipt]
+	set receipt_path [::file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
+	set receipt_file [::file join ${receipt_path} receipt]
 
-	if { [file exists $receipt_file] } {
+	if { [::file exists $receipt_file] } {
 		return 1
-	} elseif { [file exists ${receipt_file}.bz2] } {
+	} elseif { [::file exists ${receipt_file}.bz2] } {
 		return 1
 	}
 
@@ -361,7 +361,7 @@
 proc entry_exists_for_name {name} {
 	global macports::registry.path
 
-	set receipt_path [file join ${macports::registry.path} receipts ${name}]
+	set receipt_path [::file join ${macports::registry.path} receipts ${name}]
 
 	if {[llength [glob -nocomplain -directory $receipt_path */receipt{,.bz2}]] > 0} {
 		return 1
@@ -417,14 +417,14 @@
 	    array unset ref_index "$name,$version,$revision,$variants"
 	}
 
-	set receipt_path [file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
-	if { [file exists ${receipt_path}] } {
+	set receipt_path [::file join ${macports::registry.path} receipts ${name} ${version}_${revision}${variants}]
+	if { [::file exists ${receipt_path}] } {
 		# remove port receipt directory
 		ui_debug "deleting directory: ${receipt_path}"
 		file delete -force -- ${receipt_path}
 		# remove port receipt parent directory (if empty)
-		set receipt_dir [file join ${macports::registry.path} receipts ${name}]
-		if { [file isdirectory ${receipt_dir}] } {
+		set receipt_dir [::file join ${macports::registry.path} receipts ${name}]
+		if { [::file isdirectory ${receipt_dir}] } {
 			# 0 item means empty.
 			if { [llength [readdir ${receipt_dir}]] == 0 } {
 				ui_debug "deleting directory: ${receipt_dir}"
@@ -449,12 +449,12 @@
 proc installed {{name ""} {version ""}} {
 	global macports::registry.path
 
-	set query_path [file join ${macports::registry.path} receipts]
+	set query_path [::file join ${macports::registry.path} receipts]
 	
 	if { $name == "" } {
-		set query_path [file join ${query_path} *]
+		set query_path [::file join ${query_path} *]
 		if { $version == "" } {
-			set query_path [file join ${query_path} *]
+			set query_path [::file join ${query_path} *]
 		}
 		# [PG] Huh?
 	} else {
@@ -462,32 +462,32 @@
 	    # returned with the correct case even if it's wrong when given. To get the
 	    # correct case on a case-insensitive FS, we have to list the directory and
 	    # compare against each entry.
-	    set name_path [file join ${query_path} *]
+	    set name_path [::file join ${query_path} *]
 	    set name_entries [glob -nocomplain -types d ${name_path}]
 	    foreach entry $name_entries {
-	        set basename [file tail $entry]
+	        set basename [::file tail $entry]
 	        if {[string equal -nocase $basename $name]} {
 	            set name $basename
 	            break
 	        }
 	    }
-		set query_path [file join ${query_path} ${name}]
+		set query_path [::file join ${query_path} ${name}]
 		if { $version != "" } {
-			set query_path [file join ${query_path} ${version}]
+			set query_path [::file join ${query_path} ${version}]
 		} else {
-			set query_path [file join ${query_path} *]
+			set query_path [::file join ${query_path} *]
 		}
 	}
 
 	set x [glob -nocomplain -types d ${query_path}]
 	set rlist [list]
 	foreach p $x {
-		if {![file isfile [file join $p receipt.bz2]] && ![file isfile [file join $p receipt]]} {
+		if {![::file isfile [::file join $p receipt.bz2]] && ![::file isfile [::file join $p receipt]]} {
 			continue
 		}
 		set plist [list]
-		regexp {([-_a-zA-Z0-9\.]+)_([0-9]*)([+-_a-zA-Z0-9]*)$} [lindex [file split $p] end] match version revision variants
-		lappend plist [lindex [file split $p] end-1]
+		regexp {([-_a-zA-Z0-9\.]+)_([0-9]*)([+-_a-zA-Z0-9]*)$} [lindex [::file split $p] end] match version revision variants
+		lappend plist [lindex [::file split $p] end-1]
 		lappend plist $version
 		lappend plist $revision
 		lappend plist $variants
@@ -496,13 +496,13 @@
 
 	# append the ports in old HEAD format.
 	if { $name == "" } {
-		set query_path [file join ${macports::registry.path} receipts *]
+		set query_path [::file join ${macports::registry.path} receipts *]
 	} else {
-		set query_path [file join ${macports::registry.path} receipts ${name}-*]
+		set query_path [::file join ${macports::registry.path} receipts ${name}-*]
 	}
     set receiptglob [glob -nocomplain -types f ${query_path}]
     foreach receipt_file $receiptglob {
-		set theFileName [file tail $receipt_file]
+		set theFileName [::file tail $receipt_file]
 
     	# Remark: these regexes do not always work.
    		set theName ""
@@ -539,14 +539,14 @@
 	global macports::registry.path
 	variable file_map
 
-	set receipt_path [file join ${macports::registry.path} receipts]
-	set map_file [file join ${receipt_path} file_map]
+	set receipt_path [::file join ${macports::registry.path} receipts]
+	set map_file [::file join ${receipt_path} file_map]
 
 	# Don't reopen it (it actually would deadlock us), unless it was open r/o.
 	# and we want it r/w.
 	if { [info exists file_map] } {
 		if { $readonly == 0 } {
-			if {[filemap isreadonly file_map]} {
+			if {[::filemap isreadonly file_map]} {
 				filemap close file_map
 				filemap open file_map ${map_file}.db
 			}
@@ -556,11 +556,11 @@
 
 	set old_filemap [list]
 
-	if { ![file exists ${map_file}.db] } {
+	if { ![::file exists ${map_file}.db] } {
 		# Convert to new format
-		if { [file exists ${map_file}.bz2] && [file exists ${registry::autoconf::bzip2_path}] } {
+		if { [::file exists ${map_file}.bz2] && [::file exists ${registry::autoconf::bzip2_path}] } {
 			set old_filemap [exec ${registry::autoconf::bzip2_path} -d -c ${map_file}.bz2]
-		} elseif { [file exists $map_file] } {		
+		} elseif { [::file exists $map_file] } {		
 			set map_handle [open ${map_file} r]
 			set old_filemap [read $map_handle]
 			close $map_handle
@@ -608,8 +608,8 @@
 
 	open_file_map 1
 
-	if {[filemap exists file_map $file]} {
-		return [filemap get file_map $file]
+	if {[::filemap exists file_map $file]} {
+		return [::filemap get file_map $file]
 	} else {
 		return 0
 	}
@@ -630,7 +630,7 @@
 
 	open_file_map 1
 
-	set files [filemap list file_map $name]
+	set files [::filemap list file_map $name]
 
 	if { [llength $files] > 0 } {
 		return $files
@@ -641,7 +641,7 @@
 			# Convert the port and retry.
 			open_entry $name
 			
-			set files [filemap list file_map $name]
+			set files [::filemap list file_map $name]
 			
 			return $files
 		} else {
@@ -662,7 +662,7 @@
 
 	open_file_map
 
-	if { [file type $file] == "link" } {
+	if { [::file type $file] == "link" } {
 		ui_debug "Adding link to file_map: $file for: $port"
 	} else {
 		ui_debug "Adding file to file_map: $file for: $port"
@@ -684,7 +684,7 @@
 
 	foreach f $files {
 		set file [lindex $f 0]
-		if { [file type $file] == "link" } {
+		if { [::file type $file] == "link" } {
 			ui_debug "Adding link to file_map: $file for: $port"
 		} else {
 			ui_debug "Adding file to file_map: $file for: $port"
@@ -743,13 +743,13 @@
 	global macports::registry.path
 	variable dep_map
 
-	set receipt_path [file join ${macports::registry.path} receipts]
+	set receipt_path [::file join ${macports::registry.path} receipts]
 
-	set map_file [file join ${receipt_path} dep_map]
+	set map_file [::file join ${receipt_path} dep_map]
 
-	if { [file exists ${map_file}.bz2] && [file exists ${registry::autoconf::bzip2_path}] } {
+	if { [::file exists ${map_file}.bz2] && [::file exists ${registry::autoconf::bzip2_path}] } {
 		set dep_map [exec ${registry::autoconf::bzip2_path} -d -c ${map_file}.bz2]
-	} elseif { [file exists ${map_file}] } {
+	} elseif { [::file exists ${map_file}] } {
 		set map_handle [open ${map_file} r]
 		set dep_map [read $map_handle]
 		close $map_handle
@@ -837,9 +837,9 @@
 	global macports::registry.path
 	variable dep_map
 
-	set receipt_path [file join ${macports::registry.path} receipts]
+	set receipt_path [::file join ${macports::registry.path} receipts]
 
-	set map_file [file join ${receipt_path} dep_map]
+	set map_file [::file join ${receipt_path} dep_map]
 
 	set map_handle [open ${map_file}.tmp w 0644]
 	puts $map_handle $dep_map
@@ -850,7 +850,7 @@
 
     file rename -- ${map_file}.tmp ${map_file}
 
-	if { [file exists ${map_file}] && [file exists ${registry::autoconf::bzip2_path}] && ![info exists registry.nobzip] } {
+	if { [::file exists ${map_file}] && [::file exists ${registry::autoconf::bzip2_path}] && ![info exists registry.nobzip] } {
 		system "${registry::autoconf::bzip2_path} -f ${map_file}"
 	}
 


Property changes on: trunk/base/src/registry2.0/receipt_sqlite.tcl
___________________________________________________________________
Modified: svn:mergeinfo
   - /branches/gsoc08-privileges/base/src/registry1.0/receipt_sqlite.tcl:37343-46937
/branches/gsoc09-logging/base/src/registry1.0/receipt_sqlite.tcl:51231-60371
/branches/universal-sanity/base/src/registry1.0/receipt_sqlite.tcl:51872-52323
/branches/variant-descs-14482/base/src/registry1.0/receipt_sqlite.tcl:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/registry1.0/receipt_sqlite.tcl:45682-46060
/users/perry/base-select/src/registry1.0/receipt_sqlite.tcl:44044-44692
   + /branches/gsoc08-privileges/base/src/registry1.0/receipt_sqlite.tcl:37343-46937
/branches/gsoc09-logging/base/src/registry1.0/receipt_sqlite.tcl:51231-60371
/branches/gsoc11-rev-upgrade/base/src/registry2.0/receipt_sqlite.tcl:78828-88375
/branches/universal-sanity/base/src/registry1.0/receipt_sqlite.tcl:51872-52323
/branches/variant-descs-14482/base/src/registry1.0/receipt_sqlite.tcl:34469-34855,34900-37508,37511-37512,41040-41463,42575-42626,42640-42659
/users/perry/base-bugs_and_notes/src/registry1.0/receipt_sqlite.tcl:45682-46060
/users/perry/base-select/src/registry1.0/receipt_sqlite.tcl:44044-44692

Modified: trunk/base/src/registry2.0/registry.c
===================================================================
--- trunk/base/src/registry2.0/registry.c	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/registry.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -38,12 +38,14 @@
 
 #include <cregistry/registry.h>
 #include <cregistry/entry.h>
+#include <cregistry/file.h>
 
-#include "registry.h"
+#include "entry.h"
+#include "entryobj.h"
+#include "file.h"
 #include "graph.h"
 #include "item.h"
-#include "entry.h"
-#include "entryobj.h"
+#include "registry.h"
 #include "util.h"
 
 int registry_failed(Tcl_Interp* interp, reg_error* errPtr) {
@@ -54,6 +56,8 @@
     return TCL_ERROR;
 }
 
+/* we don't need delete_file_list and restore_file_list unless we allow deletion
+   of files via the file interface */
 static void delete_entry_list(ClientData list, Tcl_Interp* interp UNUSED) {
     entry_list* curr = *(entry_list**)list;
     while (curr) {
@@ -80,8 +84,11 @@
 int registry_tcl_detach(Tcl_Interp* interp, reg_registry* reg,
         reg_error* errPtr) {
     reg_entry** entries;
-    int entry_count = reg_all_open_entries(reg, &entries);
+    reg_file** files;
+    int entry_count;
+    int file_count;
     int i;
+    entry_count = reg_all_open_entries(reg, &entries);
     if (entry_count == -1) {
         return 0;
     }
@@ -91,6 +98,16 @@
         }
     }
     free(entries);
+    file_count = reg_all_open_files(reg, &files);
+    if (file_count == -1) {
+        return 0;
+    }
+    for (i = 0; i < file_count; i++) {
+        if (files[i]->proc) {
+            Tcl_DeleteCommand(interp, files[i]->proc);
+        }
+    }
+    free(files);
     if (!reg_detach(reg, errPtr)) {
         return registry_failed(interp, errPtr);
     }
@@ -319,6 +336,7 @@
     /* Tcl_CreateObjCommand(interp, "registry::graph", GraphCmd, NULL, NULL); */
     /* Tcl_CreateObjCommand(interp, "registry::item", item_cmd, NULL, NULL); */
     Tcl_CreateObjCommand(interp, "registry::entry", entry_cmd, NULL, NULL);
+    Tcl_CreateObjCommand(interp, "registry::file", file_cmd, NULL, NULL);
     if (Tcl_PkgProvide(interp, "registry2", "2.0") != TCL_OK) {
         return TCL_ERROR;
     }

Modified: trunk/base/src/registry2.0/registry.tcl
===================================================================
--- trunk/base/src/registry2.0/registry.tcl	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/registry.tcl	2011-12-30 00:17:49 UTC (rev 88376)
@@ -320,7 +320,7 @@
     # (we won't store the md5 of the target of links since it's meaningless
     # and $statvar(mode) tells us that links are links).
     if {![catch {file lstat $fname statvar}]} {
-	if {[file isfile $fname] && [file type $fname] != "link"} {
+	if {[::file isfile $fname] && [::file type $fname] != "link"} {
 	    if {[catch {md5 file $fname} md5sum] == 0} {
 		# Create a line that matches md5(1)'s output
 		# for backwards compatibility
@@ -347,7 +347,7 @@
 	set rval [list]
 	foreach file $flist {
 		if {[string index $file 0] != "/"} {
-			set file [file join $prefix $file]
+			set file [::file join $prefix $file]
 		}
 		lappend rval [fileinfo_for_file $file]
 	}
@@ -396,9 +396,9 @@
     if {$nlocked > 1} {
         return
     }
-    set lockpath [file join ${registry.path} registry .registry.lock]
+    set lockpath [::file join ${registry.path} registry .registry.lock]
     if {![info exists lockfd]} {
-        if {![file writable [file dirname $lockpath]]} {
+        if {![::file writable [::file dirname $lockpath]]} {
             # skip locking, registry can't be modified anyway
             return
         }

Modified: trunk/base/src/registry2.0/util.c
===================================================================
--- trunk/base/src/registry2.0/util.c	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/util.c	2011-12-30 00:17:49 UTC (rev 88376)
@@ -36,6 +36,7 @@
 
 #include "util.h"
 #include "entryobj.h"
+#include "fileobj.h"
 
 /**
  * Generates a unique proc name starting with prefix.
@@ -45,24 +46,28 @@
  * Tcl interp context. This behavior is similar to that of the builtin
  * `interp create` command, and is intended to generate names for created
  * objects of a similar nature.
- *
- * TODO: add a int* parameter so that functions which need large numbers of
- * unique names can keep track of the lower bound between calls,thereby turning
- * N^2 to N. It'll be alchemy for the 21st century.
  */
-char* unique_name(Tcl_Interp* interp, char* prefix) {
+char* unique_name(Tcl_Interp* interp, char* prefix, int* lower_bound) {
     int result_size = strlen(prefix) + TCL_INTEGER_SPACE + 1;
     char* result = malloc(result_size);
     Tcl_CmdInfo info;
     int i;
     if (!result)
         return NULL;
-    for (i=0; ; i++) {
+    if (lower_bound == NULL) {
+        i = 0;
+    } else {
+        i = *lower_bound;
+    }
+    for (; ; i++) {
         snprintf(result, result_size, "%s%d", prefix, i);
         if (Tcl_GetCommandInfo(interp, result, &info) == 0) {
             break;
         }
     }
+    if (lower_bound != NULL) {
+        *lower_bound = i + 1;
+    }
     return result;
 }
 
@@ -175,18 +180,39 @@
         reg_error* errPtr) {
     if (set_object(interp, name, entry, "entry", entry_obj_cmd, NULL,
                 errPtr)) {
-        int size = strlen(name) + 1;
-        entry->proc = malloc(size*sizeof(char));
+        entry->proc = strdup(name);
         if (!entry->proc) {
             return 0;
         }
-        memcpy(entry->proc, name, size);
         return 1;
     }
     return 0;
 }
 
 /**
+ * Sets a given name to be a file object.
+ *
+ * @param [in] interp  Tcl interpreter to create the file within
+ * @param [in] name    name to associate the given file with
+ * @param [in] file    file to associate with the given name
+ * @param [out] errPtr description of error if it couldn't be set
+ * @return             true if success; false if failure
+ * @see set_object
+ */
+int set_file(Tcl_Interp* interp, char* name, reg_file* file,
+        reg_error* errPtr) {
+    if (set_object(interp, name, file, "file", file_obj_cmd, NULL,
+                errPtr)) {
+        file->proc = strdup(name);
+        if (!file->proc) {
+            return 0;
+        }
+        return 1;
+    }
+    return 0;
+}
+
+/**
  * Reports a sqlite3 error to Tcl.
  *
  * Queries the database for the most recent error message and sets it as the
@@ -204,47 +230,6 @@
     }
 }
 
-/**
- * Sets the result of the interpreter to all objects returned by a query.
- *
- * This function executes `query` on `db` It expects that the query will return
- * records of a single column, `rowid`. It will then use `prefix` to construct
- * unique names for these records, and call `setter` to construct their proc
- * objects. The result of `interp` will be set to a list of all such objects.
- *
- * If TCL_OK is returned, then a list is in the result. If TCL_ERROR is, then an
- * error is there.
- */
-int all_objects(Tcl_Interp* interp, sqlite3* db, char* query, char* prefix,
-        set_object_function* setter) {
-    sqlite3_stmt* stmt;
-    if (sqlite3_prepare(db, query, -1, &stmt, NULL) == SQLITE_OK) {
-        Tcl_Obj* result = Tcl_NewListObj(0, NULL);
-        Tcl_SetObjResult(interp, result);
-        while (sqlite3_step(stmt) == SQLITE_ROW) {
-            sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
-            char* name = unique_name(interp, prefix);
-            if (!name) {
-                return TCL_ERROR;
-            }
-            if (setter(interp, name, rowid) == TCL_OK) {
-                Tcl_Obj* element = Tcl_NewStringObj(name, -1);
-                Tcl_ListObjAppendElement(interp, result, element);
-                free(name);
-            } else {
-                free(name);
-                return TCL_ERROR;
-            }
-        }
-        sqlite3_finalize(stmt);
-        return TCL_OK;
-    } else {
-        sqlite3_finalize(stmt);
-        set_sqlite_result(interp, db, query);
-        return TCL_ERROR;
-    }
-}
-
 const char* string_or_null(Tcl_Obj* obj) {
     const char* string = Tcl_GetString(obj);
     if (string[0] == '\0') {
@@ -254,15 +239,16 @@
     }
 }
 
-int recast(void* userdata, cast_function* fn, free_function* del, void*** outv,
-        void** inv, int inc, reg_error* errPtr) {
+int recast(void* userdata, cast_function* fn, void* castcalldata,
+        free_function* del, void*** outv, void** inv, int inc,
+        reg_error* errPtr) {
     void** result = malloc(inc*sizeof(void*));
     int i;
     if (!result) {
         return 0;
     }
     for (i=0; i<inc; i++) {
-        if (!fn(userdata, &result[i], inv[i], errPtr)) {
+        if (!fn(userdata, &result[i], inv[i], castcalldata, errPtr)) {
             if (del != NULL) {
                 for ( ; i>=0; i--) {
                     del(userdata, result[i]);
@@ -277,9 +263,9 @@
 }
 
 int entry_to_obj(Tcl_Interp* interp, Tcl_Obj** obj, reg_entry* entry,
-        reg_error* errPtr) {
+        int* lower_bound, reg_error* errPtr) {
     if (entry->proc == NULL) {
-        char* name = unique_name(interp, "::registry::entry");
+        char* name = unique_name(interp, "::registry::entry", lower_bound);
         if (!name) {
             return 0;
         }
@@ -293,26 +279,51 @@
     return 1;
 }
 
+int file_to_obj(Tcl_Interp* interp, Tcl_Obj** obj, reg_file* file,
+        int* lower_bound, reg_error* errPtr) {
+    if (file->proc == NULL) {
+        char* name = unique_name(interp, "::registry::file", lower_bound);
+        if (!name) {
+            return 0;
+        }
+        if (!set_file(interp, name, file, errPtr)) {
+            free(name);
+            return 0;
+        }
+        free(name);
+    }
+    *obj = Tcl_NewStringObj(file->proc, -1);
+    return 1;
+}
+
 int list_entry_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
         reg_entry** entries, int entry_count, reg_error* errPtr) {
-    return recast(interp, (cast_function*)entry_to_obj, NULL, (void***)objs,
-            (void**)entries, entry_count, errPtr);
+    int lower_bound = 0;
+    return recast(interp, (cast_function*)entry_to_obj, &lower_bound, NULL,
+            (void***)objs, (void**)entries, entry_count, errPtr);
 }
 
+int list_file_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
+        reg_file** files, int file_count, reg_error* errPtr) {
+    int lower_bound = 0;
+    return recast(interp, (cast_function*)file_to_obj, &lower_bound, NULL,
+            (void***)objs, (void**)files, file_count, errPtr);
+}
+
 static int obj_to_string(void* userdata UNUSED, char** string, Tcl_Obj* obj,
-        reg_error* errPtr UNUSED) {
+        void* param UNUSED, reg_error* errPtr UNUSED) {
     *string = Tcl_GetString(obj);
     return 1;
 }
 
 int list_obj_to_string(char*** strings, Tcl_Obj** objv, int objc,
         reg_error* errPtr) {
-    return recast(NULL, (cast_function*)obj_to_string, NULL, (void***)strings,
+    return recast(NULL, (cast_function*)obj_to_string, NULL, NULL, (void***)strings,
             (void**)objv, objc, errPtr);
 }
 
 static int string_to_obj(void* userdata UNUSED, Tcl_Obj** obj, char* string,
-        reg_error* errPtr UNUSED) {
+        void* param UNUSED, reg_error* errPtr UNUSED) {
     *obj = Tcl_NewStringObj(string, -1);
     return 1;
 }
@@ -323,6 +334,6 @@
 
 int list_string_to_obj(Tcl_Obj*** objv, char** strings, int objc,
         reg_error* errPtr) {
-    return recast(NULL, (cast_function*)string_to_obj, (free_function*)free_obj,
+    return recast(NULL, (cast_function*)string_to_obj, NULL, (free_function*)free_obj,
             (void***)objv, (void**)strings, objc, errPtr);
 }

Modified: trunk/base/src/registry2.0/util.h
===================================================================
--- trunk/base/src/registry2.0/util.h	2011-12-29 23:34:47 UTC (rev 88375)
+++ trunk/base/src/registry2.0/util.h	2011-12-30 00:17:49 UTC (rev 88376)
@@ -37,6 +37,7 @@
 
 #include <cregistry/registry.h>
 #include <cregistry/entry.h>
+#include <cregistry/file.h>
 
 typedef struct {
     char* option;
@@ -45,7 +46,7 @@
 
 #define END_FLAGS 0
 
-char* unique_name(Tcl_Interp* interp, char* prefix);
+char* unique_name(Tcl_Interp* interp, char* prefix, int* lower_bound);
 
 int parse_flags(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[], int* start,
         option_spec options[], int* flags);
@@ -56,23 +57,25 @@
         Tcl_ObjCmdProc* proc, Tcl_CmdDeleteProc* deleteProc, reg_error* errPtr);
 int set_entry(Tcl_Interp* interp, char* name, reg_entry* entry,
         reg_error* errPtr);
+int set_file(Tcl_Interp* interp, char* name, reg_file* file,
+        reg_error* errPtr);
 
 void set_sqlite_result(Tcl_Interp* interp, sqlite3* db, const char* query);
 
-typedef int set_object_function(Tcl_Interp* interp, char* name,
-        sqlite_int64 rowid);
-int all_objects(Tcl_Interp* interp, sqlite3* db, char* query, char* prefix,
-        set_object_function* setter);
-
 const char* string_or_null(Tcl_Obj* obj);
 
-int recast(void* userdata, cast_function* fn, free_function* del, void*** outv,
-        void** inv, int inc, reg_error* errPtr);
+int recast(void* userdata, cast_function* fn, void* castcalldata,
+        free_function* del, void*** outv, void** inv, int inc,
+        reg_error* errPtr);
 
 int entry_to_obj(Tcl_Interp* interp, Tcl_Obj** obj, reg_entry* entry,
-        reg_error* errPtr);
+        int* lower_bound, reg_error* errPtr);
 int list_entry_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
         reg_entry** entries, int entry_count, reg_error* errPtr);
+int file_to_obj(Tcl_Interp* interp, Tcl_Obj** ibj, reg_file* file,
+        int* lower_bound, reg_error* errPtr);
+int list_file_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
+        reg_file** files, int file_count, reg_error* errPtr);
 
 void free_strings(void* userdata UNUSED, char** strings, int count);
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macports-changes/attachments/20111229/70d9d928/attachment-0001.html>


More information about the macports-changes mailing list