[123747] branches/gsoc14-cleanup

ksammons at macports.org ksammons at macports.org
Wed Aug 13 15:14:51 PDT 2014


Revision: 123747
          https://trac.macports.org/changeset/123747
Author:   ksammons at macports.org
Date:     2014-08-13 15:14:51 -0700 (Wed, 13 Aug 2014)
Log Message:
-----------
Final (hopefully) changes

Added Paths:
-----------
    branches/gsoc14-cleanup/.DS_Store
    branches/gsoc14-cleanup/base/
    branches/gsoc14-cleanup/base/.DS_Store
    branches/gsoc14-cleanup/base/doc/
    branches/gsoc14-cleanup/base/doc/.DS_Store
    branches/gsoc14-cleanup/base/doc/exampleport/
    branches/gsoc14-cleanup/base/doc/exampleport/.DS_Store
    branches/gsoc14-cleanup/src/.DS_Store
    branches/gsoc14-cleanup/src/macports1.0/.DS_Store
    branches/gsoc14-cleanup/src/macports1.0/tests/.DS_Store
    branches/gsoc14-cleanup/src/port/port.BACKUP.23878
    branches/gsoc14-cleanup/src/port/port.BASE.23878
    branches/gsoc14-cleanup/src/port/port.LOCAL.23878
    branches/gsoc14-cleanup/src/port/port.REMOTE.23878
    branches/gsoc14-cleanup/src/port/port.orig
    branches/gsoc14-cleanup/src/port/port.tcl.orig

Added: branches/gsoc14-cleanup/.DS_Store
===================================================================
--- branches/gsoc14-cleanup/.DS_Store	                        (rev 0)
+++ branches/gsoc14-cleanup/.DS_Store	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,8 @@
+   Bud1                                                                 #       c a l . m 4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          @      \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              #   
+ a c l o c a l . m 4Ilocblob      F   (\xFF\xFF\xFF\xFF\xFF\xFF      b a s eIlocblob      \xCC   (   \xFF\xFF      b a s ebwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{355, 206}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    b a s evSrnlong      	 C h a n g e L o gIlocblob     R   (\xFF\xFF\xFF\xFF\xFF\xFF      c o n f i gIlocblob     \xD8   (\xFF\xFF\xFF\xFF\xFF\xFF      c o n f i g . g u e s sIlocblob     ^   (\xFF\xFF\xFF\xFF\xFF\xFF     
+ c o n f i g . l o gIlocblob     \xE4   (\xFF\xFF\xFF\xFF\xFF\xFF     
+ c o n f i g . s t a t u sIlocblob      F   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
+ c o n f i g . s u bIlocblob      \xCC   \x98\xFF\xFF\xFF\xFF\xFF\xFF     	 c o n f i g u r eIlocblob     R   \x98\xFF\xFF\xFF\xFF\xFF\xFF      c o n f i g u r e . a cIlocblob     \xD8   \x98\xFF\xFF\xFF\xFF\xFF\xFF      d o cIlocblob     ^   \x98\xFF\xFF\xFF\xFF\xFF\xFF      D o x y f i l eIlocblob     \xE4   \x98\xFF\xFF\xFF\xFF\xFF\xFF      D o x y f i l e . i nIlocblob      F  \xFF\xFF\xFF\xFF\xFF\xFF      H A C K I N GIlocblob      \xCC  \xFF\xFF\xFF\xFF\xFF\xFF     
+ i n s t a l l . s hIlocblob     R  \xFF\xFF\xFF\xFF\xFF\xFF      L I C E N S EIlocblob     \xD8  \xFF\xFF\xFF\xFF\xFF\xFF      m 4Ilocblob     ^  \xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s - p u b k e y . p e mIlocblob     \xE4  \xFF\xFF\xFF\xFF\xFF\xFF      M a k e f i l eIlocblob      F  x\xFF\xFF\xFF\xFF\xFF\xFF      M a k e f i l e . i nIlocblob      \xCC  x\xFF\xFF\xFF\xFF\xFF\xFF      M kIlocblob     R  x\xFF\xFF\xFF\xFF\xFF\xFF      N E W SIlocblob     \xD8  x\xFF\xFF\xFF\xFF\xFF\xFF      p o r t m g rIlocblob     ^  x\xFF\xFF\xFF\xFF\xFF\xFF     	 R E A D M E . m dIlocblob     \xE4  x\xFF\xFF\xFF\xFF\xFF\xFF      r e g e n . s hIlocblob      F  \xE8\xFF\xFF\xFF\xFF\xFF\xFF     
+ s e t u p e n v . b a s hIlocblob      \xCC  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      s e t u p e n v . b a s h . i nIlocblob     R  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      s r cIlocblob     \xD8  \xE8   \xFF\xFF      s r cbwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{355, 206}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    s r cvSrnlong       s t a n d a r d _ c o n f i g u r e . s hIlocblob     ^  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      t e s t sIlocblob     \xE4  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      v e n d o rIlocblob      F  X\xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           E                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         DSDB                                 `          \x80                          (      0          @      \x80                                          @      \x80                                          @             M kIlocblob     R  x\xFF\xFF\xFF\xFF\xFF\xFF      N E W SIlocblob     \xD8  x\xFF\xFF\xFF\xFF\xFF\xFF      p o r t m g rIlocblob     ^  x\xFF\xFF\xFF\xFF\xFF\xFF     	 R E A D M E . m dIlocblob     \xE4  x\xFF\xFF\xFF\xFF\xFF\xFF      r e g e n . s hIlocblob      F  \xE8\xFF\xFF\xFF\xFF\xFF\xFF     
+ s e t u p e n v . b a s hIlocblob      \xCC  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      s e t u p e n v . b a s h . i nIlocblob     R  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      s r cIlocblob     \xD8  \xE8   \xFF\xFF      s r cbwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{355, 206}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    s r cvSrnlong       s t a n d a r d _ c o n f i g u r e . s hIlocblob     ^  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      t e s t sIlocblob     \xE4  \xE8\xFF\xFF\xFF\xFF\xFF\xFF      v e                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
\ No newline at end of file

Added: branches/gsoc14-cleanup/base/.DS_Store
===================================================================
--- branches/gsoc14-cleanup/base/.DS_Store	                        (rev 0)
+++ branches/gsoc14-cleanup/base/.DS_Store	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,4 @@
+   Bud1                                                                      c a l . m 4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          @      \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
+ a c l o c a l . m 4Ilocblob      F   (\xFF\xFF\xFF\xFF\xFF\xFF     	 C h a n g e L o gIlocblob      \xCC   (\xFF\xFF\xFF\xFF\xFF\xFF      c o n f i gIlocblob     R   (\xFF\xFF\xFF\xFF\xFF\xFF      c o n f i g . g u e s sIlocblob     \xD8   (\xFF\xFF\xFF\xFF\xFF\xFF     
+ c o n f i g . s u bIlocblob     ^   (\xFF\xFF\xFF\xFF\xFF\xFF     	 c o n f i g u r eIlocblob     \xE4   (\xFF\xFF\xFF\xFF\xFF\xFF      c o n f i g u r e . a cIlocblob      F   \x98\xFF\xFF\xFF\xFF\xFF\xFF      d o cIlocblob      \xCC   \x98   \xFF\xFF      d o cbwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{335, 226}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    d o cvSrnlong       D o x y f i l e . i nIlocblob     R   \x98\xFF\xFF\xFF\xFF\xFF\xFF      H A C K I N GIlocblob     \xD8   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
+ i n s t a l l . s hIlocblob     ^   \x98\xFF\xFF\xFF\xFF\xFF\xFF      L I C E N S EIlocblob     \xE4   \x98\xFF\xFF\xFF\xFF\xFF\xFF      m 4Ilocblob      F  \xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s - p u b k e y . p e mIlocblob      \xCC  \xFF\xFF\xFF\xFF\xFF\xFF      M a k e f i l e . i nIlocblob     R  \xFF\xFF\xFF\xFF\xFF\xFF      M kIlocblob     \xD8  \xFF\xFF\xFF\xFF\xFF\xFF      N E W SIlocblob     ^  \xFF\xFF\xFF\xFF\xFF\xFF      p o r t m g rIlocblob     \xE4  \xFF\xFF\xFF\xFF\xFF\xFF      r e g e n . s hIlocblob      F  x\xFF\xFF\xFF\xFF\xFF\xFF      s e t u p e n v . b a s h . i nIlocblob      \xCC  x\xFF\xFF\xFF\xFF\xFF\xFF      s r cIlocblob     R  x\xFF\xFF\xFF\xFF\xFF\xFF      s t a n d a r d _ c o n f i g u r e . s hIlocblob     \xD8  x\xFF\xFF\xFF\xFF\xFF\xFF      t e s t sIlocblob     ^  x\xFF\xFF\xFF\xFF\xFF\xFF      v e n d o rIlocblob     \xE4  x\xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         E                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         DSDB                                 `          \x80                                        @      \x80                                          @      \x80                                          @       Ilocblob     R  x\xFF\xFF\xFF\xFF\xFF\xFF      s t a n d a r d _ c o n f i g u r e . s hIlocblob     \xD8  x\xFF\xFF\xFF\xFF\xFF\xFF      t e s t sIlocblob     ^  x\xFF\xFF\xFF\xFF\xFF\xFF      v e n d o rIlocblob     \xE4  x\xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
\ No newline at end of file

Added: branches/gsoc14-cleanup/base/doc/.DS_Store
===================================================================
--- branches/gsoc14-cleanup/base/doc/.DS_Store	                        (rev 0)
+++ branches/gsoc14-cleanup/base/doc/.DS_Store	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,5 @@
+   Bud1                                                                      i v e _ s i                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          @      \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  a r c h i v e _ s i t e s . c o n fIlocblob      F   (\xFF\xFF\xFF\xFF\xFF\xFF     
+ b a s e . m t r e e . i nIlocblob      \xCC   (\xFF\xFF\xFF\xFF\xFF\xFF      e x a m p l e p o r tIlocblob     R   (   \xFF\xFF      e x a m p l e p o r tbwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{335, 226}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    e x a m p l e p o r tvSrnlong      	 I N T E R N A L SIlocblob     \xD8   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c o s x . m t r e e . i nIlocblob     ^   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s . c o n f . 5Ilocblob     \xE4   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s . c o n f . i nIlocblob      F   \x98\xFF\xFF\xFF\xFF\xFF\xFF      M a k e f i l e . i nIlocblob      \xCC   \x98\xFF\xFF\xFF\xFF\xFF\xFF      p o r t . 1Ilocblob     R   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
+ p o r t f i l e . 7Ilocblob     \xD8   \x98\xFF\xFF\xFF\xFF\xFF\xFF      p o r t g r o u p . 7Ilocblob     ^   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
+ p o r t h i e r . 7Ilocblob     \xE4   \x98\xFF\xFF\xFF\xFF\xFF\xFF      p o r t s t y l e . 7Ilocblob      F  \xFF\xFF\xFF\xFF\xFF\xFF      p r e f i x . m t r e e . i nIlocblob      \xCC  \xFF\xFF\xFF\xFF\xFF\xFF      p u b k e y s . c o n f . i nIlocblob     R  \xFF\xFF\xFF\xFF\xFF\xFF      s o u r c e s . c o n fIlocblob     \xD8  \xFF\xFF\xFF\xFF\xFF\xFF     
+ v a r i a n t s . c o n fIlocblob     ^  \xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       E                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         DSDB                                 `          \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
\ No newline at end of file

Added: branches/gsoc14-cleanup/base/doc/exampleport/.DS_Store
===================================================================
--- branches/gsoc14-cleanup/base/doc/exampleport/.DS_Store	                        (rev 0)
+++ branches/gsoc14-cleanup/base/doc/exampleport/.DS_Store	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1 @@
+   Bud1            \x86                                                           f i l eIloc                                           P o r t f i l eIlocblob      F   (\xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    @      \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   E   \x86                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       DSDB                                 `      \xC0                                               @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
\ No newline at end of file

Added: branches/gsoc14-cleanup/src/.DS_Store
===================================================================
--- branches/gsoc14-cleanup/src/.DS_Store	                        (rev 0)
+++ branches/gsoc14-cleanup/src/.DS_Store	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,4 @@
+   Bud1                                                                      b 1 . 0Iloc                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          @      \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  c f l i b 1 . 0Ilocblob      F   (\xFF\xFF\xFF\xFF\xFF\xFF      c o n f i g . h . i nIlocblob      \xCC   (\xFF\xFF\xFF\xFF\xFF\xFF     	 c r e g i s t r yIlocblob     R   (\xFF\xFF\xFF\xFF\xFF\xFF      d a r w i n t r a c e l i b 1 . 0Ilocblob     \xD8   (\xFF\xFF\xFF\xFF\xFF\xFF      d e d u p _ p o r t f i l e s . t c l . i nIlocblob     ^   (\xFF\xFF\xFF\xFF\xFF\xFF      i m a g e s _ t o _ a r c h i v e s . t c l . i nIlocblob     \xE4   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c h i s t a 1 . 0Ilocblob      F   \x98\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s 1 . 0Ilocblob      \xCC   \x98   \xFF\xFF      m a c p o r t s 1 . 0bwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{355, 206}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    m a c p o r t s 1 . 0vSrnlong       M a k e f i l e . i nIlocblob     R   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
+ p a c k a g e 1 . 0Ilocblob     \xD8   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
+ p e x t l i b 1 . 0Ilocblob     ^   \x98\xFF\xFF\xFF\xFF\xFF\xFF      p k g _ m k i n d e x . s h . i nIlocblob     \xE4   \x98\xFF\xFF\xFF\xFF\xFF\xFF      p o r tIlocblob      F  \xFF\xFF\xFF\xFF\xFF\xFF      p o r t 1 . 0Ilocblob      \xCC  \xFF\xFF\xFF\xFF\xFF\xFF      p r o g r a m sIlocblob     R  \xFF\xFF\xFF\xFF\xFF\xFF      r e g i s t r y 2 . 0Ilocblob     \xD8  \xFF\xFF\xFF\xFF\xFF\xFF     
+ t c l o b j c 1 . 0Ilocblob     ^  \xFF\xFF\xFF\xFF\xFF\xFF     # u p g r a d e _ s o u r c e s _ c o n f _ d e f a u l t . t c l . i nIlocblob     \xE4  \xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   E                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         DSDB                                 `          \x80                                        @      \x80                                          @      \x80                                          @        s o u r c e s _ c o n f _ d e f a u l t . t c l . i nIlocblob     \xE4  \xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
\ No newline at end of file

Added: branches/gsoc14-cleanup/src/macports1.0/.DS_Store
===================================================================
--- branches/gsoc14-cleanup/src/macports1.0/.DS_Store	                        (rev 0)
+++ branches/gsoc14-cleanup/src/macports1.0/.DS_Store	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,3 @@
+   Bud1                                                                      o r . t c l                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          @      \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
+ d o c t o r . t c lIlocblob      F  x\xFF\xFF\xFF\xFF\xFF\xFF      d o c t o r . t c l . o r i gIlocblob      F   (\xFF\xFF\xFF\xFF\xFF\xFF     ! g e t _ s y s t e m c o n f i g u r a t i o n _ p r o x i e s . cIlocblob      \xCC   (\xFF\xFF\xFF\xFF\xFF\xFF     ! g e t _ s y s t e m c o n f i g u r a t i o n _ p r o x i e s . hIlocblob     R   (\xFF\xFF\xFF\xFF\xFF\xFF     
+ m a c p o r t s . cIlocblob      \xCC   \x98\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s . t c lIlocblob     R   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
 m a c p o r t s . t c l . B A C K U P . 2 1 7 2 2 . t c lIlocblob     \xD8   \x98\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s . t c l . B A S E . 2 1 7 2 2 . t c lIlocblob     ^   \x98\xFF\xFF\xFF\xFF\xFF\xFF     
 m a c p o r t s . t c l . L O C A L . 2 1 7 2 2 . t c lIlocblob     \xE4   \x98\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s . t c l . o r i gIlocblob      F  \xFF\xFF\xFF\xFF\xFF\xFF     
 m a c p o r t s . t c l . R E M O T E . 2 1 7 2 2 . t c lIlocblob      \xCC  \xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s _ a u t o c o n f . t c l . i nIlocblob     \xD8   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s _ d l i s t . t c lIlocblob     ^   (\xFF\xFF\xFF\xFF\xFF\xFF     
 m a c p o r t s _ t e s t _ a u t o c o n f . t c l . i nIlocblob     \xE4   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s _ u t i l . t c lIlocblob      F   \x98\xFF\xFF\xFF\xFF\xFF\xFF      M a k e f i l e . i nIlocblob     R  \xFF\xFF\xFF\xFF\xFF\xFF      r e c l a i m . t c lIlocblob      \xCC  x\xFF\xFF\xFF\xFF\xFF\xFF      s y s c t l . cIlocblob     \xD8  \xFF\xFF\xFF\xFF\xFF\xFF      s y s c t l . hIlocblob     ^  \xFF\xFF\xFF\xFF\xFF\xFF      t e s t sIlocblob     \xE4     \xFF\xFF      t e s t sbwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{355, 206}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    t e s t svSrnlong                                                                                                                                                                                                                                                                                                                                                                                                          E                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         DSDB                                 `          \x80                                        @      \x80                                          @      \x80                                          @       l . cIlocblob     \xD8  \xFF\xFF\xFF\xFF\xFF\xFF      s y s c t l . hIlocblob     ^  \xFF\xFF\xFF\xFF\xFF\xFF      t e s t sIlocblob     \xE4     \xFF\xFF      t e s t sbwspblob   \xDDbplist00\xD8			]ShowStatusBar[ShowPathbar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds\SidebarWidth[ShowSidebar		_{{355, 206}, {1010, 566}}\x97	'3?Kbo|\x88\x89\x8A\x8B\x8C\x8D\xA9\xAB                            \xAC    t e s t svSrnlong                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
\ No newline at end of file

Added: branches/gsoc14-cleanup/src/macports1.0/tests/.DS_Store
===================================================================
--- branches/gsoc14-cleanup/src/macports1.0/tests/.DS_Store	                        (rev 0)
+++ branches/gsoc14-cleanup/src/macports1.0/tests/.DS_Store	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,2 @@
+   Bud1           	                                                           a r y . t c                                                                                                                                                                                                                                                                                                                                                                                                                                           l i b r a r y . t c lIlocblob      F   (\xFF\xFF\xFF\xFF\xFF\xFF     
+ m a c p o r t s . t e s tIlocblob     \xD8   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s _ d l i s t . t e s tIlocblob      \xCC   (\xFF\xFF\xFF\xFF\xFF\xFF      m a c p o r t s _ u t i l . t e s tIlocblob     R   (\xFF\xFF\xFF\xFF\xFF\xFF      P o r t f i l eIlocblob     ^   (\xFF\xFF\xFF\xFF\xFF\xFF      s o u r c e s . c o n fIlocblob     \xE4   (\xFF\xFF\xFF\xFF\xFF\xFF      t e s t . t c lIlocblob      F   \x98\xFF\xFF\xFF\xFF\xFF\xFF                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  @      \x80                                        @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   E  	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       DSDB                                 `          \x80                                         @      \x80                                          @      \x80                                          @                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
\ No newline at end of file

Added: branches/gsoc14-cleanup/src/port/port.BACKUP.23878
===================================================================
--- branches/gsoc14-cleanup/src/port/port.BACKUP.23878	                        (rev 0)
+++ branches/gsoc14-cleanup/src/port/port.BACKUP.23878	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,5362 @@
+#!/opt/local/libexec/macports/bin/tclsh8.5
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
+# $Id: port.tcl 119177 2014-04-18 22:35:29Z cal at macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw <rshaw at opendarwin.org>
+# Copyright (c) 2002-2003 Apple Inc.
+# 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.
+# 3. Neither the name of Apple Inc. nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+# Create a namespace for some local variables
+namespace eval portclient::progress {
+    ##
+    # Indicate whether the term::ansi::send tcllib package is available and was
+    # imported. "yes", if the package is available, "no" otherwise.
+    variable hasTermAnsiSend no
+}
+
+if {![catch {package require term::ansi::send}]} {
+    set portclient::progress::hasTermAnsiSend yes
+}
+
+package require macports
+package require Pextlib 1.0
+
+# Standard procedures
+proc print_usage {{verbose 1}} {
+    global cmdname
+    set syntax {
+        [-bcdfknopqRstuvy] [-D portdir] [-F cmdfile] action [privopts] [actionflags]
+        [[portname|pseudo-portname|port-url] [@version] [+-variant]... [option=value]...]...
+    }
+
+    if {$verbose} {
+        puts stderr "Usage: $cmdname$syntax"
+        puts stderr "\"$cmdname help\" or \"man 1 port\" for more information."
+    } else {
+        puts stderr "$cmdname$syntax"
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds ""
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen > 65} {
+            set cmds "$cmds,\n"
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new "$cmd"
+        } else {
+            set new ", $cmd"
+        }
+        incr lineLen [string length $new]
+        set cmds "$cmds$new"
+    }
+
+    set cmdText "Supported actions
+------------------
+$cmds
+"
+
+    set text {
+Pseudo-portnames
+----------------
+Pseudo-portnames are words that may be used in place of a portname, and
+which expand to some set of ports. The common pseudo-portnames are:
+all, current, active, inactive, actinact, installed, uninstalled, outdated,
+obsolete, requested, unrequested and leaves.
+These pseudo-portnames expand to the set of ports named.
+
+Pseudo-portnames starting with variants:, variant:, description:, depends:,
+depends_lib:, depends_run:, depends_build:, depends_fetch:, depends_extract:,
+portdir:, homepage:, epoch:, platforms:, platform:, name:, long_description:,
+maintainers:, maintainer:, categories:, category:, version:, revision:, and
+license: each select a set of ports based on a regex search of metadata
+about the ports. In all such cases, a standard regex pattern following
+the colon will be used to select the set of ports to which the
+pseudo-portname expands.
+
+Pseudo-portnames starting with depof:, rdepof:, dependentof:, and rdependentof:
+select ports that are direct or recursive dependencies or dependents of the
+following portname, respectively.
+
+Portnames that contain standard glob characters will be expanded to the
+set of ports matching the glob pattern.
+    
+Port expressions
+----------------
+Portnames, port glob patterns, and pseudo-portnames may be logically
+combined using expressions consisting of and, or, not, !, (, and ).
+    
+For more information
+--------------------
+See man pages: port(1), macports.conf(5), portfile(7), portgroup(7),
+porthier(7), portstyle(7). Also, see http://www.macports.org.
+    }
+
+    puts "$cmdText$text"
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error "$argv0: $s"
+    exit 1
+}
+
+##
+# Helper function to define constants
+#
+# Constants defined with const can simply be accessed in the same way as
+# calling a proc.
+#
+# Example:
+# const FOO 42
+# puts [FOO]
+#
+# @param name variable name
+# @param value constant variable value
+proc const {name args} {
+    proc $name {} [list return [expr $args]]
+}
+
+# Format an integer representing bytes using given units
+proc bytesize {siz {unit {}} {format {%.3f}}} {
+    if {$unit == {}} {
+        if {$siz > 0x40000000} {
+            set unit "GiB"
+        } elseif {$siz > 0x100000} {
+            set unit "MiB"
+        } elseif {$siz > 0x400} {
+            set unit "KiB"
+        } else {
+            set unit "B"
+        }
+    }
+    switch -- $unit {
+        KiB {
+            set siz [expr {$siz / 1024.0}]
+        }
+        kB {
+            set siz [expr {$siz / 1000.0}]
+        }
+        MiB {
+            set siz [expr {$siz / 1048576.0}]
+        }
+        MB {
+            set siz [expr {$siz / 1000000.0}]
+        }
+        GiB {
+            set siz [expr {$siz / 1073741824.0}]
+        }
+        GB {
+            set siz [expr {$siz / 1000000000.0}]
+        }
+        B { }
+        default {
+            ui_warn "Unknown file size unit '$unit' specified"
+            set unit "B"
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return "$siz $unit"
+}
+
+proc filesize {fil {unit {}}} {
+    set siz {@}
+    catch {
+        set siz [bytesize [file size $fil] $unit]
+    }
+    return $siz
+}
+
+# Produce an error message, and exit, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc fatal_softcontinue s {
+    if {[macports::global_option_isset ports_force]} {
+        ui_error $s
+        return -code continue
+    } else {
+        fatal $s
+    }
+}
+
+
+# Produce an error message, and break, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc break_softcontinue { msg status name_status } {
+    upvar $name_status status_var 
+    ui_error $msg
+    if {[macports::ui_isset ports_processall]} {
+        set status_var 0
+        return -code continue
+    } else {
+        set status_var $status
+        return -code break
+    }
+}
+
+# show the URL for the ticket reporting instructions
+proc print_tickets_url {args} {
+    if {${macports::prefix} ne "/usr/local" && ${macports::prefix} ne "/usr"} {
+        ui_error "Follow http://guide.macports.org/#project.tickets to report a bug."
+    }
+}
+
+# Form a composite version as is sometimes used for registry functions
+# This function sorts the variants and presents them in a canonical representation
+proc composite_version {version variations {emptyVersionOkay 0}} {
+    # Form a composite version out of the version and variations
+    
+    # Select the variations into positive and negative
+    set pos {}
+    set neg {}
+    foreach { key val } $variations {
+        if {$val eq "+"} {
+            lappend pos $key
+        } elseif {$val eq "-"} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version ""
+    if {$version ne "" || $emptyVersionOkay} {
+        set pos_str ""
+        set neg_str ""
+
+        if {[llength $pos]} {
+            set pos_str "+[join [lsort -ascii $pos] "+"]"
+        }
+        if {[llength $neg]} {
+            set neg_str "-[join [lsort -ascii $neg] "-"]"
+        }
+
+        set composite_version "$version$pos_str$neg_str"
+    }
+
+    return $composite_version
+}
+
+
+proc split_variants {variants} {
+    set result {}
+    set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
+    foreach { match sign variant } $l {
+        lappend result $variant $sign
+    }
+    return $result
+}
+
+
+##
+# Maps friendly field names to their real name
+# Names which do not need mapping are not changed.
+#
+# @param field friendly name
+# @return real name
+proc map_friendly_field_names { field } {
+    switch -- $field {
+        variant -
+        platform -
+        maintainer -
+        subport {
+            set field "${field}s"
+        }
+        category {
+            set field "categories"
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion ""}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] > 1 } {
+        # set portname again since the one we were passed may not have had the correct case
+        set portname [lindex $ilist 0 0]
+        ui_notice "The following versions of $portname are currently installed:"
+        foreach i [portlist_sortint $ilist] { 
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants} (active)"
+            }
+        }
+        return -code error "Registry error: Please specify the full version as recorded in the port registry."
+    } else {
+        return [lindex $ilist 0]
+    }
+}
+
+
+proc entry_for_portlist {portentry} {
+    global global_options global_variations
+
+    # Each portlist entry currently has the following elements in it:
+    #   url             if any
+    #   name
+    #   version         (version_revision)
+    #   variants array  (variant=>+-)
+    #   requested_variants array  (variant=>+-)
+    #   options array   (key=>value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) "" }
+    if {![info exists port(name)]}      { set port(name) "" }
+    if {![info exists port(version)]}   { set port(version) "" }
+    if {![info exists port(variants)]}  { set port(variants) "" }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) "" }
+    if {![info exists port(options)]}   { set port(options) [array get global_options] }
+
+    # If neither portname nor url is specified, then default to the current port
+    if { $port(url) eq "" && $port(name) eq "" } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq ""} {
+            ui_error "A default port name could not be supplied."
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) "$port(name)/[composite_version $port(version) $port(variants)]"
+    
+    return [array get port]
+}
+
+
+proc add_to_portlist {listname portentry} {
+    upvar $listname portlist
+    
+    # Form portlist entry and add to portlist
+    lappend portlist [entry_for_portlist $portentry]
+}
+
+
+proc add_ports_to_portlist {listname ports {overridelist ""}} {
+    upvar $listname portlist
+
+    array set overrides $overridelist
+
+    # Add each entry to the named portlist, overriding any values
+    # specified as overrides
+    foreach portentry $ports {
+        array set port $portentry
+        if ([info exists overrides(version)])   { set port(version) $overrides(version) }
+        if ([info exists overrides(variants)])  { set port(variants) $overrides(variants) }
+        if ([info exists overrides(requested_variants)])  { set port(requested_variants) $overrides(requested_variants) }
+        if ([info exists overrides(options)])   { set port(options) $overrides(options) }
+        add_to_portlist portlist [array get port]
+    }
+}
+
+
+proc url_to_portname { url {quiet 0} } {
+    # Save directory and restore the directory, since mportopen changes it
+    set savedir [pwd]
+    set portname ""
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg "Can't map the URL '$url' to a port description file (\"${result}\")."
+            ui_msg "Please verify that the directory and portfile syntax are correct."
+        }
+    } else {
+        array set portinfo [mportinfo $ctx]
+        set portname $portinfo(name)
+        mportclose $ctx
+    }
+    cd $savedir
+    return $portname
+}
+
+
+# Supply a default porturl/portname if the portlist is empty
+proc require_portlist { nameportlist {is_upgrade "no"} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 && (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        if {${is_upgrade} == "yes"} {
+            # $> port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # "upgrade", let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg "Nothing to upgrade."
+            return 1
+        }
+        ui_error "No ports matched the given expression"
+        return 1
+    }
+
+    if {[llength $portlist] == 0} {
+        set portlist [get_current_port]
+
+        if {[llength $portlist] == 0} {
+            # there was no port in current directory
+            return 1
+        }
+    }
+
+    return 0
+}
+
+
+# Execute the enclosed block once for every element in the portlist
+# When the block is entered, the following variables will have been set:
+#   portspec, porturl, portname, portversion, options, variations, requested_variations
+proc foreachport {portlist block} {
+    set savedir [pwd]
+    foreach portspec $portlist {
+    
+        # Set the variables for the block
+        uplevel 1 "array unset portspec; array set portspec { $portspec }"
+        uplevel 1 {
+            set porturl $portspec(url)
+            set portname $portspec(name)
+            set portversion $portspec(version)
+            array unset variations
+            array set variations $portspec(variants)
+            array unset requested_variations
+            array set requested_variations $portspec(requested_variants)
+            array unset options
+            array set options $portspec(options)
+        }
+        
+        # Invoke block
+        uplevel 1 $block
+        
+        # Restore cwd after each port, since mportopen changes it, and otherwise relative
+        # urls would break on subsequent passes
+        if {[file exists $savedir]} {
+            cd $savedir
+        } else {
+            cd ~
+        }
+    }
+}
+
+
+proc portlist_compare { a b } {
+    array set a_ $a
+    array set b_ $b
+    set namecmp [string equal -nocase $a_(name) $b_(name)]
+    if {$namecmp != 1} {
+        if {$a_(name) eq [lindex [lsort -dictionary [list $a_(name) $b_(name)]] 0]} {
+            return -1
+        }
+        return 1
+    }
+    set avr_ [split $a_(version) "_"]
+    set bvr_ [split $b_(version) "_"]
+    set versioncmp [vercmp [lindex $avr_ 0] [lindex $bvr_ 0]]
+    if {$versioncmp != 0} {
+        return $versioncmp
+    }
+    set ar_ [lindex $avr_ 1]
+    set br_ [lindex $bvr_ 1]
+    if {$ar_ < $br_} {
+        return -1
+    } elseif {$ar_ > $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name at version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list "name" [lindex $a 0] "version" "[lindex $a 1]_[lindex $a 2]"]
+    array set b_ [list "name" [lindex $b 0] "version" "[lindex $b 1]_[lindex $b 2]"]
+    return [portlist_compare [array get a_] [array get b_]]
+}
+
+# Same as portlist_sort, but with numeric indexes {name version revision}
+proc portlist_sortint { list } {
+    return [lsort -command portlist_compareint $list]
+}
+
+# sort portlist so dependents come before their dependencies
+proc portlist_sortdependents { portlist } {
+    foreach p $portlist {
+        array set pvals $p
+        lappend entries($pvals(name)) $p
+        if {![info exists dependents($pvals(name))]} {
+            set dependents($pvals(name)) {}
+            foreach result [registry::list_dependents $pvals(name)] {
+                lappend dependents($pvals(name)) [lindex $result 2]
+            }
+        }
+        array unset pvals
+    }
+    set ret {}
+    foreach p $portlist {
+        portlist_sortdependents_helper $p entries dependents seen ret
+    }
+    return $ret
+}
+
+proc portlist_sortdependents_helper {p up_entries up_dependents up_seen up_retlist} {
+    upvar $up_seen seen
+    if {![info exists seen($p)]} {
+        set seen($p) 1
+        upvar $up_entries entries $up_dependents dependents $up_retlist retlist
+        array set pvals $p
+        foreach dependent $dependents($pvals(name)) {
+            if {[info exists entries($dependent)]} {
+                foreach entry $entries($dependent) {
+                    portlist_sortdependents_helper $entry entries dependents seen retlist
+                }
+            }
+        }
+        lappend retlist $p
+    }
+}
+
+proc regex_pat_sanitize { s } {
+    set sanitized [regsub -all {[\\(){}+$.^]} $s {\\&}]
+    return $sanitized
+}
+
+##
+# Makes sure we get the current terminal size
+proc term_init_size {} {
+    global env
+
+    if {![info exists env(COLUMNS)] || ![info exists env(LINES)]} {
+        if {[isatty stdout]} {
+            set size [term_get_size stdout]
+
+            if {![info exists env(LINES)] && [lindex $size 0] > 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] && [lindex $size 1] > 0} {
+                set env(COLUMNS) [lindex $size 1]
+            }
+        }
+    }
+}
+
+##
+# Wraps a multi-line string at specified textwidth
+#
+# @see wrapline
+#
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrap {string maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set splitstring {}
+    set indentline $indentfirstline
+    foreach line [split $string "\n"] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring "\n"]
+}
+
+##
+# Wraps a line at specified textwidth
+#
+# @see wrap
+#
+# @param line input line
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrapline {line maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set string [split $line " "]
+    if {$indentfirstline == 0} {
+        set newline ""
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner " "
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] >= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner ""
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 && $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner " "
+    }
+    lappend lines $newline
+    return [join $lines "\n"]
+}
+
+##
+# Wraps a line at a specified width with a label in front
+#
+# @see wrap
+#
+# @param label label for output
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @return wrapped string
+proc wraplabel {label string maxlen {indent ""}} {
+    append label ": [string repeat " " [expr {[string length $indent] - [string length "$label: "]}]]"
+    return "$label[wrap $string $maxlen $indent 0]"
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first "@" $m] < 0} {
+            if {[string first ":" $m] >= 0} {
+                set m [regsub -- "(.*):(.*)" $m "\\2@\\1"] 
+            } else {
+                set m "$m at macports.org"
+            }
+        }
+        lappend result $m
+    }
+    return $result
+}
+
+
+##########################################
+# Port selection
+##########################################
+proc unique_results_to_portlist {infos} {
+    set result {}
+    array unset unique
+    foreach {name info} $infos {
+        array unset portinfo
+        array set portinfo $info
+        
+        set portentry [entry_for_portlist [list url $portinfo(porturl) name $name]]
+        
+        array unset entry
+        array set entry $portentry
+        
+        if {[info exists unique($entry(fullname))]} continue
+        set unique($entry(fullname)) 1
+        
+        lappend result $portentry
+    }
+    return $result
+}
+
+
+proc get_matching_ports {pattern {casesensitive no} {matchstyle glob} {field name}} {
+    if {[catch {set res [mportsearch $pattern $casesensitive $matchstyle $field]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        fatal "search for portname $pattern failed: $result"
+    }
+    set results [unique_results_to_portlist $res]
+    
+    # Return the list of all ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_all_ports {} {
+    global all_ports_cache
+
+    if {![info exists all_ports_cache]} {
+         if {[catch {set res [mportlistall]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "listing all ports failed: $result"
+        }
+        set results [unique_results_to_portlist $res]
+        set all_ports_cache [portlist_sort $results]
+    }
+    return $all_ports_cache
+}
+
+
+proc get_current_ports {} {
+    # This is just a synonym for get_current_port that
+    # works with the regex in element
+    return [get_current_port]
+}
+
+
+proc get_current_port {} {
+    set url file://.
+    set portname [url_to_portname $url]
+    if {$portname eq ""} {
+        ui_msg "To use the current port, you must be in a port's directory."
+        return [list]
+    }
+
+    set results {}
+    add_to_portlist results [list url $url name $portname]
+    return $results
+}
+
+
+proc get_installed_ports { {ignore_active yes} {active yes} } {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [split_variants [lindex $i 3]]
+        set iactive [lindex $i 4]
+
+        if { ${ignore_active} == "yes" || (${active} == "yes") == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants $ivariants]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_uninstalled_ports {} {
+    # Return all - installed
+    set all [get_all_ports]
+    set installed [get_installed_ports]
+    return [opComplement $all $installed]
+}
+
+
+proc get_active_ports {} {
+    return [get_installed_ports no yes]
+}
+
+
+proc get_inactive_ports {} {
+    return [get_installed_ports no no]
+}
+
+proc get_actinact_ports {} {
+    set inactive_ports [get_inactive_ports]
+    set active_ports [get_active_ports]
+    set results {}
+
+    foreach port $inactive_ports {
+        array set portspec $port
+        set portname $portspec(name)
+        lappend inact($portname) $port
+    }
+
+    foreach port $active_ports {
+        array set portspec $port
+        set portname $portspec(name)
+
+        if {[info exists inact($portname)]} {
+            if {![info exists added_inact($portname)]} {
+                foreach inact_spec $inact($portname) {
+                    lappend results $inact_spec
+                }
+                set added_inact($portname) 1
+            }
+            lappend results $port
+        }
+    }
+    return $results
+}
+
+
+proc get_outdated_ports {} {
+    # Get the list of installed ports
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] > 0 } {
+        foreach i $ilist {
+
+            # Get information about the installed port
+            set portname            [lindex $i 0]
+            set installed_version   [lindex $i 1]
+            set installed_revision  [lindex $i 2]
+            set installed_compound  "${installed_version}_${installed_revision}"
+            set installed_variants  [lindex $i 3]
+
+            set is_active           [lindex $i 4]
+            if {$is_active == 0} continue
+
+            set installed_epoch     [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                fatal "lookup of portname $portname failed: $result"
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+
+            # Get information about latest available version and revision
+            set latest_version $portinfo(version)
+            set latest_revision     0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     "${latest_version}_${latest_revision}"
+            set latest_epoch        0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch    $portinfo(epoch)
+            }
+
+            # Compare versions, first checking epoch, then version, then revision
+            set comp_result 0
+            if {$installed_version != $latest_version} {
+                set comp_result [expr {$installed_epoch - $latest_epoch}]
+                if { $comp_result == 0 } {
+                    set comp_result [vercmp $installed_version $latest_version]
+                }
+            }
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            if {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision $installed_variants $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                }
+            }
+
+            # Add outdated ports to our results list
+            if { $comp_result < 0 } {
+                add_to_portlist results [list name $portname version $installed_compound variants [split_variants $installed_variants]]
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_obsolete_ports {} {
+    set ilist [get_installed_ports]
+    set results {}
+
+    foreach i $ilist {
+        array set port $i
+
+        if {[catch {mportlookup $port(name)} result]} {
+            ui_debug "$::errorInfo"
+            break_softcontinue "lookup of portname $portname failed: $result" 1 status
+        }
+
+        if {[llength $result] < 2} {
+            lappend results $i
+        }
+    }
+
+    # Return the list of ports, already sorted
+    return [portlist_sort $results]
+}
+
+# return ports that have registry property $propname set to $propval
+proc get_ports_with_prop {propname propval} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [lindex $i 3]
+        set iepoch [lindex $i 5]
+        set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
+        if {[registry::property_retrieve $regref $propname] == $propval} {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants [split_variants $ivariants]]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+proc get_requested_ports {} {
+    return [get_ports_with_prop requested 1]
+}
+
+proc get_unrequested_ports {} {
+    return [get_ports_with_prop requested 0]
+}
+
+proc get_leaves_ports {} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq ""} {
+            add_to_portlist results [list name $iname version "[lindex $i 1]_[lindex $i 2]" variants [split_variants [lindex $i 3]]]
+        }
+    }
+    return [portlist_sort [opIntersection $results [get_unrequested_ports]]]
+}
+
+proc get_dependent_ports {portname recursive} {
+    registry::open_dep_map
+    set deplist [registry::list_dependents $portname]
+    # could return specific versions here using registry2.0 features
+    set results {}
+    foreach dep $deplist {
+        add_to_portlist results [list name [lindex $dep 2]]
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex $dep 2]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    set rdeplist [registry::list_dependents $depname]
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex $rdep 2]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_dep_ports {portname recursive} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its deps
+    set results {}
+    set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+
+    set deplist {}
+    foreach type $deptypes {
+        if {[info exists portinfo($type)]} {
+            foreach dep $portinfo($type) {
+                add_to_portlist results [list name [lindex [split $dep :] end]]
+                lappend deplist $dep
+            }
+        }
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        return -code error "lookup of portname $depname failed: $result"
+                    }
+                    if {[llength $result] < 2} {
+                        ui_error "Port $depname not found"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                
+                    # open its portfile
+                    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+                        ui_debug "$::errorInfo"
+                        ui_error "Unable to open port: $result"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [mportinfo $mport]
+                    mportclose $mport
+
+                    # collect its deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                add_to_portlist results [list name [lindex [split $rdep :] end]]
+                                lappend rdeplist $rdep
+                            }
+                        }
+                    }
+
+                    # add them to the lists
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex [split $rdep :] end]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+proc get_subports {portname} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its subports
+    set results {}
+
+    if {[info exists portinfo(subports)]} {
+        foreach subport $portinfo(subports) {
+            add_to_portlist results [list name $subport]
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+##########################################
+# Port expressions
+##########################################
+proc portExpr { resname } {
+    upvar $resname reslist
+    set result [seqExpr reslist]
+    return $result
+}
+
+
+proc seqExpr { resname } {
+    upvar $resname reslist
+    
+    # Evaluate a sequence of expressions a b c...
+    # These act the same as a or b or c
+
+    set result 1
+    while {$result} {
+        switch -- [lookahead] {
+            ;       -
+            )       -
+            _EOF_   { break }
+        }
+
+        set blist {}
+        set result [orExpr blist]
+        if {$result} {
+            # Calculate the union of result and b
+            set reslist [opUnion $reslist $blist]
+        }
+    }
+    
+    return $result
+}
+
+
+proc orExpr { resname } {
+    upvar $resname reslist
+    
+    set a [andExpr reslist]
+    while ($a) {
+        switch -- [lookahead] {
+            or {
+                    advance
+                    set blist {}
+                    if {![andExpr blist]} {
+                        return 0
+                    }
+                        
+                    # Calculate a union b
+                    set reslist [opUnion $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc andExpr { resname } {
+    upvar $resname reslist
+    
+    set a [unaryExpr reslist]
+    while {$a} {
+        switch -- [lookahead] {
+            and {
+                    advance
+                    
+                    set blist {}
+                    set b [unaryExpr blist]
+                    if {!$b} {
+                        return 0
+                    }
+                    
+                    # Calculate a intersect b
+                    set reslist [opIntersection $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc unaryExpr { resname } {
+    upvar $resname reslist
+    set result 0
+
+    switch -- [lookahead] {
+        !   -
+        not {
+                advance
+                set blist {}
+                set result [unaryExpr blist]
+                if {$result} {
+                    set all [get_all_ports]
+                    set reslist [opComplement $all $blist]
+                }
+            }
+        default {
+                set result [element reslist]
+            }
+    }
+    
+    return $result
+}
+
+
+proc element { resname } {
+    upvar $resname reslist
+    set el 0
+    
+    set url ""
+    set name ""
+    set version ""
+    array unset requested_variants
+    array unset options
+    
+    set token [lookahead]
+    switch -regex -- $token {
+        ^\\)$               -
+        ^\;                 -
+        ^_EOF_$             { # End of expression/cmd/file
+        }
+
+        ^\\($               { # Parenthesized Expression
+            advance
+            set el [portExpr reslist]
+            if {!$el || ![match ")"]} {
+                set el 0
+            }
+        }
+
+        ^all(@.*)?$         -
+        ^installed(@.*)?$   -
+        ^uninstalled(@.*)?$ -
+        ^active(@.*)?$      -
+        ^inactive(@.*)?$    -
+        ^actinact(@.*)?$    -
+        ^leaves(@.*)?$      -
+        ^outdated(@.*)?$    -
+        ^obsolete(@.*)?$    -
+        ^requested(@.*)?$   -
+        ^unrequested(@.*)?$ -
+        ^current(@.*)?$     {
+            # A simple pseudo-port name
+            advance
+
+            # Break off the version component, if there is one
+            regexp {^(\w+)(@.*)?} $token matchvar name remainder
+
+            add_multiple_ports reslist [get_${name}_ports] $remainder
+
+            set el 1
+        }
+
+        ^variants:          -
+        ^variant:           -
+        ^description:       -
+        ^portdir:           -
+        ^homepage:          -
+        ^epoch:             -
+        ^platforms:         -
+        ^platform:          -
+        ^name:              -
+        ^long_description:  -
+        ^maintainers:       -
+        ^maintainer:        -
+        ^categories:        -
+        ^category:          -
+        ^version:           -
+        ^depends_lib:       -
+        ^depends_build:     -
+        ^depends_run:       -
+        ^depends_extract:   -
+        ^depends_fetch:     -
+        ^replaced_by:       -
+        ^revision:          -
+        ^subport:           -
+        ^subports:          -
+        ^license:           { # Handle special port selectors
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            # Remap friendly names to actual names
+            set field [map_friendly_field_names $field]
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp $field]
+            set el 1
+        }
+
+        ^depends:           { # A port selector shorthand for depends_{lib,build,run,fetch,extract}
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_lib"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_build"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_run"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_extract"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_fetch"]
+
+            set el 1
+        }
+
+        ^dependentof:       -
+        ^rdependentof:      {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdependentof"]
+            add_multiple_ports reslist [get_dependent_ports $portname $recursive]
+            
+            set el 1
+        }
+        
+        ^depof:             -
+        ^rdepof:            {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdepof"]
+            add_multiple_ports reslist [get_dep_ports $portname $recursive]
+            
+            set el 1
+        }
+
+        ^subportof:         {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            add_multiple_ports reslist [get_subports $portname]
+
+            set el 1
+        }
+
+        [][?*]              { # Handle portname glob patterns
+            advance; add_multiple_ports reslist [get_matching_ports $token no glob]
+            set el 1
+        }
+
+        ^\\w+:.+            { # Handle a url by trying to open it as a port and mapping the name
+            advance
+            set name [url_to_portname $token]
+            if {$name ne ""} {
+                parsePortSpec version requested_variants options
+                add_to_portlist reslist [list url $token \
+                  name $name \
+                  version $version \
+                  requested_variants [array get requested_variants] \
+                  variants [array get requested_variants] \
+                  options [array get options]]
+                set el 1
+            } else {
+                ui_error "Can't open URL '$token' as a port"
+                set el 0
+            }
+        }
+
+        default             { # Treat anything else as a portspec (portname, version, variants, options
+            # or some combination thereof).
+            parseFullPortSpec url name version requested_variants options
+            add_to_portlist reslist [list url $url \
+              name $name \
+              version $version \
+              requested_variants [array get requested_variants] \
+              variants [array get requested_variants] \
+              options [array get options]]
+            set el 1
+        }
+    }
+
+    return $el
+}
+
+
+proc add_multiple_ports { resname ports {remainder ""} } {
+    upvar $resname reslist
+    
+    set version ""
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne ""} { set overrides(version) $version }
+    if {[array size variants]} {
+        # we always record the requested variants separately,
+        # but requested ones always override existing ones
+        set overrides(requested_variants) [array get variants]
+        set overrides(variants) [array get variants]
+    }
+    if {[array size options]} { set overrides(options) [array get options] }
+
+    add_ports_to_portlist reslist $ports [array get overrides]
+}
+
+
+proc unique_entries { entries } {
+    # Form the list of all the unique elements in the list a,
+    # considering only the port fullname, and taking the first
+    # found element first
+    set result {}
+    array unset unique
+    foreach item $entries {
+        array set port $item
+        if {[info exists unique($port(fullname))]} continue
+        set unique($port(fullname)) 1
+        lappend result $item
+    }
+    return $result
+}
+
+
+proc opUnion { a b } {
+    # Return the unique elements in the combined two lists
+    return [unique_entries [concat $a $b]]
+}
+
+
+proc opIntersection { a b } {
+    set result {}
+    
+    # Rules we follow in performing the intersection of two port lists:
+    #
+    #   a/, a/          ==> a/
+    #   a/, b/          ==>
+    #   a/, a/1.0       ==> a/1.0
+    #   a/1.0, a/       ==> a/1.0
+    #   a/1.0, a/2.0    ==>
+    #
+    #   If there's an exact match, we take it.
+    #   If there's a match between simple and discriminated, we take the later.
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem [unique_entries $b] {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, matching against b
+    foreach aitem [unique_entries $a] {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+        foreach match $matches {
+            if {$simpleform} {
+                set i $bfull($match)
+                lappend result [lindex $b $i]
+            } else {
+                lappend result $aitem
+            }
+        }
+    }
+    
+    return $result
+}
+
+
+proc opComplement { a b } {
+    set result {}
+    
+    # Return all elements of a not matching elements in b
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem $b {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, taking all those items that don't match b
+    foreach aitem $a {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+
+        # We copy this element to result only if it didn't match against b
+        if {![llength $matches]} {
+            lappend result $aitem
+        }
+    }
+    
+    return $result
+}
+
+
+proc parseFullPortSpec { urlname namename vername varname optname } {
+    upvar $urlname porturl
+    upvar $namename portname
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    set portname ""
+    set portversion ""
+    array unset portvariants
+    array unset portoptions
+    
+    if { [moreargs] } {
+        # Look first for a potential portname
+        #
+        # We need to allow a wide variety of tokens here, because of actions like "provides"
+        # so we take a rather lenient view of what a "portname" is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder ""
+        if {![regexp {^(@|[-+]([[:alpha:]_]+[\w\.]*)|[[:alpha:]_]+[\w\.]*=)} $token match]} {
+            advance
+            regexp {^([^@]+)(@.*)?} $token match portname remainder
+            
+            # If the portname contains a /, then try to use it as a URL
+            if {[string match "*/*" $portname]} {
+                set url "file://$portname"
+                set name [url_to_portname $url 1]
+                if { $name ne "" } {
+                    # We mapped the url to valid port
+                    set porturl $url
+                    set portname $name
+                    # Continue to parse rest of portspec....
+                } else {
+                    # We didn't map the url to a port; treat it
+                    # as a raw string for something like port contents
+                    # or cd
+                    set porturl ""
+                    # Since this isn't a port, we don't try to parse
+                    # any remaining portspec....
+                    return
+                }
+            }
+        }
+        
+        # Now parse the rest of the spec
+        parsePortSpec portversion portvariants portoptions $remainder
+    }
+}
+
+# check if the install prefix is writable
+# should be called by actions that will modify it
+proc prefix_unwritable {} {
+    global macports::portdbpath
+    if {[file writable $portdbpath]} {
+        return 0
+    } else {
+        ui_error "Insufficient privileges to write to MacPorts install prefix."
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder ""} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion ""
+    array unset portoptions
+    array set portoptions [array get global_options]
+    array unset portvariants
+    
+    # Parse port version/variants/options
+    set opt $remainder
+    set adv 0
+    set consumed 0
+    for {set firstTime 1} {$opt ne "" || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq ""} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime && [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first "/" $opt]
+            if {$sepPos >= 0} {
+                # Version terminated by "/" to disambiguate -variant from part of version
+                set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                set opt [string range $opt [expr {$sepPos + 1}] end]
+            } else {
+                # Version terminated by "+", or else is complete
+                set sepPos [string first "+" $opt]
+                if {$sepPos >= 0} {
+                    # Version terminated by "+"
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt ""
+                }
+            }
+            set consumed 1
+        } else {
+            # Parse all other options
+            
+            # Look first for a variable setting: VARNAME=VALUE
+            if {[regexp {^([[:alpha:]_]+[\w\.]*)=(.*)} $opt match key val] == 1} {
+                # It's a variable setting
+                set portoptions($key) "\"$val\""
+                set opt ""
+                set consumed 1
+            } elseif {[regexp {^([-+])([[:alpha:]_]+[\w\.]*)} $opt match sign variant] == 1} {
+                # It's a variant
+                set portvariants($variant) $sign
+                set opt [string range $opt [expr {[string length $variant] + 1}] end]
+                set consumed 1
+            } else {
+                # Not an option we recognize, so break from port option processing
+                if { $consumed && $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds ""
+        if {[info exists cmd_opts_array($action)]} {
+            foreach opt $cmd_opts_array($action) {
+                if {[llength $opt] == 1} {
+                    set name $opt
+                    set optc 0
+                } else {
+                    set name [lindex $opt 0]
+                    set optc [lindex $opt 1]
+                }
+
+                append cmds " --$name"
+
+                for {set i 1} {$i <= $optc} {incr i} {
+                    append cmds " <arg$i>"
+                }
+            }
+        }
+        set args ""
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <arguments>"
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <portlist>"
+        }
+
+        set ret "Usage: "
+        set len [string length $action]
+        append ret [wrap "$action$cmds$args" 0 [string repeat " " [expr {8 + $len}]] 0]
+        append ret "\n"
+
+        return $ret
+    }
+
+    return -1
+}
+
+proc action_usage { action portlist opts } {
+    if {[llength $portlist] == 0} {
+        print_usage
+        return 0
+    }
+
+    foreach topic $portlist {
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile "$macports::prefix/var/macports/port-help.tcl"
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr "Error reading helpfile $helpfile: $err"
+            return 1
+        }
+    } else {
+        puts stderr "Unable to open help file $helpfile"
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr "No help for topic $topic"
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+
+        puts stderr $porthelp($topic)
+    }
+
+    return 0
+}
+
+
+proc action_log { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array unset portinfo
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+            set portname $portinfo(name)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            array unset portinfo
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] "main.log"]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue "Could not open file $logfile: $result" 1 status
+            }
+            set data [read $fp]
+            set data [split $data "\n"]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase "\[a-z\]*"
+            }
+
+            if {[info exists global_options(ports_log_level)]} {
+                set index [lsearch -exact ${macports::ui_priorities} $global_options(ports_log_level)]
+                if {$index == -1} {
+                    set prefix ""
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] "|"]
+                }
+            } else {
+                set prefix "\[a-z\]*"
+            }
+            foreach line $data {
+                set exp "^:($prefix|any):($phase|any) (.*)$"
+                if {[regexp $exp $line -> lpriority lphase lmsg] == 1} {
+                    puts "[macports::ui_prefix_default $lpriority]$lmsg"
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue "Log file for port $portname not found" 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator ""
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] && $options(ports_info_index)} {
+            set index_only 1
+        }
+        puts -nonewline $separator
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq "" || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!$index_only} {
+            # Add any global_variations to the variations
+            # specified for the port (so we get e.g. dependencies right)
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+ 
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            unset options(subport)
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "no PortIndex entry found for $portname"
+            continue
+        }
+        array unset options ports_info_index
+
+        # Understand which info items are actually lists
+        # (this could be overloaded to provide a generic formatting code to
+        # allow us to, say, split off the prefix on libs)
+        array set list_map "
+            categories      1
+            depends_fetch   1
+            depends_extract 1
+            depends_build   1
+            depends_lib     1
+            depends_run     1
+            maintainers     1
+            platforms       1
+            variants        1
+            conflicts       1
+            subports        1
+        "
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     ""
+            variants    Variants
+            depends_fetch "Fetch Dependencies"
+            depends_extract "Extract Dependencies"
+            depends_build "Build Dependencies"
+            depends_run "Runtime Dependencies"
+            depends_lib "Library Dependencies"
+            description "Brief Description"
+            long_description "Description"
+            fullname    "Full Name: "
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   "Conflicts with"
+            replaced_by "Replaced by"
+            subports    "Sub-ports"
+        }
+
+        # Wrap-length map for pretty printing
+        array set pretty_wrap {
+            heading 0
+            replaced_by 22
+            variants 22
+            depends_fetch 22
+            depends_extract 22
+            depends_build 22
+            depends_run 22
+            depends_lib 22
+            description 22
+            long_description 22
+            homepage 22
+            platforms 22
+            license 22
+            conflicts 22
+            maintainers 22
+            subports 22
+        }
+
+        # Interpret a convenient field abbreviation
+        if {[info exists options(ports_info_depends)] && $options(ports_info_depends) eq "yes"} {
+            array unset options ports_info_depends
+            set options(ports_info_depends_fetch) yes
+            set options(ports_info_depends_extract) yes
+            set options(ports_info_depends_build) yes
+            set options(ports_info_depends_lib) yes
+            set options(ports_info_depends_run) yes
+        }
+                
+        # Set up our field separators
+        set show_label 1
+        set field_sep "\n"
+        set subfield_sep ", "
+        set pretty_print 0
+        
+        # For human-readable summary, which is the default with no options
+        if {[llength [array get options ports_info_*]] == 0} {
+            set pretty_print 1
+        } elseif {[info exists options(ports_info_pretty)]} {
+            set pretty_print 1
+            array unset options ports_info_pretty
+        }
+
+        # Tune for sort(1)
+        if {[info exists options(ports_info_line)]} {
+            array unset options ports_info_line
+            set noseparator 1
+            set show_label 0
+            set field_sep "\t"
+            set subfield_sep ","
+        }
+        
+        # Figure out whether to show field name
+        set quiet [macports::ui_isset ports_quiet]
+        if {$quiet} {
+            set show_label 0
+        }
+        # In pretty-print mode we also suppress messages, even though we show
+        # most of the labels:
+        if {$pretty_print} {
+            set quiet 1
+        }
+
+        # Spin through action options, emitting information for any found
+        set fields {}
+        set opts_todo [array names options ports_info_*]
+        set fields_tried {}
+        if {![llength $opts_todo]} {
+            set opts_todo {ports_info_heading
+                ports_info_replaced_by
+                ports_info_subports
+                ports_info_variants 
+                ports_info_skip_line
+                ports_info_long_description ports_info_homepage 
+                ports_info_skip_line ports_info_depends_fetch
+                ports_info_depends_extract ports_info_depends_build
+                ports_info_depends_lib ports_info_depends_run
+                ports_info_conflicts
+                ports_info_platforms ports_info_license
+                ports_info_maintainers
+            }
+        }
+        foreach { option } $opts_todo {
+            set opt [string range $option 11 end]
+            # Artificial field name for formatting
+            if {$pretty_print && $opt eq "skip_line"} {
+                lappend fields ""
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq "heading"} {
+                set inf "$portinfo(name) @$portinfo(version)"
+                set ropt "heading"
+                if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                    append inf "_$portinfo(revision)"
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf " ([join $portinfo(categories) ", "])"
+                }
+            } elseif {$opt eq "fullname"} {
+                set inf "$portinfo(name) @"
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt "fullname"
+            } else {
+                # Map from friendly name
+                set ropt [map_friendly_field_names $opt]
+                
+                # If there's no such info, move on
+                if {![info exists portinfo($ropt)]} {
+                    set inf ""
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label ""
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label "$opt: "
+            }
+            
+            # Format the data
+            if { $ropt eq "maintainers" } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq "variants"} {
+                    # Use the new format for variants iff it exists in
+                    # PortInfo. This key currently does not exist outside of
+                    # trunk (1.8.0).
+                    array unset vinfo
+                    if {[info exists portinfo(vinfo)]} {
+                        array set vinfo $portinfo(vinfo)
+                    }
+
+                    set pi_vars $inf
+                    set inf {}
+                    foreach v [lsort $pi_vars] {
+                        set varmodifier ""
+                        if {[info exists variations($v)]} {
+                            # selected by command line, prefixed with +/-
+                            set varmodifier $variations($v)
+                        } elseif {[info exists global_variations($v)]} {
+                            # selected by variants.conf, prefixed with (+)/(-)
+                            set varmodifier "($global_variations($v))"
+                            # Retrieve additional information from the new key.
+                        } elseif {[info exists vinfo]} {
+                            array unset variant
+                            array set variant $vinfo($v)
+                            if {[info exists variant(is_default)]} {
+                                set varmodifier "\[$variant(is_default)]"
+                            }
+                        }
+                        lappend inf "$varmodifier$v"
+                    }
+                } elseif {[string match "depend*" $ropt] 
+                          && ![macports::ui_isset ports_verbose]} {
+                    set pi_deps $inf
+                    set inf {}
+                    foreach d $pi_deps {
+                        lappend inf [lindex [split $d :] end]
+                    }
+                }
+            } 
+            #End of special pretty-print formatting for certain fields
+            if {[info exists list_map($ropt)]} {
+                set field [join $inf $subfield_sep]
+            } else {
+                set field $inf
+            }
+            
+            # Assemble the entry
+            if {$pretty_print} {
+                # The two special fields are considered headings and are
+                # emitted immediately, rather than waiting. Also they are not
+                # recorded on the list of fields tried
+                if {$ropt eq "heading" || $ropt eq "fullname"} {
+                    puts "$label$field"
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq ""} {
+                    continue
+                }
+                if {$label eq ""} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat " " $wrap_len]]
+                } else {
+                    set wrap_len [string length $label]
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wraplabel $label $field 0 [string repeat " " $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields "$label$field"
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print && [llength $fields_tried]} {
+                puts -nonewline "$portinfo(name) has no "
+                puts [join $fields_tried ", "]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator "--\n"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_location { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        if { [catch {set ilist [registry_installed $portname [composite_version $portversion [array get variations]]]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port location failed: $result" 1 status
+        } else {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0]
+            set version [lindex $ilist 1]
+            set revision [lindex $ilist 2]
+            set variants [lindex $ilist 3]
+            set epoch [lindex $ilist 5]
+        }
+
+        set ref [registry::open_entry $portname $version $revision $variants $epoch]
+        set imagedir [registry::property_retrieve $ref location]
+        ui_notice "Port $portname ${version}_${revision}${variants} is installed as an image in:"
+        puts $imagedir
+    }
+    
+    return $status
+}
+
+
+proc action_notes { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set status 0
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue "The lookup of '$portname' failed: $result" \
+                                1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "The port '$portname' was not found" 1 status
+            }
+
+            # Retrieve the port's URL.
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        }
+        
+        # Add any global_variations to the variations
+        # specified for the port
+        array unset merged_variations
+        array set merged_variations [array get variations]
+        foreach { variation value } [array get global_variations] { 
+            if { ![info exists merged_variations($variation)] } { 
+                set merged_variations($variation) $value 
+            } 
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+
+        # Open the Portfile associated with this port.
+        if {[catch {set mport [mportopen $porturl [array get options] \
+                                         [array get merged_variations]]} \
+                   result]} {
+            ui_debug $::errorInfo
+            break_softcontinue [concat "The URL '$porturl' could not be" \
+                                       "opened: $result"] 1 status
+        }
+        array unset portinfo
+        array set portinfo [mportinfo $mport]
+        mportclose $mport
+
+        # Return the notes associated with this Portfile.
+        if {[info exists portinfo(notes)]} {
+            set portnotes $portinfo(notes)
+        } else {
+            set portnotes {}
+        }
+
+        # Retrieve the port's name once more to ensure it has the proper case.
+        set portname $portinfo(name)
+
+        # Display the notes.
+        if {$portnotes ne {}} {
+            ui_notice "$portname has the following notes:"
+            foreach note $portnotes {
+                puts [wrap $note 0 "  " 1]
+            }
+        } else {
+            puts "$portname has no notes."
+        }
+    }
+    return $status
+}
+
+
+proc action_provides { action portlist opts } {
+    # In this case, portname is going to be used for the filename... since
+    # that is the first argument we expect... perhaps there is a better way
+    # to do this?
+    if { ![llength $portlist] } {
+        ui_error "Please specify a filename to check which port provides that file."
+        return 1
+    }
+    foreach filename $portlist {
+        set file [file normalize $filename]
+        if {[file exists $file] || ![catch {file type $file}]} {
+            if {![file isdirectory $file] || [file type $file] eq "link"} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts "$file is provided by: $port"
+                } else {
+                    puts "$file is not provided by a MacPorts port."
+                }
+            } else {
+                puts "$file is a directory."
+            }
+        } else {
+            puts "$file does not exist."
+        }
+    }
+    registry::close_file_map
+    
+    return 0
+}
+
+
+proc action_activate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_activate_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[$regref installtype] eq "image" && [registry::run_target $regref activate [array get options]]} {
+                continue
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::activate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port activate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping activate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_deactivate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    set portlist [portlist_sortdependents $portlist]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_deactivate_no-exec)]
+            && ![catch {set ilist [registry::active $portname]}]} {
+
+            set i [lindex $ilist 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            if {$composite_version eq "" || $composite_version == "${iversion}_${irevision}${ivariants}"} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq "image" && [registry::run_target $regref deactivate [array get options]]} {
+                    continue
+                }
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::deactivate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port deactivate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping deactivate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug "action_select \[$portlist] \[$opts]..."
+
+    array set opts_array $opts
+    set commands [array names opts_array ports_select_*]
+    array unset opts_array
+
+    # Error out if no group is specified or command is not --summary.
+    if {[llength $portlist] < 1 && [string map {ports_select_ ""} [lindex $commands 0]] != "summary"} {
+        ui_error "port select \[--list|--set|--show|--summary] \<group> \[<version>]"
+        return 1
+    }
+
+    set group [lindex $portlist 0]
+    
+    # If no command (--set, --show, --list, --summary) is specified *but*
+    #  more than one argument is specified, default to the set command.
+    if {[llength $commands] < 1 && [llength $portlist] > 1} {
+        set command set
+        ui_debug [concat "Although no command was specified, more than " \
+                         "one argument was specified.  Defaulting to the " \
+                         "'set' command..."]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] < 1} {
+        set command list
+        ui_debug [concat "No command was specified. Defaulting to the " \
+                         "'list' command..."]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] > 1} {
+        ui_error [concat "Multiple commands were specified. Only one " \
+                         "command may be specified at a time."]
+        return 1
+    } else {
+        set command [string map {ports_select_ ""} [lindex $commands 0]]
+        ui_debug "The '$command' command was specified."
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'list' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn "Unable to get active selected version: $selected_version"
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error "The 'list' command failed: $versions"
+                return 1
+            }
+
+            ui_notice "Available versions for $group:"
+            foreach v $versions {
+                ui_notice -nonewline "\t"
+                if {$selected_version == $v} {
+                    ui_msg "$v (active)"
+                } else {
+                    ui_msg "$v"
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] < 2} {
+                ui_error [concat "The 'set' command expects two " \
+                                 "arguments: <group>, <version>"]
+                return 1
+            } elseif {[llength $portlist] > 2} {
+                ui_warn [concat "The 'set' command only expects two " \
+                                "arguments. Extra arguments will be " \
+                                "ignored."]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline "Selecting '$version' for '$group' "
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg "failed: $result"
+                return 1
+            }
+            ui_msg "succeeded. '$version' is now active."
+            return 0
+        }
+        show {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'show' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error "The 'show' command failed: $selected_version"
+                return 1
+            }
+            puts [concat "The currently selected version for '$group' is " \
+                         "'$selected_version'."]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] > 0} {
+                ui_warn [concat "The 'summary' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error "The 'summary' command failed: $portgroups"
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr "%-*s  %-*s  %s"
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn "The list of options for the select group $pg could not be obtained: $versions"
+                    continue
+                }
+                # remove "none", sort the list, append none at the end
+                set noneidx [lsearch -exact $versions "none"]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions "none"
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn "The currently selected option for the select group $pg could not be obtained: $selected_version"
+                    continue
+                }
+                set groupdesc(selected) $selected_version
+
+                set w1 [expr {max($w1, [string length $pg])}]
+                set w2 [expr {max($w2, [string length $selected_version])}]
+
+                lappend groups [array get groupdesc]
+                array unset groupdesc
+            }
+            puts [format $formatStr $w1 "Name" $w2 "Selected" "Options"]
+            puts [format $formatStr $w1 "====" $w2 "========" "======="]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) " "]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error "An unknown command '$command' was specified."
+            return 1
+        }
+    }
+}
+
+
+proc action_selfupdate { action portlist opts } {
+    global global_options
+    if { [catch {macports::selfupdate [array get global_options] base_updated} result ] } {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_error "$result"
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg "Please run `port -v selfupdate' for details."
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal "port selfupdate failed: $result"
+    }
+    
+    if {$base_updated} {
+        # exit immediately if in batch/interactive mode
+        return -999
+    } else {
+        return 0
+    }
+}
+
+
+proc action_setrequested { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    # set or unset?
+    set val [string equal $action "setrequested"]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info "Setting requested flag for $portname to $val"
+            foreach i $ilist {
+                set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+                registry::property_store $regref requested $val
+            }
+        } else {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist "yes"] || ([prefix_unwritable] && ![macports::global_option_isset ports_dryrun])} {
+        return 1
+    }
+
+    # shared depscache for all ports in the list
+    array set depscache {}
+    set status 0
+    foreachport $portlist {
+        if {![info exists depscache(port:$portname)]} {
+            set status [macports::upgrade $portname "port:$portname" [array get requested_variations] [array get options] depscache]
+            # status 2 means the port was not found in the index,
+            # status 3 means the port is not installed
+            if {$status != 0 && $status != 2 && $status != 3 && ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 && $status != 2 && $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] && ${macports::revupgrade_autorun} && ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+<<<<<<< HEAD
+    macports::doctor_main
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::doctor_main $opts
+>>>>>>> svn
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+<<<<<<< HEAD
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+>>>>>>> svn
+    macports::reclaim_main  
+    return 0
+}
+
+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 } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Version: "
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Platform: "
+    }
+    puts "${macports::os_platform} ${macports::os_major} ${macports::os_arch}"
+    return 0
+}
+
+
+proc action_dependents { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set ilist {}
+
+    registry::open_dep_map
+
+    set status 0
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if { [catch {set ilist [registry::installed $portname $composite_version]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        } else {
+            # choose the active version if there is one
+            set index 0
+            foreach i $ilist {
+                if {[lindex $i 4]} {
+                    set found 1
+                    break
+                }
+                incr index
+            }
+            if {![info exists found]} {
+                set index 0
+            }
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist $index 0]
+            set iversion [lindex $ilist $index 1]
+            set irevision [lindex $ilist $index 2]
+            set ivariants [lindex $ilist $index 3]
+        }
+        
+        set deplist [registry::list_dependents $portname $iversion $irevision $ivariants]
+        if { [llength $deplist] > 0 } {
+            if {$action eq "rdependents"} {
+                set toplist $deplist
+                while 1 {
+                    set newlist {}
+                    foreach dep $deplist {
+                        set depname [lindex $dep 2]
+                        if {![info exists seen($depname)]} {
+                            set seen($depname) 1
+                            set rdeplist [registry::list_dependents $depname]
+                            foreach rdep $rdeplist {
+                                lappend newlist $rdep
+                            }
+                            set dependentsof($depname) $rdeplist
+                        }
+                    }
+                    if {[llength $newlist] > 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice "The following ports are dependent on ${portname}:"
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos >= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] <= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] && [string is true -strict $options(ports_rdependents_full)])} {
+                        puts "${spaces}${cur_portname}"
+                        set seen($cur_portname) 1
+                        incr cur_pos
+                        set pos_stack [lreplace $pos_stack end end $cur_pos]
+                        if {[info exists dependentsof($cur_portname)]} {
+                            lappend portstack $dependentsof($cur_portname)
+                            lappend pos_stack 0
+                        }
+                        continue
+                    }
+                    incr cur_pos
+                    set pos_stack [lreplace $pos_stack end end $cur_pos]
+                }
+            } else {
+                foreach dep $deplist {
+                    set depport [lindex $dep 2]
+                    if {[macports::ui_isset ports_quiet]} {
+                        ui_msg "$depport"
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg "$depport depends on $portname"
+                    } else {
+                        ui_msg "$depport depends on $portname (by [lindex $dep 1]:)"
+                    }
+                }
+            }
+        } else {
+            ui_notice "$portname has no dependents."
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator ""
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] && [string is true -strict $options(ports_${action}_no-build)]} {
+            set deptypes {depends_lib depends_run}
+        } else {
+            set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+        }
+
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+            # Add any global_variations to the variations
+            # specified for the port, so we get dependencies right
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn "port ${action} --index does not work with the 'current' pseudo-port"
+            continue
+        }
+        set portname $portinfo(name)
+
+        set deplist {}
+        set deps_output {}
+        set ndeps 0
+        array set labeldict {depends_fetch Fetch depends_extract Extract depends_build Build depends_lib Library depends_run Runtime}
+        # get list of direct deps
+        foreach type $deptypes {
+            if {[info exists portinfo($type)]} {
+                if {$action eq "rdeps" || [macports::ui_isset ports_verbose]} {
+                    foreach dep $portinfo($type) {
+                        lappend deplist $dep
+                    }
+                } else {
+                    foreach dep $portinfo($type) {
+                        lappend deplist [lindex [split $dep :] end]
+                    }
+                }
+                if {$action eq "deps"} {
+                    set label "$labeldict($type) Dependencies"
+                    lappend deps_output [wraplabel $label [join $deplist ", "] 0 [string repeat " " 22]]
+                    incr ndeps [llength $deplist]
+                    set deplist {}
+                }
+            }
+        }
+
+        set version $portinfo(version)
+        set revision $portinfo(revision)
+        if {[info exists portinfo(canonical_active_variants)]} {
+            set variants $portinfo(canonical_active_variants)
+        } else {
+            set variants {}
+        }
+
+        puts -nonewline $separator
+        if {$action eq "deps"} {
+            if {$ndeps == 0} {
+                ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+            } else {
+                ui_notice "Full Name: $portname @${version}_${revision}${variants}"
+                puts [join $deps_output "\n"]
+            }
+            set separator "--\n"
+            continue
+        }
+
+        set toplist $deplist
+        # gather all the deps
+        while 1 {
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        break_softcontinue "lookup of portname $depname failed: $result" 1 status
+                    }
+                    if {[llength $result] < 2} {
+                        break_softcontinue "Port $depname not found" 1 status
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                    set options(subport) $portinfo(name)
+                    
+                    # open the portfile if requested
+                    if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug "$::errorInfo"
+                            break_softcontinue "Unable to open port: $result" 1 status
+                        }
+                        array unset portinfo
+                        array set portinfo [mportinfo $mport]
+                        mportclose $mport
+                    }
+                    
+                    # get list of the dep's deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                lappend rdeplist $rdep
+                                lappend newlist $rdep
+                            }
+                        }
+                    }
+                    set depsof($depname) $rdeplist
+                }
+            }
+            if {[llength $newlist] > 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] > 0} {
+            ui_notice "The following ports are dependencies of $portname @${version}_${revision}${variants}:"
+        } else {
+            ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos >= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] <= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] && [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts "${spaces}${cur_port}"
+                } else {
+                    puts "${spaces}${cur_portname}"
+                }
+                set seen($cur_portname) 1
+                incr cur_pos
+                set pos_stack [lreplace $pos_stack end end $cur_pos]
+                if {[info exists depsof($cur_portname)]} {
+                    lappend portstack $depsof($cur_portname)
+                    lappend pos_stack 0
+                }
+                continue
+            }
+            incr cur_pos
+            set pos_stack [lreplace $pos_stack end end $cur_pos]
+        }
+        set separator "--\n"
+    }
+    return $status
+}
+
+
+proc action_uninstall { action portlist opts } {
+    set status 0
+    if {[macports::global_option_isset port_uninstall_old]} {
+        # if -u then uninstall all inactive ports
+        # (union these to any other ports user has in the port list)
+        set portlist [opUnion $portlist [get_inactive_ports]]
+    } else {
+        # Otherwise the user hopefully supplied a portlist, or we'll default to the existing directory
+        if {[require_portlist portlist]} {
+            return 1
+        }
+    }
+    if {[prefix_unwritable]} {
+        return 1
+    }
+
+    set portlist [portlist_sortdependents $portlist]
+
+    foreachport $portlist {
+        if {![registry::entry_exists_for_name $portname]} {
+            # if the code path arrives here the port either isn't installed, or
+            # it doesn't exist at all. We can't be sure, but we can check the
+            # portindex whether a port by that name exists (in which case not
+            # uninstalling it is probably no problem). If there is no port by
+            # that name, alert the user in case of typos.
+            ui_info "$portname is not installed"
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn "no such port: $portname, skipping uninstall"
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set iactive [lindex $i 4]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[registry::run_target $regref uninstall [array get options]]} {
+                continue
+            }
+        }
+
+        if { [catch {registry_uninstall::uninstall_composite $portname $composite_version [array get options]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port uninstall failed: $result" 1 status
+        }
+    }
+
+    return $status
+}
+
+
+proc action_installed { action portlist opts } {
+    global private_options
+    set status 0
+    set restrictedList 0
+    set ilist {}
+    
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreachport $portlist {
+            set composite_version [composite_version $portversion [array get variations]]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port installed failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] > 0 } {
+        ui_notice "The following ports are currently installed:"
+        foreach i [portlist_sortint $ilist] {
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            set extra ""
+            set nvariants ""
+            if {[macports::ui_isset ports_verbose]} {
+                set regref [registry::open_entry $iname $iversion $irevision $ivariants [lindex $i 5]]
+                set nvariants [registry::property_retrieve $regref negated_variants]
+                if {$nvariants == 0} {
+                    set nvariants ""
+                }
+                set os_platform [registry::property_retrieve $regref os_platform]
+                set os_major [registry::property_retrieve $regref os_major]
+                set archs [registry::property_retrieve $regref archs]
+                if {$os_platform != 0 && $os_platform ne "" && $os_major != 0 && $os_major ne ""} {
+                    append extra " platform='$os_platform $os_major'"
+                }
+                if {$archs != 0 && $archs ne ""} {
+                    append extra " archs='$archs'"
+                }
+            }
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}"
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are installed."
+    } else {
+        ui_notice "No ports are installed."
+    }
+
+    return $status
+}
+
+
+proc action_outdated { action portlist opts } {
+    global private_options
+    set status 0
+
+    # If port names were supplied, limit ourselves to those ports, else check all installed ports
+    set ilist {}
+    set restrictedList 0
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreach portspec $portlist {
+            array set port $portspec
+            set portname $port(name)
+            set composite_version [composite_version $port(version) $port(variants)]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port outdated failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] > 0 } {
+        foreach i [portlist_sortint $ilist] {
+        
+            # Get information about the installed port
+            set portname [lindex $i 0]
+            set installed_version [lindex $i 1]
+            set installed_revision [lindex $i 2]
+            set installed_compound "${installed_version}_${installed_revision}"
+
+            set is_active [lindex $i 4]
+            if {$is_active == 0} {
+                continue
+            }
+            set installed_epoch [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+            
+            # Get information about latest available version and revision
+            if {![info exists portinfo(version)]} {
+                ui_warn "$portname has no version field"
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound "${latest_version}_${latest_revision}"
+            set latest_epoch 0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch $portinfo(epoch)
+            }
+            
+            # Compare versions, first checking epoch, then version, then revision
+            set epoch_comp_result [expr {$installed_epoch - $latest_epoch}]
+            set comp_result [vercmp $installed_version $latest_version]
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            set reason ""
+            if {$epoch_comp_result != 0 && $installed_version != $latest_version} {
+                if {($comp_result >= 0 && $epoch_comp_result < 0) || ($comp_result <= 0 && $epoch_comp_result > 0)} {
+                    set reason { (epoch $installed_epoch $relation $latest_epoch)}
+                }
+                set comp_result $epoch_comp_result
+            } elseif {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision [lindex $i 3] $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                    set reason { (platform $os_platform_installed $os_major_installed != ${macports::os_platform} ${macports::os_major})}
+                }
+            }
+            
+            # Report outdated (or, for verbose, predated) versions
+            if { $comp_result != 0 } {
+                            
+                # Form a relation between the versions
+                set flag ""
+                if { $comp_result > 0 } {
+                    set relation ">"
+                    set flag "!"
+                } else {
+                    set relation "<"
+                }
+                
+                # Emit information
+                if {$comp_result < 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice "The following installed ports are outdated:"
+                    }
+                    incr num_outdated
+
+                    puts [format "%-30s %-24s %1s" $portname "$installed_compound $relation $latest_compound [subst $reason]" $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice "No installed ports are outdated."
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are outdated."
+    } else {
+        ui_notice "No ports are installed."
+    }
+    
+    return $status
+}
+
+
+proc action_contents { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {[info exists global_options(ports_contents_size)]} {
+        set units {}
+        if {[info exists global_options(ports_contents_units)]} {
+            set units [complete_size_units $global_options(ports_contents_units)]
+        }
+        set outstring {[format "%12s $file" [filesize $file $units]]}
+    } else {
+        set outstring {  $file}
+    }
+
+    foreachport $portlist {
+        if { ![catch {set ilist [registry::installed $portname]} result] } {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0 0]
+        }
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                ui_notice "Port $portname contains:"
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice "Port $portname does not contain any files or is not active."
+            }
+        } else {
+            ui_notice "Port $portname is not installed."
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq "K" || $units eq "Ki"} {
+        return "KiB"
+    } elseif {$units eq "k"} {
+        return "kB"
+    } elseif {$units eq "Mi"} {
+        return "MiB"
+    } elseif {$units eq "M"} {
+        return "MB"
+    } elseif {$units eq "Gi"} {
+        return "GiB"
+    } elseif {$units eq "G"} {
+        return "GB"
+    } else {
+        return $units
+    }
+}
+
+# Show space used by the given ports' files
+proc action_space {action portlist opts} {
+    global global_options
+    require_portlist portlist
+
+    set units {}
+    if {[info exists global_options(ports_space_units)]} {
+        set units [complete_size_units $global_options(ports_space_units)]
+    }
+    set spaceall 0.0
+    foreachport $portlist {
+        set space 0.0
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne "yes"} {
+                    set msg "[bytesize $space $units] $portname"
+                    if { $portversion != {} } {
+                        append msg " @$portversion"
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr "Port $portname does not contain any file or is not active."
+            }
+        } else {
+            puts stderr "Port $portname is not installed."
+        }
+    }
+    if {[llength $portlist] > 1 || ([info exists options(ports_space_total)] && $options(ports_space_total) eq "yes")} {
+        puts "[bytesize $spaceall $units] total"
+    }
+    return 0
+}
+
+proc action_variants { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] && $options(ports_variants_index) eq "yes")} {
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "port variants --index does not work with 'current' pseudo-port"
+            continue
+        }
+
+        # set portname again since the one we were passed may not have had the correct case
+        set portname $portinfo(name)
+
+        # if this fails the port doesn't have any variants
+        if {![info exists portinfo(variants)]} {
+            ui_notice "$portname has no variants"
+        } else {
+            array unset vinfo
+            # Use the new format if it exists.
+            if {[info exists portinfo(vinfo)]} {
+                array set vinfo $portinfo(vinfo)
+            # Otherwise fall back to the old format.
+            } elseif {[info exists portinfo(variant_desc)]} {
+                array set vdescriptions $portinfo(variant_desc)
+            }
+
+            # print out all the variants
+            ui_notice "$portname has the variants:"
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier "   "
+                # Retrieve variants' information from the new format.
+                if {[info exists vinfo]} {
+                    array unset variant
+                    array set variant $vinfo($v)
+
+                    # Retrieve conflicts, description, is_default, and
+                    # vrequires.
+                    if {[info exists variant(conflicts)]} {
+                        set vconflicts $variant(conflicts)
+                    }
+                    if {[info exists variant(description)]} {
+                        set vdescription $variant(description)
+                    }
+
+                    # XXX Keep these varmodifiers in sync with action_info, or create a wrapper for it
+                    if {[info exists variations($v)]} {
+                        set varmodifier "  $variations($v)"
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier "($global_variations($v))"
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier "\[$variant(is_default)\]"
+                    }
+                    if {[info exists variant(requires)]} {
+                        set vrequires $variant(requires)
+                    }
+                # Retrieve variants' information from the old format,
+                # which only consists of the description.
+                } elseif {[info exists vdescriptions($v)]} {
+                    set vdescription $vdescriptions($v)
+                }
+
+                if {[info exists vdescription]} {
+                    puts [wraplabel "$varmodifier$v" [string trim $vdescription] 0 [string repeat " " [expr 5 + [string length $v]]]]
+                } else {
+                    puts "$varmodifier$v"
+                }
+                if {[info exists vconflicts]} {
+                    puts "     * conflicts with [string trim $vconflicts]"
+                }
+                if {[info exists vrequires]} {
+                    puts "     * requires [string trim $vrequires]"
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        ui_error "You must specify a search pattern"
+        return 1
+    }
+
+    # Copy global options as we are going to modify the array
+    array set options [array get global_options]
+
+    if {[info exists options(ports_search_depends)] && $options(ports_search_depends) eq "yes"} {
+        array unset options ports_search_depends
+        set options(ports_search_depends_fetch) yes
+        set options(ports_search_depends_extract) yes
+        set options(ports_search_depends_build) yes
+        set options(ports_search_depends_lib) yes
+        set options(ports_search_depends_run) yes
+    }
+
+    # Array to hold given filters
+    array set filters {}
+    # Default matchstyle
+    set filter_matchstyle "none"
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne "yes" } {
+            continue
+        }
+        switch -- $opt {
+            exact -
+            glob {
+                set filter_matchstyle $opt
+                continue
+            }
+            regex {
+                set filter_matchstyle regexp
+                continue
+            }
+            case-sensitive {
+                set filter_case yes
+                continue
+            }
+            line {
+                continue
+            }
+        }
+
+        set filters($opt) "yes"
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) "yes"
+        set filters(description) "yes"
+    }
+
+    set separator ""
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq "none"} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first "*" $portname] == -1 && [string first "?" $portname] == -1} {
+                set searchstring "*$portname*"
+            }
+            set matchstyle glob
+        }
+
+        set res {}
+        set portfound 0
+        foreach { opt } [array get filters] {
+            # Map from friendly name
+            set opt [map_friendly_field_names $opt]
+
+            if {[catch {eval set matches \[mportsearch \$searchstring $filter_case \$matchstyle $opt\]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for name $portname failed: $result" 1 status
+            }
+
+            set tmp {}
+            foreach {name info} $matches {
+                add_to_portlist tmp [concat [list name $name] $info]
+            }
+            set res [opUnion $res $tmp]
+        }
+        set res [portlist_sort $res]
+
+        set joiner ""
+        foreach info $res {
+            array unset portinfo
+            array set portinfo $info
+
+            # XXX is this the right place to verify an entry?
+            if {![info exists portinfo(name)]} {
+                puts stderr "Invalid port entry, missing portname"
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing description"
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing version"
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        && $options(ports_search_line) eq "yes"} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts "$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)"
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts "$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)"
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline "$portinfo(name) @$portinfo(version)"
+                    if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                        puts -nonewline "_$portinfo(revision)"
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline " ([join $portinfo(categories) ", "])"
+                    }
+                    puts ""
+                    puts [wrap [join $portinfo(description)] 0 [string repeat " " 4]]
+                }
+            }
+
+            set joiner "\n"
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice "No match for $portname found"
+        } elseif {[llength $res] > 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne "yes")} {
+                ui_notice "\nFound [llength $res] ports."
+            }
+        }
+
+        set separator "--\n"
+    }
+
+    array unset options
+    array unset filters
+
+    return $status
+}
+
+
+proc action_list { action portlist opts } {
+    global private_options
+    set status 0
+    
+    # Default to list all ports if no portnames are supplied
+    if { ![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        add_to_portlist portlist [list name "-all-"]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq "-all-"} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "listing all ports failed: $result" 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $search_string failed: $result" 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir ""
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format "%-30s @%-14s %s" $portinfo(name) $portinfo(version) $outdir]
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_echo { action portlist opts } {
+    global global_options
+
+    # Simply echo back the port specs given to this command
+    foreachport $portlist {
+        if {![macports::ui_isset ports_quiet]} {
+            set opts {}
+            foreach { key value } [array get options] {
+                if {![info exists global_options($key)]} {
+                    lappend opts "$key=$value"
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne "" } {
+                set ver_field "@$composite_version"
+            } else {
+                set ver_field ""
+            }
+            puts [format "%-30s %s %s" $portname $ver_field  [join $opts " "]]
+        } else {
+            puts "$portname"
+        }
+    }
+
+    return 0
+}
+
+
+proc action_portcmds { action portlist opts } {
+    # Operations on the port's directory and Portfile
+    global env boot_env current_portdir
+
+    array set local_options $opts
+    
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific, otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+            set portname $portinfo(name)
+        }
+        
+        
+        # Calculate portdir, porturl, and portfile from initial porturl
+        set portdir [file normalize [macports::getportdir $porturl]]
+        set porturl "file://${portdir}";    # Rebuild url so it's fully qualified
+        set portfile "${portdir}/Portfile"
+        
+        # Now execute the specific action
+        if {[file readable $portfile]} {
+            switch -- $action {
+                cat {
+                    # Copy the portfile to standard output
+                    set f [open $portfile RDONLY]
+                    while { ![eof $f] } {
+                        puts -nonewline [read $f 4096]
+                    }
+                    close $f
+                }
+                
+                edit {
+                    # Edit the port's portfile with the user's editor
+                    
+                    # Restore our entire environment from start time.
+                    # We need it to evaluate the editor, and the editor
+                    # may want stuff from it as well, like TERM.
+                    array unset env_save; array set env_save [array get env]
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor ""
+                    set editor_var "ports_${action}_editor"
+                    if {[info exists local_options($editor_var)]} {
+                        set editor [join $local_options($editor_var)]
+                    } else {
+                        foreach ed { MP_EDITOR VISUAL EDITOR } {
+                            if {[info exists env($ed)]} {
+                                set editor $env($ed)
+                                break
+                            }
+                        }
+                    }
+                    
+                    # Use a reasonable canned default if no editor specified or set in env
+                    if { $editor eq "" } { set editor "/usr/bin/vi" }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec >@stdout <@stdin 2>@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug "$errorInfo"
+                        break_softcontinue "unable to invoke editor $editor: $result" 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get env_save]
+                }
+
+                dir {
+                    # output the path to the port's directory
+                    puts $portdir
+                }
+
+                work {
+                    # output the path to the port's work directory
+                    set workpath [macports::getportworkpath_from_portdir $portdir $portname]
+                    if {[file exists $workpath]} {
+                        puts $workpath
+                    }
+                }
+
+                cd {
+                    # Change to the port's directory, making it the default
+                    # port for any future commands
+                    set current_portdir $portdir
+                }
+
+                url {
+                    # output the url of the port's directory, suitable to feed back in later as a port descriptor
+                    puts $porturl
+                }
+
+                file {
+                    # output the path to the port's portfile
+                    puts $portfile
+                }
+
+                logfile {
+                    set logfile [file join [macports::getportlogpath $portdir $portname] "main.log"]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error "Log file not found for port in $portdir"
+                    }
+                }
+
+                gohome {
+                    set homepage ""
+
+                    # Get the homepage as read from PortIndex
+                    if {[info exists portinfo(homepage)]} {
+                        set homepage $portinfo(homepage)
+                    }
+
+                    # If not available, get the homepage for the port by opening the Portfile
+                    if {$homepage eq "" && ![catch {set ctx [mportopen $porturl]} result]} {
+                        array set portinfo [mportinfo $ctx]
+                        if {[info exists portinfo(homepage)]} {
+                            set homepage $portinfo(homepage)
+                        }
+                        mportclose $ctx
+                    }
+
+                    # Try to open a browser to the homepage for the given port
+                    if { $homepage ne "" } {
+                        if {[catch {system "${macports::autoconf::open_path} '$homepage'"} result]} {
+                            global errorInfo
+                            ui_debug "$errorInfo"
+                            break_softcontinue "unable to invoke browser using ${macports::autoconf::open_path}: $result" 1 status
+                        }
+                    } else {
+                        ui_error [format "No homepage for %s" $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue "Could not read $portfile" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_sync { action portlist opts } {
+    global global_options
+
+    set status 0
+    if {[catch {mportsync [array get global_options]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_msg "port sync failed: $result"
+        set status 1
+    }
+    
+    return $status
+}
+
+
+proc action_target { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {($action eq "install" || $action eq "archive") && [prefix_unwritable] && ![macports::global_option_isset ports_dryrun]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn "Skipping $portname (not in the ports tree)"
+                    continue
+                } else {
+                    break_softcontinue "Port $portname not found" 1 status
+                }
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+        }
+
+        # use existing variants iff none were explicitly requested
+        if {[array get requested_variations] eq "" && [array get variations] ne ""} {
+            array unset requested_variations
+            array set requested_variations [array get variations]
+        }
+
+        # Add any global_variations to the variations
+        # specified for the port
+        foreach { variation value } [array get global_variations] {
+            if { ![info exists requested_variations($variation)] } {
+                set requested_variations($variation) $value
+            }
+        }
+
+        # If version was specified, save it as a version glob for use
+        # in port actions (e.g. clean).
+        if {[string length $portversion]} {
+            set options(ports_version_glob) $portversion
+        }
+        # if installing, mark the port as explicitly requested
+        if {$action eq "install"} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq "archive"} {
+            set target install
+        } else {
+            set target $action
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+        if {[catch {set workername [mportopen $porturl [array get options] [array get requested_variations]]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to open port: $result" 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to execute port: $result" 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue "Processing of port $portname failed" 1 status
+        }
+    }
+    
+    if {$status == 0 && $action eq "install" && ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] && ![info exists options(ports_install_no-rev-upgrade)] && ${macports::revupgrade_autorun}} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+
+proc action_exit { action portlist opts } {
+    # Return a semaphore telling the main loop to quit
+    return -999
+}
+
+
+##########################################
+# Command Parsing
+##########################################
+proc moreargs {} {
+    global cmd_argn cmd_argc
+    return [expr {$cmd_argn < $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn < $cmd_argc} {
+        return [lindex $cmd_argv $cmd_argn]
+    } else {
+        return _EOF_
+    }
+}
+
+
+proc advance {} {
+    global cmd_argn
+    incr cmd_argn
+}
+
+
+proc match s {
+    if {[lookahead] == $s} {
+        advance
+        return 1
+    }
+    return 0
+}
+
+# action_array specifies which action to run on the given command
+# and if the action wants an expanded portlist.
+# The value is a list of the form {action expand},
+# where action is a string and expand a value:
+#   0 none        Does not expect any text argument
+#   1 strings     Expects some strings as text argument
+#   2 ports       Wants an expanded list of ports as text argument
+global action_array
+
+# Define global constants
+const ACTION_ARGS_NONE 0
+const ACTION_ARGS_STRINGS 1
+const ACTION_ARGS_PORTS 2
+
+array set action_array [list \
+    usage       [list action_usage          [ACTION_ARGS_STRINGS]] \
+    help        [list action_help           [ACTION_ARGS_STRINGS]] \
+    \
+    echo        [list action_echo           [ACTION_ARGS_PORTS]] \
+    \
+    info        [list action_info           [ACTION_ARGS_PORTS]] \
+    location    [list action_location       [ACTION_ARGS_PORTS]] \
+    notes       [list action_notes          [ACTION_ARGS_PORTS]] \
+    provides    [list action_provides       [ACTION_ARGS_STRINGS]] \
+    log         [list action_log            [ACTION_ARGS_PORTS]] \
+    \
+    activate    [list action_activate       [ACTION_ARGS_PORTS]] \
+    deactivate  [list action_deactivate     [ACTION_ARGS_PORTS]] \
+    \
+    select      [list action_select         [ACTION_ARGS_STRINGS]] \
+    \
+    sync        [list action_sync           [ACTION_ARGS_NONE]] \
+    selfupdate  [list action_selfupdate     [ACTION_ARGS_NONE]] \
+    \
+    setrequested   [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    unsetrequested [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    \
+    upgrade     [list action_upgrade        [ACTION_ARGS_PORTS]] \
+    rev-upgrade [list action_revupgrade     [ACTION_ARGS_NONE]] \
+    reclaim     [list action_reclaim        [ACTION_ARGS_NONE]] \
+    doctor      [list action_doctor         [ACTION_ARGS_NONE]] \
+    \
+    version     [list action_version        [ACTION_ARGS_NONE]] \
+    platform    [list action_platform       [ACTION_ARGS_NONE]] \
+    \
+    uninstall   [list action_uninstall      [ACTION_ARGS_PORTS]] \
+    \
+    installed   [list action_installed      [ACTION_ARGS_PORTS]] \
+    outdated    [list action_outdated       [ACTION_ARGS_PORTS]] \
+    contents    [list action_contents       [ACTION_ARGS_PORTS]] \
+    space       [list action_space          [ACTION_ARGS_PORTS]] \
+    dependents  [list action_dependents     [ACTION_ARGS_PORTS]] \
+    rdependents [list action_dependents     [ACTION_ARGS_PORTS]] \
+    deps        [list action_deps           [ACTION_ARGS_PORTS]] \
+    rdeps       [list action_deps           [ACTION_ARGS_PORTS]] \
+    variants    [list action_variants       [ACTION_ARGS_PORTS]] \
+    \
+    search      [list action_search         [ACTION_ARGS_STRINGS]] \
+    list        [list action_list           [ACTION_ARGS_PORTS]] \
+    \
+    edit        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cat         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    dir         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    work        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cd          [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    url         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    file        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    logfile     [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    gohome      [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    \
+    fetch       [list action_target         [ACTION_ARGS_PORTS]] \
+    checksum    [list action_target         [ACTION_ARGS_PORTS]] \
+    extract     [list action_target         [ACTION_ARGS_PORTS]] \
+    patch       [list action_target         [ACTION_ARGS_PORTS]] \
+    configure   [list action_target         [ACTION_ARGS_PORTS]] \
+    build       [list action_target         [ACTION_ARGS_PORTS]] \
+    destroot    [list action_target         [ACTION_ARGS_PORTS]] \
+    install     [list action_target         [ACTION_ARGS_PORTS]] \
+    clean       [list action_target         [ACTION_ARGS_PORTS]] \
+    test        [list action_target         [ACTION_ARGS_PORTS]] \
+    lint        [list action_target         [ACTION_ARGS_PORTS]] \
+    livecheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    distcheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    mirror      [list action_target         [ACTION_ARGS_PORTS]] \
+    load        [list action_target         [ACTION_ARGS_PORTS]] \
+    unload      [list action_target         [ACTION_ARGS_PORTS]] \
+    distfiles   [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    archivefetch [list action_target         [ACTION_ARGS_PORTS]] \
+    archive     [list action_target         [ACTION_ARGS_PORTS]] \
+    unarchive   [list action_target         [ACTION_ARGS_PORTS]] \
+    dmg         [list action_target         [ACTION_ARGS_PORTS]] \
+    mdmg        [list action_target         [ACTION_ARGS_PORTS]] \
+    dpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    mpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    pkg         [list action_target         [ACTION_ARGS_PORTS]] \
+    portpkg     [list action_target         [ACTION_ARGS_PORTS]] \
+    rpm         [list action_target         [ACTION_ARGS_PORTS]] \
+    srpm        [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    quit        [list action_exit           [ACTION_ARGS_NONE]] \
+    exit        [list action_exit           [ACTION_ARGS_NONE]] \
+]
+
+# Expand "action".
+# Returns an action proc, or a list of matching action procs, or the action passed in
+proc find_action { action } {
+    global action_array
+    
+    if { ! [info exists action_array($action)] } {
+        set guess [guess_action $action]
+        if { [info exists action_array($guess)] } {
+            return $guess
+        }
+        return $guess
+    }
+    
+    return $action
+}
+
+# Expand action
+# If there's more than one match, return the next possibility
+proc find_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    } else {
+        set action [complete_action $action]
+        if { [info exists action_array($action)] } {
+            set action_proc [lindex $action_array($action) 0]
+        }
+    }
+    
+    return $action_proc
+}
+
+proc get_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    }
+    
+    return $action_proc
+}
+
+# Returns whether an action expects text arguments at all,
+# expects text arguments or wants an expanded list of ports
+# Return values are constants:
+#   [ACTION_ARGS_NONE]     Does not expect any text argument
+#   [ACTION_ARGS_STRINGS]  Expects some strings as text argument
+#   [ACTION_ARGS_PORTS]    Wants an expanded list of ports as text argument
+proc action_needs_portlist { action } {
+    global action_array
+
+    set ret 0
+    if {[info exists action_array($action)]} {
+        set ret [lindex $action_array($action) 1]
+    }
+
+    return $ret
+}
+
+# cmd_opts_array specifies which arguments the commands accept
+# Commands not listed here do not accept any arguments
+# Syntax if {option argn}
+# Where option is the name of the option and argn specifies how many arguments
+# this argument takes
+global cmd_opts_array
+array set cmd_opts_array {
+    edit        {{editor 1}}
+    info        {category categories depends_fetch depends_extract
+                 depends_build depends_lib depends_run
+                 depends description epoch fullname heading homepage index license
+                 line long_description
+                 maintainer maintainers name platform platforms portdir pretty
+                 replaced_by revision subports variant variants version}
+    contents    {size {units 1}}
+    deps        {index no-build}
+    rdeps       {index no-build full}
+    rdependents {full}
+    search      {case-sensitive category categories depends_fetch
+                 depends_extract depends_build depends_lib depends_run
+                 depends description epoch exact glob homepage line
+                 long_description maintainer maintainers name platform
+                 platforms portdir regex revision variant variants version}
+    selfupdate  {nosync}
+    space       {{units 1} total}
+    activate    {no-exec}
+    deactivate  {no-exec}
+    install     {no-rev-upgrade unrequested}
+    uninstall   {follow-dependents follow-dependencies no-exec}
+    variants    {index}
+    clean       {all archive dist work logs}
+    mirror      {new}
+    lint        {nitpick}
+    select      {list set show summary}
+    log         {{phase 1} {level 1}}
+    upgrade     {force enforce-variants no-replace no-rev-upgrade}
+    rev-upgrade {id-loadcmd-check}
+    doctor      {quiet}
+}
+
+##
+# Checks whether the given option is valid
+#
+# @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} {
+    global cmd_opts_array
+
+    # This could be so easy with lsearch -index,
+    # but that's only available as of Tcl 8.5
+
+    if {![info exists cmd_opts_array($action)]} {
+        return {}
+    }
+
+    set result {}
+
+    foreach item $cmd_opts_array($action) {
+        if {[llength $item] == 1} {
+            set name $item
+            set argc 0
+        } else {
+            set name [lindex $item 0]
+            set argc [lindex $item 1]
+        }
+
+        if {$name == $option} {
+            set result [list [list $name $argc]]
+            break
+        } elseif {[string first $option $name] == 0} {
+            lappend result [list $name $argc]
+        }
+    }
+
+    return $result
+}
+
+# Parse global options
+#
+# Note that this is called several times:
+#   (1) Initially, to parse options that will be constant across all commands
+#       (options that come prior to any command, frozen into global_options_base)
+#   (2) Following each command (to parse options that will be unique to that command
+#       (the global_options array is reset to global_options_base prior to each command)
+#
+proc parse_options { action ui_options_name global_options_name } {
+    upvar $ui_options_name ui_options
+    upvar $global_options_name global_options
+    global cmdname cmd_opts_array
+    
+    while {[moreargs]} {
+        set arg [lookahead]
+        
+        if {[string index $arg 0] ne "-"} {
+            break
+        } elseif {[string index $arg 1] eq "-"} {
+            # Process long arguments
+            switch -- $arg {
+                -- { # This is the options terminator; do no further option processing
+                    advance; break
+                }
+                default {
+                    set key [string range $arg 2 end]
+                    set kopts [cmd_option_matches $action $key]
+                    if {[llength $kopts] == 0} {
+                        return -code error "${action} does not accept --${key}"
+                    } elseif {[llength $kopts] > 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst "--[lindex $e 0]"
+                        }
+                        return -code error "\"port ${action} --${key}\" is ambiguous: \n  port ${action} [join $errlst "\n  port ${action} "]"
+                    }
+                    set key   [lindex $kopts 0 0]
+                    set kargc [lindex $kopts 0 1]
+                    if {$kargc == 0} {
+                        set global_options(ports_${action}_${key}) yes
+                    } else {
+                        set args {}
+                        while {[moreargs] && $kargc > 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc > 0} {
+                            return -code error "--${key} expects [expr {$kargc + [llength $args]}] parameters!"
+                        }
+                        set global_options(ports_${action}_${key}) $args
+                    }
+                }
+            }
+        } else {
+            # Process short arg(s)
+            set opts [string range $arg 1 end]
+            foreach c [split $opts {}] {
+                switch -- $c {
+                    v {
+                        set ui_options(ports_verbose) yes
+                    }
+                    d {
+                        set ui_options(ports_debug) yes
+                        # debug implies verbose
+                        set ui_options(ports_verbose) yes
+                    }
+                    q {
+                        set ui_options(ports_quiet) yes
+                    }
+                    p {
+                        # Ignore errors while processing within a command
+                        set ui_options(ports_processall) yes
+                    }
+                    f {
+                        set global_options(ports_force) yes
+                    }
+                    o {
+                        set global_options(ports_ignore_different) yes
+                    }
+                    n {
+                        set global_options(ports_nodeps) yes
+                    }
+                    u {
+                        set global_options(port_uninstall_old) yes
+                    }
+                    R {
+                        set global_options(ports_do_dependents) yes
+                    }
+                    s {
+                        set global_options(ports_source_only) yes
+                    }
+                    b {
+                        set global_options(ports_binary_only) yes
+                    }
+                    c {
+                        set global_options(ports_autoclean) yes
+                    }
+                    k {
+                        set global_options(ports_autoclean) no
+                    }
+                    t {
+                        set global_options(ports_trace) yes
+                    }
+                    y {
+                        set global_options(ports_dryrun) yes
+                    }
+                    F {
+                        # Name a command file to process
+                        advance
+                        if {[moreargs]} {
+                            lappend ui_options(ports_commandfiles) [lookahead]
+                        }
+                    }
+                    D {
+                        advance
+                        if {[moreargs]} {
+                            cd [lookahead]
+                        }
+                        break
+                    }
+                    default {
+                        print_usage; exit 1
+                    }
+                }
+            }
+        }
+
+        advance
+    }
+}
+
+# acquire exclusive registry lock for actions that need it
+# returns 1 if locked, 0 otherwise
+proc lock_reg_if_needed {action} {
+    switch -- $action {
+        activate -
+        deactivate -
+        setrequested -
+        unsetrequested -
+        upgrade -
+        uninstall -
+        install {
+            registry::exclusive_lock
+            return 1
+        }
+    }
+    return 0
+}
+
+proc process_cmd { argv } {
+    global cmd_argc cmd_argv cmd_argn \
+           global_options global_options_base private_options ui_options \
+           current_portdir
+    set cmd_argv $argv
+    set cmd_argc [llength $argv]
+    set cmd_argn 0
+
+    set action_status 0
+
+    # Process an action if there is one
+    while {($action_status == 0 || [macports::ui_isset ports_processall]) && [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == ";" } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == "#" } {
+            while { [moreargs] } { advance }
+            break
+        }
+
+        set locked [lock_reg_if_needed $action]
+        # Always start out processing an action in current_portdir
+        cd $current_portdir
+        
+        # Reset global_options from base before each action, as we munge it just below...
+        array unset global_options
+        array set global_options $global_options_base
+        
+        # Find an action to execute
+        set actions [find_action $action]
+        if {[llength $actions] == 1} {
+            set action [lindex $actions 0]
+            set action_proc [get_action_proc $action]
+        } else {
+            if {[llength $actions] > 1} {
+                ui_error "\"port ${action}\" is ambiguous: \n  port [join $actions "\n  port "]"
+            } else {
+                ui_error "Unrecognized action \"port $action\""
+            }
+            set action_status 1
+            break
+        }
+
+        # Parse options that will be unique to this action
+        # (to avoid abiguity with -variants and a default port, either -- must be
+        # used to terminate option processing, or the pseudo-port current must be specified).
+        if {[catch {parse_options $action ui_options global_options} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            ui_error $result
+            set action_status 1
+            break
+        }
+
+        # What kind of arguments does the command expect?
+        set expand [action_needs_portlist $action]
+
+        # Parse action arguments, setting a special flag if there were none
+        # We otherwise can't tell the difference between arguments that evaluate
+        # to the empty set, and the empty set itself.
+        set portlist {}
+        switch -- [lookahead] {
+            ;       -
+            _EOF_ {
+                set private_options(ports_no_args) yes
+            }
+            default {
+                if {[ACTION_ARGS_NONE] == $expand} {
+                    ui_error "$action does not accept string arguments"
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] && ![match ";"] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error "Improper expression syntax while processing parameters"
+                        set action_status 1
+                        break
+                    }
+                }
+            }
+        }
+        
+        # execute the action
+        set action_status [$action_proc $action $portlist [array get global_options]]
+
+        # unlock if needed
+        if {$locked} {
+            registry::exclusive_unlock
+        }
+
+        # Print notifications of just-activated ports.
+        portclient::notifications::display
+
+        # semaphore to exit
+        if {$action_status == -999} break
+    }
+    
+    return $action_status
+}
+
+
+proc complete_portname { text state } { 
+    global complete_choices complete_position
+    
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices {}
+
+        # Build a list of ports with text as their prefix
+        if {[catch {set res [mportsearch "${text}*" false glob]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "search for portname $pattern failed: $result"
+        }
+        foreach {name info} $res {
+            lappend complete_choices $name
+        }
+    }
+    
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+    
+    return $word
+}
+
+
+# return text action beginning with $text
+proc complete_action { text state } {   
+    global action_array complete_choices complete_position
+
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices [array names action_array "[string tolower $text]*"]
+    }
+
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+
+    return $word
+}
+
+# return all actions beginning with $text
+proc guess_action { text } {   
+    global action_array
+
+    return [array names action_array "[string tolower $text]*"]
+
+    if { [llength $complete_choices ] == 1 } {
+        return [lindex $complete_choices 0]
+    }
+
+    return {}
+}
+
+proc attempt_completion { text word start end } {
+    # If the word starts with '~', or contains '.' or '/', then use the build-in
+    # completion to complete the word
+    if { [regexp {^~|[/.]} $word] } {
+        return ""
+    }
+
+    # Decide how to do completion based on where we are in the string
+    set prefix [string range $text 0 [expr {$start - 1}]]
+    
+    # If only whitespace characters preceed us, or if the
+    # previous non-whitespace character was a ;, then we're
+    # an action (the first word of a command)
+    if { [regexp {(^\s*$)|(;\s*$)} $prefix] } {
+        return complete_action
+    }
+    
+    # Otherwise, do completion on portname
+    return complete_portname
+}
+
+
+proc get_next_cmdline { in out use_readline prompt linename } {
+    upvar $linename line
+    
+    set line ""
+    while { $line eq "" } {
+
+        if {$use_readline} {
+            set len [readline read -attempted_completion attempt_completion line $prompt]
+        } else {
+            puts -nonewline $out $prompt
+            flush $out
+            set len [gets $in line]
+        }
+
+        if { $len < 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline && $line ne "" } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in "stdin"]
+    set name "port"
+    set use_readline [expr {$isstdin && [readline init $name]}]
+    set history_file [file normalize "${macports::macports_user_dir}/history"]
+
+    # Read readline history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin && ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts "MacPorts [macports::version]"
+        puts "Entering interactive mode... (\"help\" for help, \"quit\" to quit)"
+    }
+
+    # Main command loop
+    set exit_status 0
+    while { $exit_status == 0 || $isstdin || [macports::ui_isset ports_processall] } {
+
+        # Calculate our prompt
+        if { $noisy } {
+            set shortdir [eval file join [lrange [file split $current_portdir] end-1 end]]
+            set prompt "\[$shortdir\] > "
+        } else {
+            set prompt ""
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] <= 0  } {
+            puts ""
+            break
+        }
+
+        # Process the command
+        set exit_status [process_cmd $line]
+        
+        # Check for semaphore to exit
+        if {$exit_status == -999} {
+            set exit_status 0
+            break
+        }
+    }
+
+    # Create macports user directory if it does not exist yet
+    if {$use_readline && ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts "Goodbye"
+    }
+
+    return $exit_status
+}
+
+
+proc process_command_files { filelist } {
+    set exit_status 0
+
+    # For each file in the command list, process commands
+    # in the file
+    foreach file $filelist {
+        if {$file eq "-"} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal "Failed to open command file; $result"
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne "stdin"} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 && ![macports::ui_isset ports_processall]} {
+            return $exit_status
+        }
+    }
+
+    return $exit_status
+}
+
+namespace eval portclient::progress {
+    ##
+    # Maximum width of the progress bar or indicator when displaying it.
+    variable maxWidth 50
+
+    ##
+    # The start time of the last progress callback as returned by [clock time].
+    # Since only one progress indicator is active at a time, this variable is
+    # shared between the different variants of progress functions.
+    variable startTime
+
+    ##
+    # Delay in milliseconds after the start of the operation before deciding
+    # that showing a progress bar makes sense.
+    variable showTimeThreshold 500
+
+    ##
+    # Percentage value between 0 and 1 that must not have been reached yet when
+    # $showTimeThreshold has passed for a progress bar to be shown. If the
+    # operation has proceeded above e.g. 75% after 500ms we won't bother
+    # displaying a progress indicator anymore -- the operation will be finished
+    # in well below a second anyway.
+    variable showPercentageThreshold 0.75
+
+    ##
+    # Boolean indication whether the progress indicator should be shown or is
+    # still hidden because the current operation didn't need enough time for
+    # a progress indicator to make sense, yet.
+    variable show no
+
+    ##
+    # Initialize the progress bar display delay; call this from the start
+    # action of the progress functions.
+    proc initDelay {} {
+        variable show
+        variable startTime
+
+        set startTime [clock milliseconds]
+        set show no
+    }
+
+    ##
+    # Determine whether a progress bar should be shown for the current
+    # operation in its current state. You must have called initDelay for the
+    # current operation before calling this method.
+    #
+    # @param cur
+    #        Current progress in abstract units.
+    # @param total
+    #        Total number of abstract units to be processed, if known. Pass
+    #        0 if unknown.
+    # @return
+    #        "yes", if the progress indicator should be shown, "no" otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq "yes"} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] > $showTimeThreshold &&
+                ($total == 0 || [expr {double($cur) / double($total)}] < $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of "start", "update", "intermission" or "finish", where start
+    #        will be called before any number of update calls, interrupted by
+    #        any number of intermission calls (called because other output is
+    #        being produced), followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        "intermission" and "finish", the args are empty and unused. For
+    #        "update", args contains $cur and $total, where $cur is the current
+    #        number of units processed and $total is the total number of units
+    #        to be processed. If the total is not known, it is 0.
+    proc generic {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {now total} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            progressbar $now $total [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        } else {
+                            unprogressbar [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        }
+                    }
+                }
+            }
+            intermission -
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of "start", "update" or "finish", where start will be called
+    #        before any number of update calls, followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        contains a single argument "ul" or "dl" indicating whether this is
+    #        an up- or download. For "update", contains the arguments
+    #        ("ul"|"dl") $total $now $speed where ul/dl are as for start, and
+    #        total, now and speed are doubles indicating the total transfer
+    #        size, currently transferred amount and average speed per second in
+    #        bytes. Unused for "finish".
+    proc download {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {type total now speed} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format "        speed: %-13s" "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format " %-10s     speed: %-13s" [bytesize $now {} "%6.1f"] "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            unprogressbar $barLen $barPrefix $barSuffix
+                        }
+                    }
+                }
+            }
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Draw a progress bar using unicode block drawing characters
+    #
+    # @param current
+    #        The current progress value.
+    # @param total
+    #        The progress value representing 100%.
+    # @param width
+    #        The width in characters of the progress bar. This includes percentage
+    #        output, which takes up 8 characters.
+    # @param prefix
+    #        Prefix to be printed in front of the progress bar.
+    # @param suffix
+    #        Suffix to be printed after the progress bar.
+    proc progressbar {current total width {prefix ""} {suffix ""}} {
+        # Subtract the width of the percentage output, also subtract the two
+        # characters [ and ] bounding the progress bar.
+        set percentageWidth 8
+        set barWidth      [expr {entier($width) - $percentageWidth - 2}]
+
+        # Map the range (0, $total) to (0, 4 * $width) where $width is the maximum
+        # numebr of characters to be printed for the progress bar. Multiply the
+        # upper bound with 8 because we have 8 sub-states per character.
+        set barProgress   [expr {entier(round(($current * $barWidth * 8) / $total))}]
+
+        set barInteger    [expr {$barProgress / 8}]
+        #set barRemainder  [expr {$barProgress % 8}]
+
+        # Finally, also provide a percentage value to print behind the progress bar
+        set percentage [expr {double($current) * 100 / double($total)}]
+
+        # clear the current line, enable reverse video
+        set progressbar "\033\[7m"
+        for {set i 0} {$i < $barInteger} {incr i} {
+            # U+2588 FULL BLOCK doesn't match the other blocks in some fonts :/
+            # Two half blocks work better in some fonts, but not in others (because
+            # they leave ugly spaces). So, one or the other choice isn't better or
+            # worse and even just using full blocks looks ugly in a few fonts.
+
+            # Use pure ASCII until somebody fixes most of the default terminal fonts :/
+            append progressbar " "
+        }
+        # back to normal output
+        append progressbar "\033\[0m"
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger < $barWidth} {
+        #            append progressbar " "
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar "\u258f"
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar "\u258e"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar "\u258c"
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar "\u258b"
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar "\u258a"
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar "\u2589"
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i < $barWidth} {incr i} {
+            append progressbar " "
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format " %[expr {$percentageWidth - 3}].1f %%" $percentage]
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}"
+        flush stdout
+    }
+
+
+    ##
+    # Internal state of the progress indicator; unless you're hacking the
+    # unprogressbar code you should never touch this.
+    variable unprogressState 0
+
+    ##
+    # Draw a progress indicator
+    #
+    # @param width
+    #        The width in characters of the progress indicator.
+    # @param prefix
+    #        Prefix to be printed in front of the progress indicator.
+    # @param suffix
+    #        Suffix to be printed after the progress indicator.
+    proc unprogressbar {width {prefix ""} {suffix ""}} {
+        variable unprogressState
+
+        # Subtract the two characters [ and ] bounding the progress indicator
+        # from the width.
+        set barWidth [expr {int($width) - 2}]
+
+        # Number of states of the progress bar, or rather: the number of
+        # characters before the sequence repeats.
+        set numStates 4
+
+        set unprogressState [expr {($unprogressState + 1) % $numStates}]
+
+        set progressbar ""
+        for {set i 0} {$i < $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar "\u2022"
+            } else {
+                append progressbar " "
+            }
+        }
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${suffix}"
+        flush stdout
+    }
+}
+
+namespace eval portclient::notifications {
+    ##
+    # Ports whose notifications to display; these were either installed
+    # or requested to be installed.
+    variable notificationsToPrint
+    array set notificationsToPrint {}
+
+    ##
+    # Add a port to the list for printing notifications.
+    #
+    # @param name
+    #        The name of the port.
+    # @param note
+    #        A list of notes to be stored for the given port.
+    proc append {name notes} {
+        variable notificationsToPrint
+
+        set notificationsToPrint($name) $notes
+    }
+
+    ##
+    # Print port notifications.
+    #
+    proc display {} {
+        global env
+        variable notificationsToPrint
+
+        # Display notes at the end of the activation phase.
+        if {[array size notificationsToPrint] > 0} {
+            ui_notice "--->  Some of the ports you installed have notes:"
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice "  $name has the following notes:"
+
+                # If env(COLUMNS) exists, limit each line's width to this width.
+                if {[info exists env(COLUMNS)]} {
+                    set maxlen $env(COLUMNS)
+
+                    foreach note $notes {
+                        foreach line [split $note "\n"] {
+                            set joiner ""
+                            set lines ""
+                            set newline "    "
+
+                            foreach word [split $line " "] {
+                                if {[string length $newline] + [string length $word] >= $maxlen} {
+                                    lappend lines $newline
+                                    set newline "    "
+                                    set joiner ""
+                                }
+                                ::append newline $joiner $word
+                                set joiner " "
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines "\n"]
+                        }
+                    }
+                } else {
+                    foreach note $notes {
+                        ui_notice $note
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+##########################################
+# Main
+##########################################
+
+# Global arrays passed to the macports1.0 layer
+array set ui_options        {}
+array set global_options    {}
+array set global_variations {}
+
+# Global options private to this script
+array set private_options {}
+
+# Make sure we get the size of the terminal
+# We do this here to save it in the boot_env, in case we determined it manually
+term_init_size
+
+global env boot_env argv0 cmdname argc argv cmd_argc cmd_argv cmd_argn \
+       current_portdir global_options_base exit_status
+
+# Save off a copy of the environment before mportinit monkeys with it
+array set boot_env [array get env]
+
+set cmdname [file tail $argv0]
+
+# Setp cmd_argv to match argv
+set cmd_argv $argv
+set cmd_argc $argc
+set cmd_argn 0
+
+# make sure we're using a sane umask
+umask 022
+
+# If we've been invoked as portf, then the first argument is assumed
+# to be the name of a command file (i.e., there is an implicit -F
+# before any arguments).
+if {[moreargs] && $cmdname eq "portf"} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options "global" ui_options global_options} result]} {
+    puts "Error: $result"
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    && $portclient::progress::hasTermAnsiSend eq "yes"
+    && (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne "yes")} {
+    set ui_options(progress_download) portclient::progress::download
+    set ui_options(progress_generic)  portclient::progress::generic
+}
+
+set ui_options(notifications_append) portclient::notifications::append
+
+# Get arguments remaining after option processing
+set remaining_args [lrange $cmd_argv $cmd_argn end]
+
+# If we have no arguments remaining after option processing then force
+# interactive mode
+if { [llength $remaining_args] == 0 && ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq "selfupdate" || [lookahead] eq "sync"} {
+    # tell mportinit not to tell the user they should selfupdate
+    set ui_options(ports_no_old_index_warning) 1
+}
+
+# Initialize mport
+# This must be done following parse of global options, as some options are
+# evaluated by mportinit.
+if {[catch {mportinit ui_options global_options global_variations} result]} {
+    global errorInfo
+    puts "$errorInfo"
+    fatal "Failed to initialize MacPorts, $result"
+}
+
+# Set up some global state for our code
+set current_portdir [pwd]
+
+# Freeze global_options into global_options_base; global_options
+# will be reset to global_options_base prior to processing each command.
+set global_options_base [array get global_options]
+
+# First process any remaining args as action(s)
+set exit_status 0
+if { [llength $remaining_args] > 0 } {
+
+    # If there are remaining arguments, process those as a command
+    set exit_status [process_cmd $remaining_args]
+}
+
+# Process any prescribed command files, including standard input
+if { ($exit_status == 0 || [macports::ui_isset ports_processall]) && [info exists ui_options(ports_commandfiles)] } {
+    set exit_status [process_command_files $ui_options(ports_commandfiles)]
+}
+if {$exit_status == -999} {
+    set exit_status 0
+}
+
+# shut down macports1.0
+mportshutdown
+
+# Return with exit_status
+exit $exit_status

Added: branches/gsoc14-cleanup/src/port/port.BASE.23878
===================================================================
--- branches/gsoc14-cleanup/src/port/port.BASE.23878	                        (rev 0)
+++ branches/gsoc14-cleanup/src/port/port.BASE.23878	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,5343 @@
+#!/opt/local/libexec/macports/bin/tclsh8.5
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
+# $Id: port.tcl 119177 2014-04-18 22:35:29Z cal at macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw <rshaw at opendarwin.org>
+# Copyright (c) 2002-2003 Apple Inc.
+# 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.
+# 3. Neither the name of Apple Inc. nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+# Create a namespace for some local variables
+namespace eval portclient::progress {
+    ##
+    # Indicate whether the term::ansi::send tcllib package is available and was
+    # imported. "yes", if the package is available, "no" otherwise.
+    variable hasTermAnsiSend no
+}
+
+if {![catch {package require term::ansi::send}]} {
+    set portclient::progress::hasTermAnsiSend yes
+}
+
+package require macports
+package require reclaim 1.0
+package require Pextlib 1.0
+
+# Standard procedures
+proc print_usage {{verbose 1}} {
+    global cmdname
+    set syntax {
+        [-bcdfknopqRstuvy] [-D portdir] [-F cmdfile] action [privopts] [actionflags]
+        [[portname|pseudo-portname|port-url] [@version] [+-variant]... [option=value]...]...
+    }
+
+    if {$verbose} {
+        puts stderr "Usage: $cmdname$syntax"
+        puts stderr "\"$cmdname help\" or \"man 1 port\" for more information."
+    } else {
+        puts stderr "$cmdname$syntax"
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds ""
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen > 65} {
+            set cmds "$cmds,\n"
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new "$cmd"
+        } else {
+            set new ", $cmd"
+        }
+        incr lineLen [string length $new]
+        set cmds "$cmds$new"
+    }
+
+    set cmdText "Supported actions
+------------------
+$cmds
+"
+
+    set text {
+Pseudo-portnames
+----------------
+Pseudo-portnames are words that may be used in place of a portname, and
+which expand to some set of ports. The common pseudo-portnames are:
+all, current, active, inactive, actinact, installed, uninstalled, outdated,
+obsolete, requested, unrequested and leaves.
+These pseudo-portnames expand to the set of ports named.
+
+Pseudo-portnames starting with variants:, variant:, description:, depends:,
+depends_lib:, depends_run:, depends_build:, depends_fetch:, depends_extract:,
+portdir:, homepage:, epoch:, platforms:, platform:, name:, long_description:,
+maintainers:, maintainer:, categories:, category:, version:, revision:, and
+license: each select a set of ports based on a regex search of metadata
+about the ports. In all such cases, a standard regex pattern following
+the colon will be used to select the set of ports to which the
+pseudo-portname expands.
+
+Pseudo-portnames starting with depof:, rdepof:, dependentof:, and rdependentof:
+select ports that are direct or recursive dependencies or dependents of the
+following portname, respectively.
+
+Portnames that contain standard glob characters will be expanded to the
+set of ports matching the glob pattern.
+    
+Port expressions
+----------------
+Portnames, port glob patterns, and pseudo-portnames may be logically
+combined using expressions consisting of and, or, not, !, (, and ).
+    
+For more information
+--------------------
+See man pages: port(1), macports.conf(5), portfile(7), portgroup(7),
+porthier(7), portstyle(7). Also, see http://www.macports.org.
+    }
+
+    puts "$cmdText$text"
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error "$argv0: $s"
+    exit 1
+}
+
+##
+# Helper function to define constants
+#
+# Constants defined with const can simply be accessed in the same way as
+# calling a proc.
+#
+# Example:
+# const FOO 42
+# puts [FOO]
+#
+# @param name variable name
+# @param value constant variable value
+proc const {name args} {
+    proc $name {} [list return [expr $args]]
+}
+
+# Format an integer representing bytes using given units
+proc bytesize {siz {unit {}} {format {%.3f}}} {
+    if {$unit == {}} {
+        if {$siz > 0x40000000} {
+            set unit "GiB"
+        } elseif {$siz > 0x100000} {
+            set unit "MiB"
+        } elseif {$siz > 0x400} {
+            set unit "KiB"
+        } else {
+            set unit "B"
+        }
+    }
+    switch -- $unit {
+        KiB {
+            set siz [expr {$siz / 1024.0}]
+        }
+        kB {
+            set siz [expr {$siz / 1000.0}]
+        }
+        MiB {
+            set siz [expr {$siz / 1048576.0}]
+        }
+        MB {
+            set siz [expr {$siz / 1000000.0}]
+        }
+        GiB {
+            set siz [expr {$siz / 1073741824.0}]
+        }
+        GB {
+            set siz [expr {$siz / 1000000000.0}]
+        }
+        B { }
+        default {
+            ui_warn "Unknown file size unit '$unit' specified"
+            set unit "B"
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return "$siz $unit"
+}
+
+proc filesize {fil {unit {}}} {
+    set siz {@}
+    catch {
+        set siz [bytesize [file size $fil] $unit]
+    }
+    return $siz
+}
+
+# Produce an error message, and exit, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc fatal_softcontinue s {
+    if {[macports::global_option_isset ports_force]} {
+        ui_error $s
+        return -code continue
+    } else {
+        fatal $s
+    }
+}
+
+
+# Produce an error message, and break, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc break_softcontinue { msg status name_status } {
+    upvar $name_status status_var 
+    ui_error $msg
+    if {[macports::ui_isset ports_processall]} {
+        set status_var 0
+        return -code continue
+    } else {
+        set status_var $status
+        return -code break
+    }
+}
+
+# show the URL for the ticket reporting instructions
+proc print_tickets_url {args} {
+    if {${macports::prefix} ne "/usr/local" && ${macports::prefix} ne "/usr"} {
+        ui_error "Follow http://guide.macports.org/#project.tickets to report a bug."
+    }
+}
+
+# Form a composite version as is sometimes used for registry functions
+# This function sorts the variants and presents them in a canonical representation
+proc composite_version {version variations {emptyVersionOkay 0}} {
+    # Form a composite version out of the version and variations
+    
+    # Select the variations into positive and negative
+    set pos {}
+    set neg {}
+    foreach { key val } $variations {
+        if {$val eq "+"} {
+            lappend pos $key
+        } elseif {$val eq "-"} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version ""
+    if {$version ne "" || $emptyVersionOkay} {
+        set pos_str ""
+        set neg_str ""
+
+        if {[llength $pos]} {
+            set pos_str "+[join [lsort -ascii $pos] "+"]"
+        }
+        if {[llength $neg]} {
+            set neg_str "-[join [lsort -ascii $neg] "-"]"
+        }
+
+        set composite_version "$version$pos_str$neg_str"
+    }
+
+    return $composite_version
+}
+
+
+proc split_variants {variants} {
+    set result {}
+    set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
+    foreach { match sign variant } $l {
+        lappend result $variant $sign
+    }
+    return $result
+}
+
+
+##
+# Maps friendly field names to their real name
+# Names which do not need mapping are not changed.
+#
+# @param field friendly name
+# @return real name
+proc map_friendly_field_names { field } {
+    switch -- $field {
+        variant -
+        platform -
+        maintainer -
+        subport {
+            set field "${field}s"
+        }
+        category {
+            set field "categories"
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion ""}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] > 1 } {
+        # set portname again since the one we were passed may not have had the correct case
+        set portname [lindex $ilist 0 0]
+        ui_notice "The following versions of $portname are currently installed:"
+        foreach i [portlist_sortint $ilist] { 
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants} (active)"
+            }
+        }
+        return -code error "Registry error: Please specify the full version as recorded in the port registry."
+    } else {
+        return [lindex $ilist 0]
+    }
+}
+
+
+proc entry_for_portlist {portentry} {
+    global global_options global_variations
+
+    # Each portlist entry currently has the following elements in it:
+    #   url             if any
+    #   name
+    #   version         (version_revision)
+    #   variants array  (variant=>+-)
+    #   requested_variants array  (variant=>+-)
+    #   options array   (key=>value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) "" }
+    if {![info exists port(name)]}      { set port(name) "" }
+    if {![info exists port(version)]}   { set port(version) "" }
+    if {![info exists port(variants)]}  { set port(variants) "" }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) "" }
+    if {![info exists port(options)]}   { set port(options) [array get global_options] }
+
+    # If neither portname nor url is specified, then default to the current port
+    if { $port(url) eq "" && $port(name) eq "" } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq ""} {
+            ui_error "A default port name could not be supplied."
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) "$port(name)/[composite_version $port(version) $port(variants)]"
+    
+    return [array get port]
+}
+
+
+proc add_to_portlist {listname portentry} {
+    upvar $listname portlist
+    
+    # Form portlist entry and add to portlist
+    lappend portlist [entry_for_portlist $portentry]
+}
+
+
+proc add_ports_to_portlist {listname ports {overridelist ""}} {
+    upvar $listname portlist
+
+    array set overrides $overridelist
+
+    # Add each entry to the named portlist, overriding any values
+    # specified as overrides
+    foreach portentry $ports {
+        array set port $portentry
+        if ([info exists overrides(version)])   { set port(version) $overrides(version) }
+        if ([info exists overrides(variants)])  { set port(variants) $overrides(variants) }
+        if ([info exists overrides(requested_variants)])  { set port(requested_variants) $overrides(requested_variants) }
+        if ([info exists overrides(options)])   { set port(options) $overrides(options) }
+        add_to_portlist portlist [array get port]
+    }
+}
+
+
+proc url_to_portname { url {quiet 0} } {
+    # Save directory and restore the directory, since mportopen changes it
+    set savedir [pwd]
+    set portname ""
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg "Can't map the URL '$url' to a port description file (\"${result}\")."
+            ui_msg "Please verify that the directory and portfile syntax are correct."
+        }
+    } else {
+        array set portinfo [mportinfo $ctx]
+        set portname $portinfo(name)
+        mportclose $ctx
+    }
+    cd $savedir
+    return $portname
+}
+
+
+# Supply a default porturl/portname if the portlist is empty
+proc require_portlist { nameportlist {is_upgrade "no"} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 && (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        if {${is_upgrade} == "yes"} {
+            # $> port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # "upgrade", let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg "Nothing to upgrade."
+            return 1
+        }
+        ui_error "No ports matched the given expression"
+        return 1
+    }
+
+    if {[llength $portlist] == 0} {
+        set portlist [get_current_port]
+
+        if {[llength $portlist] == 0} {
+            # there was no port in current directory
+            return 1
+        }
+    }
+
+    return 0
+}
+
+
+# Execute the enclosed block once for every element in the portlist
+# When the block is entered, the following variables will have been set:
+#   portspec, porturl, portname, portversion, options, variations, requested_variations
+proc foreachport {portlist block} {
+    set savedir [pwd]
+    foreach portspec $portlist {
+    
+        # Set the variables for the block
+        uplevel 1 "array unset portspec; array set portspec { $portspec }"
+        uplevel 1 {
+            set porturl $portspec(url)
+            set portname $portspec(name)
+            set portversion $portspec(version)
+            array unset variations
+            array set variations $portspec(variants)
+            array unset requested_variations
+            array set requested_variations $portspec(requested_variants)
+            array unset options
+            array set options $portspec(options)
+        }
+        
+        # Invoke block
+        uplevel 1 $block
+        
+        # Restore cwd after each port, since mportopen changes it, and otherwise relative
+        # urls would break on subsequent passes
+        if {[file exists $savedir]} {
+            cd $savedir
+        } else {
+            cd ~
+        }
+    }
+}
+
+
+proc portlist_compare { a b } {
+    array set a_ $a
+    array set b_ $b
+    set namecmp [string equal -nocase $a_(name) $b_(name)]
+    if {$namecmp != 1} {
+        if {$a_(name) eq [lindex [lsort -dictionary [list $a_(name) $b_(name)]] 0]} {
+            return -1
+        }
+        return 1
+    }
+    set avr_ [split $a_(version) "_"]
+    set bvr_ [split $b_(version) "_"]
+    set versioncmp [vercmp [lindex $avr_ 0] [lindex $bvr_ 0]]
+    if {$versioncmp != 0} {
+        return $versioncmp
+    }
+    set ar_ [lindex $avr_ 1]
+    set br_ [lindex $bvr_ 1]
+    if {$ar_ < $br_} {
+        return -1
+    } elseif {$ar_ > $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name at version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list "name" [lindex $a 0] "version" "[lindex $a 1]_[lindex $a 2]"]
+    array set b_ [list "name" [lindex $b 0] "version" "[lindex $b 1]_[lindex $b 2]"]
+    return [portlist_compare [array get a_] [array get b_]]
+}
+
+# Same as portlist_sort, but with numeric indexes {name version revision}
+proc portlist_sortint { list } {
+    return [lsort -command portlist_compareint $list]
+}
+
+# sort portlist so dependents come before their dependencies
+proc portlist_sortdependents { portlist } {
+    foreach p $portlist {
+        array set pvals $p
+        lappend entries($pvals(name)) $p
+        if {![info exists dependents($pvals(name))]} {
+            set dependents($pvals(name)) {}
+            foreach result [registry::list_dependents $pvals(name)] {
+                lappend dependents($pvals(name)) [lindex $result 2]
+            }
+        }
+        array unset pvals
+    }
+    set ret {}
+    foreach p $portlist {
+        portlist_sortdependents_helper $p entries dependents seen ret
+    }
+    return $ret
+}
+
+proc portlist_sortdependents_helper {p up_entries up_dependents up_seen up_retlist} {
+    upvar $up_seen seen
+    if {![info exists seen($p)]} {
+        set seen($p) 1
+        upvar $up_entries entries $up_dependents dependents $up_retlist retlist
+        array set pvals $p
+        foreach dependent $dependents($pvals(name)) {
+            if {[info exists entries($dependent)]} {
+                foreach entry $entries($dependent) {
+                    portlist_sortdependents_helper $entry entries dependents seen retlist
+                }
+            }
+        }
+        lappend retlist $p
+    }
+}
+
+proc regex_pat_sanitize { s } {
+    set sanitized [regsub -all {[\\(){}+$.^]} $s {\\&}]
+    return $sanitized
+}
+
+##
+# Makes sure we get the current terminal size
+proc term_init_size {} {
+    global env
+
+    if {![info exists env(COLUMNS)] || ![info exists env(LINES)]} {
+        if {[isatty stdout]} {
+            set size [term_get_size stdout]
+
+            if {![info exists env(LINES)] && [lindex $size 0] > 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] && [lindex $size 1] > 0} {
+                set env(COLUMNS) [lindex $size 1]
+            }
+        }
+    }
+}
+
+##
+# Wraps a multi-line string at specified textwidth
+#
+# @see wrapline
+#
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrap {string maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set splitstring {}
+    set indentline $indentfirstline
+    foreach line [split $string "\n"] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring "\n"]
+}
+
+##
+# Wraps a line at specified textwidth
+#
+# @see wrap
+#
+# @param line input line
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrapline {line maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set string [split $line " "]
+    if {$indentfirstline == 0} {
+        set newline ""
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner " "
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] >= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner ""
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 && $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner " "
+    }
+    lappend lines $newline
+    return [join $lines "\n"]
+}
+
+##
+# Wraps a line at a specified width with a label in front
+#
+# @see wrap
+#
+# @param label label for output
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @return wrapped string
+proc wraplabel {label string maxlen {indent ""}} {
+    append label ": [string repeat " " [expr {[string length $indent] - [string length "$label: "]}]]"
+    return "$label[wrap $string $maxlen $indent 0]"
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first "@" $m] < 0} {
+            if {[string first ":" $m] >= 0} {
+                set m [regsub -- "(.*):(.*)" $m "\\2@\\1"] 
+            } else {
+                set m "$m at macports.org"
+            }
+        }
+        lappend result $m
+    }
+    return $result
+}
+
+
+##########################################
+# Port selection
+##########################################
+proc unique_results_to_portlist {infos} {
+    set result {}
+    array unset unique
+    foreach {name info} $infos {
+        array unset portinfo
+        array set portinfo $info
+        
+        set portentry [entry_for_portlist [list url $portinfo(porturl) name $name]]
+        
+        array unset entry
+        array set entry $portentry
+        
+        if {[info exists unique($entry(fullname))]} continue
+        set unique($entry(fullname)) 1
+        
+        lappend result $portentry
+    }
+    return $result
+}
+
+
+proc get_matching_ports {pattern {casesensitive no} {matchstyle glob} {field name}} {
+    if {[catch {set res [mportsearch $pattern $casesensitive $matchstyle $field]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        fatal "search for portname $pattern failed: $result"
+    }
+    set results [unique_results_to_portlist $res]
+    
+    # Return the list of all ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_all_ports {} {
+    global all_ports_cache
+
+    if {![info exists all_ports_cache]} {
+         if {[catch {set res [mportlistall]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "listing all ports failed: $result"
+        }
+        set results [unique_results_to_portlist $res]
+        set all_ports_cache [portlist_sort $results]
+    }
+    return $all_ports_cache
+}
+
+
+proc get_current_ports {} {
+    # This is just a synonym for get_current_port that
+    # works with the regex in element
+    return [get_current_port]
+}
+
+
+proc get_current_port {} {
+    set url file://.
+    set portname [url_to_portname $url]
+    if {$portname eq ""} {
+        ui_msg "To use the current port, you must be in a port's directory."
+        return [list]
+    }
+
+    set results {}
+    add_to_portlist results [list url $url name $portname]
+    return $results
+}
+
+
+proc get_installed_ports { {ignore_active yes} {active yes} } {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [split_variants [lindex $i 3]]
+        set iactive [lindex $i 4]
+
+        if { ${ignore_active} == "yes" || (${active} == "yes") == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants $ivariants]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_uninstalled_ports {} {
+    # Return all - installed
+    set all [get_all_ports]
+    set installed [get_installed_ports]
+    return [opComplement $all $installed]
+}
+
+
+proc get_active_ports {} {
+    return [get_installed_ports no yes]
+}
+
+
+proc get_inactive_ports {} {
+    return [get_installed_ports no no]
+}
+
+proc get_actinact_ports {} {
+    set inactive_ports [get_inactive_ports]
+    set active_ports [get_active_ports]
+    set results {}
+
+    foreach port $inactive_ports {
+        array set portspec $port
+        set portname $portspec(name)
+        lappend inact($portname) $port
+    }
+
+    foreach port $active_ports {
+        array set portspec $port
+        set portname $portspec(name)
+
+        if {[info exists inact($portname)]} {
+            if {![info exists added_inact($portname)]} {
+                foreach inact_spec $inact($portname) {
+                    lappend results $inact_spec
+                }
+                set added_inact($portname) 1
+            }
+            lappend results $port
+        }
+    }
+    return $results
+}
+
+
+proc get_outdated_ports {} {
+    # Get the list of installed ports
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] > 0 } {
+        foreach i $ilist {
+
+            # Get information about the installed port
+            set portname            [lindex $i 0]
+            set installed_version   [lindex $i 1]
+            set installed_revision  [lindex $i 2]
+            set installed_compound  "${installed_version}_${installed_revision}"
+            set installed_variants  [lindex $i 3]
+
+            set is_active           [lindex $i 4]
+            if {$is_active == 0} continue
+
+            set installed_epoch     [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                fatal "lookup of portname $portname failed: $result"
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+
+            # Get information about latest available version and revision
+            set latest_version $portinfo(version)
+            set latest_revision     0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     "${latest_version}_${latest_revision}"
+            set latest_epoch        0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch    $portinfo(epoch)
+            }
+
+            # Compare versions, first checking epoch, then version, then revision
+            set comp_result 0
+            if {$installed_version != $latest_version} {
+                set comp_result [expr {$installed_epoch - $latest_epoch}]
+                if { $comp_result == 0 } {
+                    set comp_result [vercmp $installed_version $latest_version]
+                }
+            }
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            if {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision $installed_variants $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                }
+            }
+
+            # Add outdated ports to our results list
+            if { $comp_result < 0 } {
+                add_to_portlist results [list name $portname version $installed_compound variants [split_variants $installed_variants]]
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_obsolete_ports {} {
+    set ilist [get_installed_ports]
+    set results {}
+
+    foreach i $ilist {
+        array set port $i
+
+        if {[catch {mportlookup $port(name)} result]} {
+            ui_debug "$::errorInfo"
+            break_softcontinue "lookup of portname $portname failed: $result" 1 status
+        }
+
+        if {[llength $result] < 2} {
+            lappend results $i
+        }
+    }
+
+    # Return the list of ports, already sorted
+    return [portlist_sort $results]
+}
+
+# return ports that have registry property $propname set to $propval
+proc get_ports_with_prop {propname propval} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [lindex $i 3]
+        set iepoch [lindex $i 5]
+        set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
+        if {[registry::property_retrieve $regref $propname] == $propval} {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants [split_variants $ivariants]]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+proc get_requested_ports {} {
+    return [get_ports_with_prop requested 1]
+}
+
+proc get_unrequested_ports {} {
+    return [get_ports_with_prop requested 0]
+}
+
+proc get_leaves_ports {} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq ""} {
+            add_to_portlist results [list name $iname version "[lindex $i 1]_[lindex $i 2]" variants [split_variants [lindex $i 3]]]
+        }
+    }
+    return [portlist_sort [opIntersection $results [get_unrequested_ports]]]
+}
+
+proc get_dependent_ports {portname recursive} {
+    registry::open_dep_map
+    set deplist [registry::list_dependents $portname]
+    # could return specific versions here using registry2.0 features
+    set results {}
+    foreach dep $deplist {
+        add_to_portlist results [list name [lindex $dep 2]]
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex $dep 2]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    set rdeplist [registry::list_dependents $depname]
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex $rdep 2]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_dep_ports {portname recursive} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its deps
+    set results {}
+    set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+
+    set deplist {}
+    foreach type $deptypes {
+        if {[info exists portinfo($type)]} {
+            foreach dep $portinfo($type) {
+                add_to_portlist results [list name [lindex [split $dep :] end]]
+                lappend deplist $dep
+            }
+        }
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        return -code error "lookup of portname $depname failed: $result"
+                    }
+                    if {[llength $result] < 2} {
+                        ui_error "Port $depname not found"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                
+                    # open its portfile
+                    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+                        ui_debug "$::errorInfo"
+                        ui_error "Unable to open port: $result"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [mportinfo $mport]
+                    mportclose $mport
+
+                    # collect its deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                add_to_portlist results [list name [lindex [split $rdep :] end]]
+                                lappend rdeplist $rdep
+                            }
+                        }
+                    }
+
+                    # add them to the lists
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex [split $rdep :] end]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+proc get_subports {portname} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its subports
+    set results {}
+
+    if {[info exists portinfo(subports)]} {
+        foreach subport $portinfo(subports) {
+            add_to_portlist results [list name $subport]
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+##########################################
+# Port expressions
+##########################################
+proc portExpr { resname } {
+    upvar $resname reslist
+    set result [seqExpr reslist]
+    return $result
+}
+
+
+proc seqExpr { resname } {
+    upvar $resname reslist
+    
+    # Evaluate a sequence of expressions a b c...
+    # These act the same as a or b or c
+
+    set result 1
+    while {$result} {
+        switch -- [lookahead] {
+            ;       -
+            )       -
+            _EOF_   { break }
+        }
+
+        set blist {}
+        set result [orExpr blist]
+        if {$result} {
+            # Calculate the union of result and b
+            set reslist [opUnion $reslist $blist]
+        }
+    }
+    
+    return $result
+}
+
+
+proc orExpr { resname } {
+    upvar $resname reslist
+    
+    set a [andExpr reslist]
+    while ($a) {
+        switch -- [lookahead] {
+            or {
+                    advance
+                    set blist {}
+                    if {![andExpr blist]} {
+                        return 0
+                    }
+                        
+                    # Calculate a union b
+                    set reslist [opUnion $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc andExpr { resname } {
+    upvar $resname reslist
+    
+    set a [unaryExpr reslist]
+    while {$a} {
+        switch -- [lookahead] {
+            and {
+                    advance
+                    
+                    set blist {}
+                    set b [unaryExpr blist]
+                    if {!$b} {
+                        return 0
+                    }
+                    
+                    # Calculate a intersect b
+                    set reslist [opIntersection $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc unaryExpr { resname } {
+    upvar $resname reslist
+    set result 0
+
+    switch -- [lookahead] {
+        !   -
+        not {
+                advance
+                set blist {}
+                set result [unaryExpr blist]
+                if {$result} {
+                    set all [get_all_ports]
+                    set reslist [opComplement $all $blist]
+                }
+            }
+        default {
+                set result [element reslist]
+            }
+    }
+    
+    return $result
+}
+
+
+proc element { resname } {
+    upvar $resname reslist
+    set el 0
+    
+    set url ""
+    set name ""
+    set version ""
+    array unset requested_variants
+    array unset options
+    
+    set token [lookahead]
+    switch -regex -- $token {
+        ^\\)$               -
+        ^\;                 -
+        ^_EOF_$             { # End of expression/cmd/file
+        }
+
+        ^\\($               { # Parenthesized Expression
+            advance
+            set el [portExpr reslist]
+            if {!$el || ![match ")"]} {
+                set el 0
+            }
+        }
+
+        ^all(@.*)?$         -
+        ^installed(@.*)?$   -
+        ^uninstalled(@.*)?$ -
+        ^active(@.*)?$      -
+        ^inactive(@.*)?$    -
+        ^actinact(@.*)?$    -
+        ^leaves(@.*)?$      -
+        ^outdated(@.*)?$    -
+        ^obsolete(@.*)?$    -
+        ^requested(@.*)?$   -
+        ^unrequested(@.*)?$ -
+        ^current(@.*)?$     {
+            # A simple pseudo-port name
+            advance
+
+            # Break off the version component, if there is one
+            regexp {^(\w+)(@.*)?} $token matchvar name remainder
+
+            add_multiple_ports reslist [get_${name}_ports] $remainder
+
+            set el 1
+        }
+
+        ^variants:          -
+        ^variant:           -
+        ^description:       -
+        ^portdir:           -
+        ^homepage:          -
+        ^epoch:             -
+        ^platforms:         -
+        ^platform:          -
+        ^name:              -
+        ^long_description:  -
+        ^maintainers:       -
+        ^maintainer:        -
+        ^categories:        -
+        ^category:          -
+        ^version:           -
+        ^depends_lib:       -
+        ^depends_build:     -
+        ^depends_run:       -
+        ^depends_extract:   -
+        ^depends_fetch:     -
+        ^replaced_by:       -
+        ^revision:          -
+        ^subport:           -
+        ^subports:          -
+        ^license:           { # Handle special port selectors
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            # Remap friendly names to actual names
+            set field [map_friendly_field_names $field]
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp $field]
+            set el 1
+        }
+
+        ^depends:           { # A port selector shorthand for depends_{lib,build,run,fetch,extract}
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_lib"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_build"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_run"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_extract"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_fetch"]
+
+            set el 1
+        }
+
+        ^dependentof:       -
+        ^rdependentof:      {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdependentof"]
+            add_multiple_ports reslist [get_dependent_ports $portname $recursive]
+            
+            set el 1
+        }
+        
+        ^depof:             -
+        ^rdepof:            {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdepof"]
+            add_multiple_ports reslist [get_dep_ports $portname $recursive]
+            
+            set el 1
+        }
+
+        ^subportof:         {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            add_multiple_ports reslist [get_subports $portname]
+
+            set el 1
+        }
+
+        [][?*]              { # Handle portname glob patterns
+            advance; add_multiple_ports reslist [get_matching_ports $token no glob]
+            set el 1
+        }
+
+        ^\\w+:.+            { # Handle a url by trying to open it as a port and mapping the name
+            advance
+            set name [url_to_portname $token]
+            if {$name ne ""} {
+                parsePortSpec version requested_variants options
+                add_to_portlist reslist [list url $token \
+                  name $name \
+                  version $version \
+                  requested_variants [array get requested_variants] \
+                  variants [array get requested_variants] \
+                  options [array get options]]
+                set el 1
+            } else {
+                ui_error "Can't open URL '$token' as a port"
+                set el 0
+            }
+        }
+
+        default             { # Treat anything else as a portspec (portname, version, variants, options
+            # or some combination thereof).
+            parseFullPortSpec url name version requested_variants options
+            add_to_portlist reslist [list url $url \
+              name $name \
+              version $version \
+              requested_variants [array get requested_variants] \
+              variants [array get requested_variants] \
+              options [array get options]]
+            set el 1
+        }
+    }
+
+    return $el
+}
+
+
+proc add_multiple_ports { resname ports {remainder ""} } {
+    upvar $resname reslist
+    
+    set version ""
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne ""} { set overrides(version) $version }
+    if {[array size variants]} {
+        # we always record the requested variants separately,
+        # but requested ones always override existing ones
+        set overrides(requested_variants) [array get variants]
+        set overrides(variants) [array get variants]
+    }
+    if {[array size options]} { set overrides(options) [array get options] }
+
+    add_ports_to_portlist reslist $ports [array get overrides]
+}
+
+
+proc unique_entries { entries } {
+    # Form the list of all the unique elements in the list a,
+    # considering only the port fullname, and taking the first
+    # found element first
+    set result {}
+    array unset unique
+    foreach item $entries {
+        array set port $item
+        if {[info exists unique($port(fullname))]} continue
+        set unique($port(fullname)) 1
+        lappend result $item
+    }
+    return $result
+}
+
+
+proc opUnion { a b } {
+    # Return the unique elements in the combined two lists
+    return [unique_entries [concat $a $b]]
+}
+
+
+proc opIntersection { a b } {
+    set result {}
+    
+    # Rules we follow in performing the intersection of two port lists:
+    #
+    #   a/, a/          ==> a/
+    #   a/, b/          ==>
+    #   a/, a/1.0       ==> a/1.0
+    #   a/1.0, a/       ==> a/1.0
+    #   a/1.0, a/2.0    ==>
+    #
+    #   If there's an exact match, we take it.
+    #   If there's a match between simple and discriminated, we take the later.
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem [unique_entries $b] {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, matching against b
+    foreach aitem [unique_entries $a] {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+        foreach match $matches {
+            if {$simpleform} {
+                set i $bfull($match)
+                lappend result [lindex $b $i]
+            } else {
+                lappend result $aitem
+            }
+        }
+    }
+    
+    return $result
+}
+
+
+proc opComplement { a b } {
+    set result {}
+    
+    # Return all elements of a not matching elements in b
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem $b {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, taking all those items that don't match b
+    foreach aitem $a {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+
+        # We copy this element to result only if it didn't match against b
+        if {![llength $matches]} {
+            lappend result $aitem
+        }
+    }
+    
+    return $result
+}
+
+
+proc parseFullPortSpec { urlname namename vername varname optname } {
+    upvar $urlname porturl
+    upvar $namename portname
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    set portname ""
+    set portversion ""
+    array unset portvariants
+    array unset portoptions
+    
+    if { [moreargs] } {
+        # Look first for a potential portname
+        #
+        # We need to allow a wide variety of tokens here, because of actions like "provides"
+        # so we take a rather lenient view of what a "portname" is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder ""
+        if {![regexp {^(@|[-+]([[:alpha:]_]+[\w\.]*)|[[:alpha:]_]+[\w\.]*=)} $token match]} {
+            advance
+            regexp {^([^@]+)(@.*)?} $token match portname remainder
+            
+            # If the portname contains a /, then try to use it as a URL
+            if {[string match "*/*" $portname]} {
+                set url "file://$portname"
+                set name [url_to_portname $url 1]
+                if { $name ne "" } {
+                    # We mapped the url to valid port
+                    set porturl $url
+                    set portname $name
+                    # Continue to parse rest of portspec....
+                } else {
+                    # We didn't map the url to a port; treat it
+                    # as a raw string for something like port contents
+                    # or cd
+                    set porturl ""
+                    # Since this isn't a port, we don't try to parse
+                    # any remaining portspec....
+                    return
+                }
+            }
+        }
+        
+        # Now parse the rest of the spec
+        parsePortSpec portversion portvariants portoptions $remainder
+    }
+}
+
+# check if the install prefix is writable
+# should be called by actions that will modify it
+proc prefix_unwritable {} {
+    global macports::portdbpath
+    if {[file writable $portdbpath]} {
+        return 0
+    } else {
+        ui_error "Insufficient privileges to write to MacPorts install prefix."
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder ""} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion ""
+    array unset portoptions
+    array set portoptions [array get global_options]
+    array unset portvariants
+    
+    # Parse port version/variants/options
+    set opt $remainder
+    set adv 0
+    set consumed 0
+    for {set firstTime 1} {$opt ne "" || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq ""} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime && [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first "/" $opt]
+            if {$sepPos >= 0} {
+                # Version terminated by "/" to disambiguate -variant from part of version
+                set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                set opt [string range $opt [expr {$sepPos + 1}] end]
+            } else {
+                # Version terminated by "+", or else is complete
+                set sepPos [string first "+" $opt]
+                if {$sepPos >= 0} {
+                    # Version terminated by "+"
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt ""
+                }
+            }
+            set consumed 1
+        } else {
+            # Parse all other options
+            
+            # Look first for a variable setting: VARNAME=VALUE
+            if {[regexp {^([[:alpha:]_]+[\w\.]*)=(.*)} $opt match key val] == 1} {
+                # It's a variable setting
+                set portoptions($key) "\"$val\""
+                set opt ""
+                set consumed 1
+            } elseif {[regexp {^([-+])([[:alpha:]_]+[\w\.]*)} $opt match sign variant] == 1} {
+                # It's a variant
+                set portvariants($variant) $sign
+                set opt [string range $opt [expr {[string length $variant] + 1}] end]
+                set consumed 1
+            } else {
+                # Not an option we recognize, so break from port option processing
+                if { $consumed && $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds ""
+        if {[info exists cmd_opts_array($action)]} {
+            foreach opt $cmd_opts_array($action) {
+                if {[llength $opt] == 1} {
+                    set name $opt
+                    set optc 0
+                } else {
+                    set name [lindex $opt 0]
+                    set optc [lindex $opt 1]
+                }
+
+                append cmds " --$name"
+
+                for {set i 1} {$i <= $optc} {incr i} {
+                    append cmds " <arg$i>"
+                }
+            }
+        }
+        set args ""
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <arguments>"
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <portlist>"
+        }
+
+        set ret "Usage: "
+        set len [string length $action]
+        append ret [wrap "$action$cmds$args" 0 [string repeat " " [expr {8 + $len}]] 0]
+        append ret "\n"
+
+        return $ret
+    }
+
+    return -1
+}
+
+proc action_usage { action portlist opts } {
+    if {[llength $portlist] == 0} {
+        print_usage
+        return 0
+    }
+
+    foreach topic $portlist {
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile "$macports::prefix/var/macports/port-help.tcl"
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr "Error reading helpfile $helpfile: $err"
+            return 1
+        }
+    } else {
+        puts stderr "Unable to open help file $helpfile"
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr "No help for topic $topic"
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+
+        puts stderr $porthelp($topic)
+    }
+
+    return 0
+}
+
+
+proc action_log { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array unset portinfo
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+            set portname $portinfo(name)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            array unset portinfo
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] "main.log"]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue "Could not open file $logfile: $result" 1 status
+            }
+            set data [read $fp]
+            set data [split $data "\n"]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase "\[a-z\]*"
+            }
+
+            if {[info exists global_options(ports_log_level)]} {
+                set index [lsearch -exact ${macports::ui_priorities} $global_options(ports_log_level)]
+                if {$index == -1} {
+                    set prefix ""
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] "|"]
+                }
+            } else {
+                set prefix "\[a-z\]*"
+            }
+            foreach line $data {
+                set exp "^:($prefix|any):($phase|any) (.*)$"
+                if {[regexp $exp $line -> lpriority lphase lmsg] == 1} {
+                    puts "[macports::ui_prefix_default $lpriority]$lmsg"
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue "Log file for port $portname not found" 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator ""
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] && $options(ports_info_index)} {
+            set index_only 1
+        }
+        puts -nonewline $separator
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq "" || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!$index_only} {
+            # Add any global_variations to the variations
+            # specified for the port (so we get e.g. dependencies right)
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+ 
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            unset options(subport)
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "no PortIndex entry found for $portname"
+            continue
+        }
+        array unset options ports_info_index
+
+        # Understand which info items are actually lists
+        # (this could be overloaded to provide a generic formatting code to
+        # allow us to, say, split off the prefix on libs)
+        array set list_map "
+            categories      1
+            depends_fetch   1
+            depends_extract 1
+            depends_build   1
+            depends_lib     1
+            depends_run     1
+            maintainers     1
+            platforms       1
+            variants        1
+            conflicts       1
+            subports        1
+        "
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     ""
+            variants    Variants
+            depends_fetch "Fetch Dependencies"
+            depends_extract "Extract Dependencies"
+            depends_build "Build Dependencies"
+            depends_run "Runtime Dependencies"
+            depends_lib "Library Dependencies"
+            description "Brief Description"
+            long_description "Description"
+            fullname    "Full Name: "
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   "Conflicts with"
+            replaced_by "Replaced by"
+            subports    "Sub-ports"
+        }
+
+        # Wrap-length map for pretty printing
+        array set pretty_wrap {
+            heading 0
+            replaced_by 22
+            variants 22
+            depends_fetch 22
+            depends_extract 22
+            depends_build 22
+            depends_run 22
+            depends_lib 22
+            description 22
+            long_description 22
+            homepage 22
+            platforms 22
+            license 22
+            conflicts 22
+            maintainers 22
+            subports 22
+        }
+
+        # Interpret a convenient field abbreviation
+        if {[info exists options(ports_info_depends)] && $options(ports_info_depends) eq "yes"} {
+            array unset options ports_info_depends
+            set options(ports_info_depends_fetch) yes
+            set options(ports_info_depends_extract) yes
+            set options(ports_info_depends_build) yes
+            set options(ports_info_depends_lib) yes
+            set options(ports_info_depends_run) yes
+        }
+                
+        # Set up our field separators
+        set show_label 1
+        set field_sep "\n"
+        set subfield_sep ", "
+        set pretty_print 0
+        
+        # For human-readable summary, which is the default with no options
+        if {[llength [array get options ports_info_*]] == 0} {
+            set pretty_print 1
+        } elseif {[info exists options(ports_info_pretty)]} {
+            set pretty_print 1
+            array unset options ports_info_pretty
+        }
+
+        # Tune for sort(1)
+        if {[info exists options(ports_info_line)]} {
+            array unset options ports_info_line
+            set noseparator 1
+            set show_label 0
+            set field_sep "\t"
+            set subfield_sep ","
+        }
+        
+        # Figure out whether to show field name
+        set quiet [macports::ui_isset ports_quiet]
+        if {$quiet} {
+            set show_label 0
+        }
+        # In pretty-print mode we also suppress messages, even though we show
+        # most of the labels:
+        if {$pretty_print} {
+            set quiet 1
+        }
+
+        # Spin through action options, emitting information for any found
+        set fields {}
+        set opts_todo [array names options ports_info_*]
+        set fields_tried {}
+        if {![llength $opts_todo]} {
+            set opts_todo {ports_info_heading
+                ports_info_replaced_by
+                ports_info_subports
+                ports_info_variants 
+                ports_info_skip_line
+                ports_info_long_description ports_info_homepage 
+                ports_info_skip_line ports_info_depends_fetch
+                ports_info_depends_extract ports_info_depends_build
+                ports_info_depends_lib ports_info_depends_run
+                ports_info_conflicts
+                ports_info_platforms ports_info_license
+                ports_info_maintainers
+            }
+        }
+        foreach { option } $opts_todo {
+            set opt [string range $option 11 end]
+            # Artificial field name for formatting
+            if {$pretty_print && $opt eq "skip_line"} {
+                lappend fields ""
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq "heading"} {
+                set inf "$portinfo(name) @$portinfo(version)"
+                set ropt "heading"
+                if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                    append inf "_$portinfo(revision)"
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf " ([join $portinfo(categories) ", "])"
+                }
+            } elseif {$opt eq "fullname"} {
+                set inf "$portinfo(name) @"
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt "fullname"
+            } else {
+                # Map from friendly name
+                set ropt [map_friendly_field_names $opt]
+                
+                # If there's no such info, move on
+                if {![info exists portinfo($ropt)]} {
+                    set inf ""
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label ""
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label "$opt: "
+            }
+            
+            # Format the data
+            if { $ropt eq "maintainers" } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq "variants"} {
+                    # Use the new format for variants iff it exists in
+                    # PortInfo. This key currently does not exist outside of
+                    # trunk (1.8.0).
+                    array unset vinfo
+                    if {[info exists portinfo(vinfo)]} {
+                        array set vinfo $portinfo(vinfo)
+                    }
+
+                    set pi_vars $inf
+                    set inf {}
+                    foreach v [lsort $pi_vars] {
+                        set varmodifier ""
+                        if {[info exists variations($v)]} {
+                            # selected by command line, prefixed with +/-
+                            set varmodifier $variations($v)
+                        } elseif {[info exists global_variations($v)]} {
+                            # selected by variants.conf, prefixed with (+)/(-)
+                            set varmodifier "($global_variations($v))"
+                            # Retrieve additional information from the new key.
+                        } elseif {[info exists vinfo]} {
+                            array unset variant
+                            array set variant $vinfo($v)
+                            if {[info exists variant(is_default)]} {
+                                set varmodifier "\[$variant(is_default)]"
+                            }
+                        }
+                        lappend inf "$varmodifier$v"
+                    }
+                } elseif {[string match "depend*" $ropt] 
+                          && ![macports::ui_isset ports_verbose]} {
+                    set pi_deps $inf
+                    set inf {}
+                    foreach d $pi_deps {
+                        lappend inf [lindex [split $d :] end]
+                    }
+                }
+            } 
+            #End of special pretty-print formatting for certain fields
+            if {[info exists list_map($ropt)]} {
+                set field [join $inf $subfield_sep]
+            } else {
+                set field $inf
+            }
+            
+            # Assemble the entry
+            if {$pretty_print} {
+                # The two special fields are considered headings and are
+                # emitted immediately, rather than waiting. Also they are not
+                # recorded on the list of fields tried
+                if {$ropt eq "heading" || $ropt eq "fullname"} {
+                    puts "$label$field"
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq ""} {
+                    continue
+                }
+                if {$label eq ""} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat " " $wrap_len]]
+                } else {
+                    set wrap_len [string length $label]
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wraplabel $label $field 0 [string repeat " " $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields "$label$field"
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print && [llength $fields_tried]} {
+                puts -nonewline "$portinfo(name) has no "
+                puts [join $fields_tried ", "]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator "--\n"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_location { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        if { [catch {set ilist [registry_installed $portname [composite_version $portversion [array get variations]]]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port location failed: $result" 1 status
+        } else {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0]
+            set version [lindex $ilist 1]
+            set revision [lindex $ilist 2]
+            set variants [lindex $ilist 3]
+            set epoch [lindex $ilist 5]
+        }
+
+        set ref [registry::open_entry $portname $version $revision $variants $epoch]
+        set imagedir [registry::property_retrieve $ref location]
+        ui_notice "Port $portname ${version}_${revision}${variants} is installed as an image in:"
+        puts $imagedir
+    }
+    
+    return $status
+}
+
+
+proc action_notes { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set status 0
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue "The lookup of '$portname' failed: $result" \
+                                1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "The port '$portname' was not found" 1 status
+            }
+
+            # Retrieve the port's URL.
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        }
+        
+        # Add any global_variations to the variations
+        # specified for the port
+        array unset merged_variations
+        array set merged_variations [array get variations]
+        foreach { variation value } [array get global_variations] { 
+            if { ![info exists merged_variations($variation)] } { 
+                set merged_variations($variation) $value 
+            } 
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+
+        # Open the Portfile associated with this port.
+        if {[catch {set mport [mportopen $porturl [array get options] \
+                                         [array get merged_variations]]} \
+                   result]} {
+            ui_debug $::errorInfo
+            break_softcontinue [concat "The URL '$porturl' could not be" \
+                                       "opened: $result"] 1 status
+        }
+        array unset portinfo
+        array set portinfo [mportinfo $mport]
+        mportclose $mport
+
+        # Return the notes associated with this Portfile.
+        if {[info exists portinfo(notes)]} {
+            set portnotes $portinfo(notes)
+        } else {
+            set portnotes {}
+        }
+
+        # Retrieve the port's name once more to ensure it has the proper case.
+        set portname $portinfo(name)
+
+        # Display the notes.
+        if {$portnotes ne {}} {
+            ui_notice "$portname has the following notes:"
+            foreach note $portnotes {
+                puts [wrap $note 0 "  " 1]
+            }
+        } else {
+            puts "$portname has no notes."
+        }
+    }
+    return $status
+}
+
+
+proc action_provides { action portlist opts } {
+    # In this case, portname is going to be used for the filename... since
+    # that is the first argument we expect... perhaps there is a better way
+    # to do this?
+    if { ![llength $portlist] } {
+        ui_error "Please specify a filename to check which port provides that file."
+        return 1
+    }
+    foreach filename $portlist {
+        set file [file normalize $filename]
+        if {[file exists $file] || ![catch {file type $file}]} {
+            if {![file isdirectory $file] || [file type $file] eq "link"} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts "$file is provided by: $port"
+                } else {
+                    puts "$file is not provided by a MacPorts port."
+                }
+            } else {
+                puts "$file is a directory."
+            }
+        } else {
+            puts "$file does not exist."
+        }
+    }
+    registry::close_file_map
+    
+    return 0
+}
+
+
+proc action_activate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_activate_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[$regref installtype] eq "image" && [registry::run_target $regref activate [array get options]]} {
+                continue
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::activate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port activate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping activate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_deactivate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    set portlist [portlist_sortdependents $portlist]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_deactivate_no-exec)]
+            && ![catch {set ilist [registry::active $portname]}]} {
+
+            set i [lindex $ilist 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            if {$composite_version eq "" || $composite_version == "${iversion}_${irevision}${ivariants}"} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq "image" && [registry::run_target $regref deactivate [array get options]]} {
+                    continue
+                }
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::deactivate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port deactivate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping deactivate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug "action_select \[$portlist] \[$opts]..."
+
+    array set opts_array $opts
+    set commands [array names opts_array ports_select_*]
+    array unset opts_array
+
+    # Error out if no group is specified or command is not --summary.
+    if {[llength $portlist] < 1 && [string map {ports_select_ ""} [lindex $commands 0]] != "summary"} {
+        ui_error "port select \[--list|--set|--show|--summary] \<group> \[<version>]"
+        return 1
+    }
+
+    set group [lindex $portlist 0]
+    
+    # If no command (--set, --show, --list, --summary) is specified *but*
+    #  more than one argument is specified, default to the set command.
+    if {[llength $commands] < 1 && [llength $portlist] > 1} {
+        set command set
+        ui_debug [concat "Although no command was specified, more than " \
+                         "one argument was specified.  Defaulting to the " \
+                         "'set' command..."]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] < 1} {
+        set command list
+        ui_debug [concat "No command was specified. Defaulting to the " \
+                         "'list' command..."]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] > 1} {
+        ui_error [concat "Multiple commands were specified. Only one " \
+                         "command may be specified at a time."]
+        return 1
+    } else {
+        set command [string map {ports_select_ ""} [lindex $commands 0]]
+        ui_debug "The '$command' command was specified."
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'list' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn "Unable to get active selected version: $selected_version"
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error "The 'list' command failed: $versions"
+                return 1
+            }
+
+            ui_notice "Available versions for $group:"
+            foreach v $versions {
+                ui_notice -nonewline "\t"
+                if {$selected_version == $v} {
+                    ui_msg "$v (active)"
+                } else {
+                    ui_msg "$v"
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] < 2} {
+                ui_error [concat "The 'set' command expects two " \
+                                 "arguments: <group>, <version>"]
+                return 1
+            } elseif {[llength $portlist] > 2} {
+                ui_warn [concat "The 'set' command only expects two " \
+                                "arguments. Extra arguments will be " \
+                                "ignored."]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline "Selecting '$version' for '$group' "
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg "failed: $result"
+                return 1
+            }
+            ui_msg "succeeded. '$version' is now active."
+            return 0
+        }
+        show {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'show' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error "The 'show' command failed: $selected_version"
+                return 1
+            }
+            puts [concat "The currently selected version for '$group' is " \
+                         "'$selected_version'."]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] > 0} {
+                ui_warn [concat "The 'summary' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error "The 'summary' command failed: $portgroups"
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr "%-*s  %-*s  %s"
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn "The list of options for the select group $pg could not be obtained: $versions"
+                    continue
+                }
+                # remove "none", sort the list, append none at the end
+                set noneidx [lsearch -exact $versions "none"]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions "none"
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn "The currently selected option for the select group $pg could not be obtained: $selected_version"
+                    continue
+                }
+                set groupdesc(selected) $selected_version
+
+                set w1 [expr {max($w1, [string length $pg])}]
+                set w2 [expr {max($w2, [string length $selected_version])}]
+
+                lappend groups [array get groupdesc]
+                array unset groupdesc
+            }
+            puts [format $formatStr $w1 "Name" $w2 "Selected" "Options"]
+            puts [format $formatStr $w1 "====" $w2 "========" "======="]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) " "]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error "An unknown command '$command' was specified."
+            return 1
+        }
+    }
+}
+
+
+proc action_selfupdate { action portlist opts } {
+    global global_options
+    if { [catch {macports::selfupdate [array get global_options] base_updated} result ] } {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_error "$result"
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg "Please run `port -v selfupdate' for details."
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal "port selfupdate failed: $result"
+    }
+    
+    if {$base_updated} {
+        # exit immediately if in batch/interactive mode
+        return -999
+    } else {
+        return 0
+    }
+}
+
+
+proc action_setrequested { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    # set or unset?
+    set val [string equal $action "setrequested"]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info "Setting requested flag for $portname to $val"
+            foreach i $ilist {
+                set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+                registry::property_store $regref requested $val
+            }
+        } else {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist "yes"] || ([prefix_unwritable] && ![macports::global_option_isset ports_dryrun])} {
+        return 1
+    }
+
+    # shared depscache for all ports in the list
+    array set depscache {}
+    set status 0
+    foreachport $portlist {
+        if {![info exists depscache(port:$portname)]} {
+            set status [macports::upgrade $portname "port:$portname" [array get requested_variations] [array get options] depscache]
+            # status 2 means the port was not found in the index,
+            # status 3 means the port is not installed
+            if {$status != 0 && $status != 2 && $status != 3 && ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 && $status != 2 && $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] && ${macports::revupgrade_autorun} && ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_reclaim { action portlist opts } {
+    reclaim::main 
+    return 0
+}
+
+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 } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Version: "
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Platform: "
+    }
+    puts "${macports::os_platform} ${macports::os_major} ${macports::os_arch}"
+    return 0
+}
+
+
+proc action_dependents { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set ilist {}
+
+    registry::open_dep_map
+
+    set status 0
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if { [catch {set ilist [registry::installed $portname $composite_version]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        } else {
+            # choose the active version if there is one
+            set index 0
+            foreach i $ilist {
+                if {[lindex $i 4]} {
+                    set found 1
+                    break
+                }
+                incr index
+            }
+            if {![info exists found]} {
+                set index 0
+            }
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist $index 0]
+            set iversion [lindex $ilist $index 1]
+            set irevision [lindex $ilist $index 2]
+            set ivariants [lindex $ilist $index 3]
+        }
+        
+        set deplist [registry::list_dependents $portname $iversion $irevision $ivariants]
+        if { [llength $deplist] > 0 } {
+            if {$action eq "rdependents"} {
+                set toplist $deplist
+                while 1 {
+                    set newlist {}
+                    foreach dep $deplist {
+                        set depname [lindex $dep 2]
+                        if {![info exists seen($depname)]} {
+                            set seen($depname) 1
+                            set rdeplist [registry::list_dependents $depname]
+                            foreach rdep $rdeplist {
+                                lappend newlist $rdep
+                            }
+                            set dependentsof($depname) $rdeplist
+                        }
+                    }
+                    if {[llength $newlist] > 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice "The following ports are dependent on ${portname}:"
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos >= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] <= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] && [string is true -strict $options(ports_rdependents_full)])} {
+                        puts "${spaces}${cur_portname}"
+                        set seen($cur_portname) 1
+                        incr cur_pos
+                        set pos_stack [lreplace $pos_stack end end $cur_pos]
+                        if {[info exists dependentsof($cur_portname)]} {
+                            lappend portstack $dependentsof($cur_portname)
+                            lappend pos_stack 0
+                        }
+                        continue
+                    }
+                    incr cur_pos
+                    set pos_stack [lreplace $pos_stack end end $cur_pos]
+                }
+            } else {
+                foreach dep $deplist {
+                    set depport [lindex $dep 2]
+                    if {[macports::ui_isset ports_quiet]} {
+                        ui_msg "$depport"
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg "$depport depends on $portname"
+                    } else {
+                        ui_msg "$depport depends on $portname (by [lindex $dep 1]:)"
+                    }
+                }
+            }
+        } else {
+            ui_notice "$portname has no dependents."
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator ""
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] && [string is true -strict $options(ports_${action}_no-build)]} {
+            set deptypes {depends_lib depends_run}
+        } else {
+            set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+        }
+
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+            # Add any global_variations to the variations
+            # specified for the port, so we get dependencies right
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn "port ${action} --index does not work with the 'current' pseudo-port"
+            continue
+        }
+        set portname $portinfo(name)
+
+        set deplist {}
+        set deps_output {}
+        set ndeps 0
+        array set labeldict {depends_fetch Fetch depends_extract Extract depends_build Build depends_lib Library depends_run Runtime}
+        # get list of direct deps
+        foreach type $deptypes {
+            if {[info exists portinfo($type)]} {
+                if {$action eq "rdeps" || [macports::ui_isset ports_verbose]} {
+                    foreach dep $portinfo($type) {
+                        lappend deplist $dep
+                    }
+                } else {
+                    foreach dep $portinfo($type) {
+                        lappend deplist [lindex [split $dep :] end]
+                    }
+                }
+                if {$action eq "deps"} {
+                    set label "$labeldict($type) Dependencies"
+                    lappend deps_output [wraplabel $label [join $deplist ", "] 0 [string repeat " " 22]]
+                    incr ndeps [llength $deplist]
+                    set deplist {}
+                }
+            }
+        }
+
+        set version $portinfo(version)
+        set revision $portinfo(revision)
+        if {[info exists portinfo(canonical_active_variants)]} {
+            set variants $portinfo(canonical_active_variants)
+        } else {
+            set variants {}
+        }
+
+        puts -nonewline $separator
+        if {$action eq "deps"} {
+            if {$ndeps == 0} {
+                ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+            } else {
+                ui_notice "Full Name: $portname @${version}_${revision}${variants}"
+                puts [join $deps_output "\n"]
+            }
+            set separator "--\n"
+            continue
+        }
+
+        set toplist $deplist
+        # gather all the deps
+        while 1 {
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        break_softcontinue "lookup of portname $depname failed: $result" 1 status
+                    }
+                    if {[llength $result] < 2} {
+                        break_softcontinue "Port $depname not found" 1 status
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                    set options(subport) $portinfo(name)
+                    
+                    # open the portfile if requested
+                    if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug "$::errorInfo"
+                            break_softcontinue "Unable to open port: $result" 1 status
+                        }
+                        array unset portinfo
+                        array set portinfo [mportinfo $mport]
+                        mportclose $mport
+                    }
+                    
+                    # get list of the dep's deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                lappend rdeplist $rdep
+                                lappend newlist $rdep
+                            }
+                        }
+                    }
+                    set depsof($depname) $rdeplist
+                }
+            }
+            if {[llength $newlist] > 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] > 0} {
+            ui_notice "The following ports are dependencies of $portname @${version}_${revision}${variants}:"
+        } else {
+            ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos >= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] <= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] && [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts "${spaces}${cur_port}"
+                } else {
+                    puts "${spaces}${cur_portname}"
+                }
+                set seen($cur_portname) 1
+                incr cur_pos
+                set pos_stack [lreplace $pos_stack end end $cur_pos]
+                if {[info exists depsof($cur_portname)]} {
+                    lappend portstack $depsof($cur_portname)
+                    lappend pos_stack 0
+                }
+                continue
+            }
+            incr cur_pos
+            set pos_stack [lreplace $pos_stack end end $cur_pos]
+        }
+        set separator "--\n"
+    }
+    return $status
+}
+
+
+proc action_uninstall { action portlist opts } {
+    set status 0
+    if {[macports::global_option_isset port_uninstall_old]} {
+        # if -u then uninstall all inactive ports
+        # (union these to any other ports user has in the port list)
+        set portlist [opUnion $portlist [get_inactive_ports]]
+    } else {
+        # Otherwise the user hopefully supplied a portlist, or we'll default to the existing directory
+        if {[require_portlist portlist]} {
+            return 1
+        }
+    }
+    if {[prefix_unwritable]} {
+        return 1
+    }
+
+    set portlist [portlist_sortdependents $portlist]
+
+    foreachport $portlist {
+        if {![registry::entry_exists_for_name $portname]} {
+            # if the code path arrives here the port either isn't installed, or
+            # it doesn't exist at all. We can't be sure, but we can check the
+            # portindex whether a port by that name exists (in which case not
+            # uninstalling it is probably no problem). If there is no port by
+            # that name, alert the user in case of typos.
+            ui_info "$portname is not installed"
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn "no such port: $portname, skipping uninstall"
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set iactive [lindex $i 4]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[registry::run_target $regref uninstall [array get options]]} {
+                continue
+            }
+        }
+
+        if { [catch {registry_uninstall::uninstall_composite $portname $composite_version [array get options]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port uninstall failed: $result" 1 status
+        }
+    }
+
+    return $status
+}
+
+
+proc action_installed { action portlist opts } {
+    global private_options
+    set status 0
+    set restrictedList 0
+    set ilist {}
+    
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreachport $portlist {
+            set composite_version [composite_version $portversion [array get variations]]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port installed failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] > 0 } {
+        ui_notice "The following ports are currently installed:"
+        foreach i [portlist_sortint $ilist] {
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            set extra ""
+            set nvariants ""
+            if {[macports::ui_isset ports_verbose]} {
+                set regref [registry::open_entry $iname $iversion $irevision $ivariants [lindex $i 5]]
+                set nvariants [registry::property_retrieve $regref negated_variants]
+                if {$nvariants == 0} {
+                    set nvariants ""
+                }
+                set os_platform [registry::property_retrieve $regref os_platform]
+                set os_major [registry::property_retrieve $regref os_major]
+                set archs [registry::property_retrieve $regref archs]
+                if {$os_platform != 0 && $os_platform ne "" && $os_major != 0 && $os_major ne ""} {
+                    append extra " platform='$os_platform $os_major'"
+                }
+                if {$archs != 0 && $archs ne ""} {
+                    append extra " archs='$archs'"
+                }
+            }
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}"
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are installed."
+    } else {
+        ui_notice "No ports are installed."
+    }
+
+    return $status
+}
+
+
+proc action_outdated { action portlist opts } {
+    global private_options
+    set status 0
+
+    # If port names were supplied, limit ourselves to those ports, else check all installed ports
+    set ilist {}
+    set restrictedList 0
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreach portspec $portlist {
+            array set port $portspec
+            set portname $port(name)
+            set composite_version [composite_version $port(version) $port(variants)]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port outdated failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] > 0 } {
+        foreach i [portlist_sortint $ilist] {
+        
+            # Get information about the installed port
+            set portname [lindex $i 0]
+            set installed_version [lindex $i 1]
+            set installed_revision [lindex $i 2]
+            set installed_compound "${installed_version}_${installed_revision}"
+
+            set is_active [lindex $i 4]
+            if {$is_active == 0} {
+                continue
+            }
+            set installed_epoch [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+            
+            # Get information about latest available version and revision
+            if {![info exists portinfo(version)]} {
+                ui_warn "$portname has no version field"
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound "${latest_version}_${latest_revision}"
+            set latest_epoch 0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch $portinfo(epoch)
+            }
+            
+            # Compare versions, first checking epoch, then version, then revision
+            set epoch_comp_result [expr {$installed_epoch - $latest_epoch}]
+            set comp_result [vercmp $installed_version $latest_version]
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            set reason ""
+            if {$epoch_comp_result != 0 && $installed_version != $latest_version} {
+                if {($comp_result >= 0 && $epoch_comp_result < 0) || ($comp_result <= 0 && $epoch_comp_result > 0)} {
+                    set reason { (epoch $installed_epoch $relation $latest_epoch)}
+                }
+                set comp_result $epoch_comp_result
+            } elseif {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision [lindex $i 3] $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                    set reason { (platform $os_platform_installed $os_major_installed != ${macports::os_platform} ${macports::os_major})}
+                }
+            }
+            
+            # Report outdated (or, for verbose, predated) versions
+            if { $comp_result != 0 } {
+                            
+                # Form a relation between the versions
+                set flag ""
+                if { $comp_result > 0 } {
+                    set relation ">"
+                    set flag "!"
+                } else {
+                    set relation "<"
+                }
+                
+                # Emit information
+                if {$comp_result < 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice "The following installed ports are outdated:"
+                    }
+                    incr num_outdated
+
+                    puts [format "%-30s %-24s %1s" $portname "$installed_compound $relation $latest_compound [subst $reason]" $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice "No installed ports are outdated."
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are outdated."
+    } else {
+        ui_notice "No ports are installed."
+    }
+    
+    return $status
+}
+
+
+proc action_contents { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {[info exists global_options(ports_contents_size)]} {
+        set units {}
+        if {[info exists global_options(ports_contents_units)]} {
+            set units [complete_size_units $global_options(ports_contents_units)]
+        }
+        set outstring {[format "%12s $file" [filesize $file $units]]}
+    } else {
+        set outstring {  $file}
+    }
+
+    foreachport $portlist {
+        if { ![catch {set ilist [registry::installed $portname]} result] } {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0 0]
+        }
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                ui_notice "Port $portname contains:"
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice "Port $portname does not contain any files or is not active."
+            }
+        } else {
+            ui_notice "Port $portname is not installed."
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq "K" || $units eq "Ki"} {
+        return "KiB"
+    } elseif {$units eq "k"} {
+        return "kB"
+    } elseif {$units eq "Mi"} {
+        return "MiB"
+    } elseif {$units eq "M"} {
+        return "MB"
+    } elseif {$units eq "Gi"} {
+        return "GiB"
+    } elseif {$units eq "G"} {
+        return "GB"
+    } else {
+        return $units
+    }
+}
+
+# Show space used by the given ports' files
+proc action_space {action portlist opts} {
+    global global_options
+    require_portlist portlist
+
+    set units {}
+    if {[info exists global_options(ports_space_units)]} {
+        set units [complete_size_units $global_options(ports_space_units)]
+    }
+    set spaceall 0.0
+    foreachport $portlist {
+        set space 0.0
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne "yes"} {
+                    set msg "[bytesize $space $units] $portname"
+                    if { $portversion != {} } {
+                        append msg " @$portversion"
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr "Port $portname does not contain any file or is not active."
+            }
+        } else {
+            puts stderr "Port $portname is not installed."
+        }
+    }
+    if {[llength $portlist] > 1 || ([info exists options(ports_space_total)] && $options(ports_space_total) eq "yes")} {
+        puts "[bytesize $spaceall $units] total"
+    }
+    return 0
+}
+
+proc action_variants { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] && $options(ports_variants_index) eq "yes")} {
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "port variants --index does not work with 'current' pseudo-port"
+            continue
+        }
+
+        # set portname again since the one we were passed may not have had the correct case
+        set portname $portinfo(name)
+
+        # if this fails the port doesn't have any variants
+        if {![info exists portinfo(variants)]} {
+            ui_notice "$portname has no variants"
+        } else {
+            array unset vinfo
+            # Use the new format if it exists.
+            if {[info exists portinfo(vinfo)]} {
+                array set vinfo $portinfo(vinfo)
+            # Otherwise fall back to the old format.
+            } elseif {[info exists portinfo(variant_desc)]} {
+                array set vdescriptions $portinfo(variant_desc)
+            }
+
+            # print out all the variants
+            ui_notice "$portname has the variants:"
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier "   "
+                # Retrieve variants' information from the new format.
+                if {[info exists vinfo]} {
+                    array unset variant
+                    array set variant $vinfo($v)
+
+                    # Retrieve conflicts, description, is_default, and
+                    # vrequires.
+                    if {[info exists variant(conflicts)]} {
+                        set vconflicts $variant(conflicts)
+                    }
+                    if {[info exists variant(description)]} {
+                        set vdescription $variant(description)
+                    }
+
+                    # XXX Keep these varmodifiers in sync with action_info, or create a wrapper for it
+                    if {[info exists variations($v)]} {
+                        set varmodifier "  $variations($v)"
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier "($global_variations($v))"
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier "\[$variant(is_default)\]"
+                    }
+                    if {[info exists variant(requires)]} {
+                        set vrequires $variant(requires)
+                    }
+                # Retrieve variants' information from the old format,
+                # which only consists of the description.
+                } elseif {[info exists vdescriptions($v)]} {
+                    set vdescription $vdescriptions($v)
+                }
+
+                if {[info exists vdescription]} {
+                    puts [wraplabel "$varmodifier$v" [string trim $vdescription] 0 [string repeat " " [expr 5 + [string length $v]]]]
+                } else {
+                    puts "$varmodifier$v"
+                }
+                if {[info exists vconflicts]} {
+                    puts "     * conflicts with [string trim $vconflicts]"
+                }
+                if {[info exists vrequires]} {
+                    puts "     * requires [string trim $vrequires]"
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        ui_error "You must specify a search pattern"
+        return 1
+    }
+
+    # Copy global options as we are going to modify the array
+    array set options [array get global_options]
+
+    if {[info exists options(ports_search_depends)] && $options(ports_search_depends) eq "yes"} {
+        array unset options ports_search_depends
+        set options(ports_search_depends_fetch) yes
+        set options(ports_search_depends_extract) yes
+        set options(ports_search_depends_build) yes
+        set options(ports_search_depends_lib) yes
+        set options(ports_search_depends_run) yes
+    }
+
+    # Array to hold given filters
+    array set filters {}
+    # Default matchstyle
+    set filter_matchstyle "none"
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne "yes" } {
+            continue
+        }
+        switch -- $opt {
+            exact -
+            glob {
+                set filter_matchstyle $opt
+                continue
+            }
+            regex {
+                set filter_matchstyle regexp
+                continue
+            }
+            case-sensitive {
+                set filter_case yes
+                continue
+            }
+            line {
+                continue
+            }
+        }
+
+        set filters($opt) "yes"
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) "yes"
+        set filters(description) "yes"
+    }
+
+    set separator ""
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq "none"} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first "*" $portname] == -1 && [string first "?" $portname] == -1} {
+                set searchstring "*$portname*"
+            }
+            set matchstyle glob
+        }
+
+        set res {}
+        set portfound 0
+        foreach { opt } [array get filters] {
+            # Map from friendly name
+            set opt [map_friendly_field_names $opt]
+
+            if {[catch {eval set matches \[mportsearch \$searchstring $filter_case \$matchstyle $opt\]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for name $portname failed: $result" 1 status
+            }
+
+            set tmp {}
+            foreach {name info} $matches {
+                add_to_portlist tmp [concat [list name $name] $info]
+            }
+            set res [opUnion $res $tmp]
+        }
+        set res [portlist_sort $res]
+
+        set joiner ""
+        foreach info $res {
+            array unset portinfo
+            array set portinfo $info
+
+            # XXX is this the right place to verify an entry?
+            if {![info exists portinfo(name)]} {
+                puts stderr "Invalid port entry, missing portname"
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing description"
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing version"
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        && $options(ports_search_line) eq "yes"} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts "$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)"
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts "$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)"
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline "$portinfo(name) @$portinfo(version)"
+                    if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                        puts -nonewline "_$portinfo(revision)"
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline " ([join $portinfo(categories) ", "])"
+                    }
+                    puts ""
+                    puts [wrap [join $portinfo(description)] 0 [string repeat " " 4]]
+                }
+            }
+
+            set joiner "\n"
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice "No match for $portname found"
+        } elseif {[llength $res] > 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne "yes")} {
+                ui_notice "\nFound [llength $res] ports."
+            }
+        }
+
+        set separator "--\n"
+    }
+
+    array unset options
+    array unset filters
+
+    return $status
+}
+
+
+proc action_list { action portlist opts } {
+    global private_options
+    set status 0
+    
+    # Default to list all ports if no portnames are supplied
+    if { ![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        add_to_portlist portlist [list name "-all-"]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq "-all-"} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "listing all ports failed: $result" 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $search_string failed: $result" 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir ""
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format "%-30s @%-14s %s" $portinfo(name) $portinfo(version) $outdir]
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_echo { action portlist opts } {
+    global global_options
+
+    # Simply echo back the port specs given to this command
+    foreachport $portlist {
+        if {![macports::ui_isset ports_quiet]} {
+            set opts {}
+            foreach { key value } [array get options] {
+                if {![info exists global_options($key)]} {
+                    lappend opts "$key=$value"
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne "" } {
+                set ver_field "@$composite_version"
+            } else {
+                set ver_field ""
+            }
+            puts [format "%-30s %s %s" $portname $ver_field  [join $opts " "]]
+        } else {
+            puts "$portname"
+        }
+    }
+
+    return 0
+}
+
+
+proc action_portcmds { action portlist opts } {
+    # Operations on the port's directory and Portfile
+    global env boot_env current_portdir
+
+    array set local_options $opts
+    
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific, otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+            set portname $portinfo(name)
+        }
+        
+        
+        # Calculate portdir, porturl, and portfile from initial porturl
+        set portdir [file normalize [macports::getportdir $porturl]]
+        set porturl "file://${portdir}";    # Rebuild url so it's fully qualified
+        set portfile "${portdir}/Portfile"
+        
+        # Now execute the specific action
+        if {[file readable $portfile]} {
+            switch -- $action {
+                cat {
+                    # Copy the portfile to standard output
+                    set f [open $portfile RDONLY]
+                    while { ![eof $f] } {
+                        puts -nonewline [read $f 4096]
+                    }
+                    close $f
+                }
+                
+                edit {
+                    # Edit the port's portfile with the user's editor
+                    
+                    # Restore our entire environment from start time.
+                    # We need it to evaluate the editor, and the editor
+                    # may want stuff from it as well, like TERM.
+                    array unset env_save; array set env_save [array get env]
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor ""
+                    set editor_var "ports_${action}_editor"
+                    if {[info exists local_options($editor_var)]} {
+                        set editor [join $local_options($editor_var)]
+                    } else {
+                        foreach ed { MP_EDITOR VISUAL EDITOR } {
+                            if {[info exists env($ed)]} {
+                                set editor $env($ed)
+                                break
+                            }
+                        }
+                    }
+                    
+                    # Use a reasonable canned default if no editor specified or set in env
+                    if { $editor eq "" } { set editor "/usr/bin/vi" }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec >@stdout <@stdin 2>@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug "$errorInfo"
+                        break_softcontinue "unable to invoke editor $editor: $result" 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get env_save]
+                }
+
+                dir {
+                    # output the path to the port's directory
+                    puts $portdir
+                }
+
+                work {
+                    # output the path to the port's work directory
+                    set workpath [macports::getportworkpath_from_portdir $portdir $portname]
+                    if {[file exists $workpath]} {
+                        puts $workpath
+                    }
+                }
+
+                cd {
+                    # Change to the port's directory, making it the default
+                    # port for any future commands
+                    set current_portdir $portdir
+                }
+
+                url {
+                    # output the url of the port's directory, suitable to feed back in later as a port descriptor
+                    puts $porturl
+                }
+
+                file {
+                    # output the path to the port's portfile
+                    puts $portfile
+                }
+
+                logfile {
+                    set logfile [file join [macports::getportlogpath $portdir $portname] "main.log"]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error "Log file not found for port in $portdir"
+                    }
+                }
+
+                gohome {
+                    set homepage ""
+
+                    # Get the homepage as read from PortIndex
+                    if {[info exists portinfo(homepage)]} {
+                        set homepage $portinfo(homepage)
+                    }
+
+                    # If not available, get the homepage for the port by opening the Portfile
+                    if {$homepage eq "" && ![catch {set ctx [mportopen $porturl]} result]} {
+                        array set portinfo [mportinfo $ctx]
+                        if {[info exists portinfo(homepage)]} {
+                            set homepage $portinfo(homepage)
+                        }
+                        mportclose $ctx
+                    }
+
+                    # Try to open a browser to the homepage for the given port
+                    if { $homepage ne "" } {
+                        if {[catch {system "${macports::autoconf::open_path} '$homepage'"} result]} {
+                            global errorInfo
+                            ui_debug "$errorInfo"
+                            break_softcontinue "unable to invoke browser using ${macports::autoconf::open_path}: $result" 1 status
+                        }
+                    } else {
+                        ui_error [format "No homepage for %s" $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue "Could not read $portfile" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_sync { action portlist opts } {
+    global global_options
+
+    set status 0
+    if {[catch {mportsync [array get global_options]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_msg "port sync failed: $result"
+        set status 1
+    }
+    
+    return $status
+}
+
+
+proc action_target { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {($action eq "install" || $action eq "archive") && [prefix_unwritable] && ![macports::global_option_isset ports_dryrun]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn "Skipping $portname (not in the ports tree)"
+                    continue
+                } else {
+                    break_softcontinue "Port $portname not found" 1 status
+                }
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+        }
+
+        # use existing variants iff none were explicitly requested
+        if {[array get requested_variations] eq "" && [array get variations] ne ""} {
+            array unset requested_variations
+            array set requested_variations [array get variations]
+        }
+
+        # Add any global_variations to the variations
+        # specified for the port
+        foreach { variation value } [array get global_variations] {
+            if { ![info exists requested_variations($variation)] } {
+                set requested_variations($variation) $value
+            }
+        }
+
+        # If version was specified, save it as a version glob for use
+        # in port actions (e.g. clean).
+        if {[string length $portversion]} {
+            set options(ports_version_glob) $portversion
+        }
+        # if installing, mark the port as explicitly requested
+        if {$action eq "install"} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq "archive"} {
+            set target install
+        } else {
+            set target $action
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+        if {[catch {set workername [mportopen $porturl [array get options] [array get requested_variations]]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to open port: $result" 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to execute port: $result" 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue "Processing of port $portname failed" 1 status
+        }
+    }
+    
+    if {$status == 0 && $action eq "install" && ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] && ![info exists options(ports_install_no-rev-upgrade)] && ${macports::revupgrade_autorun}} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+
+proc action_exit { action portlist opts } {
+    # Return a semaphore telling the main loop to quit
+    return -999
+}
+
+
+##########################################
+# Command Parsing
+##########################################
+proc moreargs {} {
+    global cmd_argn cmd_argc
+    return [expr {$cmd_argn < $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn < $cmd_argc} {
+        return [lindex $cmd_argv $cmd_argn]
+    } else {
+        return _EOF_
+    }
+}
+
+
+proc advance {} {
+    global cmd_argn
+    incr cmd_argn
+}
+
+
+proc match s {
+    if {[lookahead] == $s} {
+        advance
+        return 1
+    }
+    return 0
+}
+
+# action_array specifies which action to run on the given command
+# and if the action wants an expanded portlist.
+# The value is a list of the form {action expand},
+# where action is a string and expand a value:
+#   0 none        Does not expect any text argument
+#   1 strings     Expects some strings as text argument
+#   2 ports       Wants an expanded list of ports as text argument
+global action_array
+
+# Define global constants
+const ACTION_ARGS_NONE 0
+const ACTION_ARGS_STRINGS 1
+const ACTION_ARGS_PORTS 2
+
+array set action_array [list \
+    usage       [list action_usage          [ACTION_ARGS_STRINGS]] \
+    help        [list action_help           [ACTION_ARGS_STRINGS]] \
+    \
+    echo        [list action_echo           [ACTION_ARGS_PORTS]] \
+    \
+    info        [list action_info           [ACTION_ARGS_PORTS]] \
+    location    [list action_location       [ACTION_ARGS_PORTS]] \
+    notes       [list action_notes          [ACTION_ARGS_PORTS]] \
+    provides    [list action_provides       [ACTION_ARGS_STRINGS]] \
+    log         [list action_log            [ACTION_ARGS_PORTS]] \
+    \
+    activate    [list action_activate       [ACTION_ARGS_PORTS]] \
+    deactivate  [list action_deactivate     [ACTION_ARGS_PORTS]] \
+    \
+    select      [list action_select         [ACTION_ARGS_STRINGS]] \
+    \
+    sync        [list action_sync           [ACTION_ARGS_NONE]] \
+    selfupdate  [list action_selfupdate     [ACTION_ARGS_NONE]] \
+    \
+    setrequested   [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    unsetrequested [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    \
+    upgrade     [list action_upgrade        [ACTION_ARGS_PORTS]] \
+    rev-upgrade [list action_revupgrade     [ACTION_ARGS_NONE]] \
+    reclaim     [list action_reclaim        [ACTION_ARGS_NONE]] \
+    \
+    version     [list action_version        [ACTION_ARGS_NONE]] \
+    platform    [list action_platform       [ACTION_ARGS_NONE]] \
+    \
+    uninstall   [list action_uninstall      [ACTION_ARGS_PORTS]] \
+    \
+    installed   [list action_installed      [ACTION_ARGS_PORTS]] \
+    outdated    [list action_outdated       [ACTION_ARGS_PORTS]] \
+    contents    [list action_contents       [ACTION_ARGS_PORTS]] \
+    space       [list action_space          [ACTION_ARGS_PORTS]] \
+    dependents  [list action_dependents     [ACTION_ARGS_PORTS]] \
+    rdependents [list action_dependents     [ACTION_ARGS_PORTS]] \
+    deps        [list action_deps           [ACTION_ARGS_PORTS]] \
+    rdeps       [list action_deps           [ACTION_ARGS_PORTS]] \
+    variants    [list action_variants       [ACTION_ARGS_PORTS]] \
+    \
+    search      [list action_search         [ACTION_ARGS_STRINGS]] \
+    list        [list action_list           [ACTION_ARGS_PORTS]] \
+    \
+    edit        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cat         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    dir         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    work        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cd          [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    url         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    file        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    logfile     [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    gohome      [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    \
+    fetch       [list action_target         [ACTION_ARGS_PORTS]] \
+    checksum    [list action_target         [ACTION_ARGS_PORTS]] \
+    extract     [list action_target         [ACTION_ARGS_PORTS]] \
+    patch       [list action_target         [ACTION_ARGS_PORTS]] \
+    configure   [list action_target         [ACTION_ARGS_PORTS]] \
+    build       [list action_target         [ACTION_ARGS_PORTS]] \
+    destroot    [list action_target         [ACTION_ARGS_PORTS]] \
+    install     [list action_target         [ACTION_ARGS_PORTS]] \
+    clean       [list action_target         [ACTION_ARGS_PORTS]] \
+    test        [list action_target         [ACTION_ARGS_PORTS]] \
+    lint        [list action_target         [ACTION_ARGS_PORTS]] \
+    livecheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    distcheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    mirror      [list action_target         [ACTION_ARGS_PORTS]] \
+    load        [list action_target         [ACTION_ARGS_PORTS]] \
+    unload      [list action_target         [ACTION_ARGS_PORTS]] \
+    distfiles   [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    archivefetch [list action_target         [ACTION_ARGS_PORTS]] \
+    archive     [list action_target         [ACTION_ARGS_PORTS]] \
+    unarchive   [list action_target         [ACTION_ARGS_PORTS]] \
+    dmg         [list action_target         [ACTION_ARGS_PORTS]] \
+    mdmg        [list action_target         [ACTION_ARGS_PORTS]] \
+    dpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    mpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    pkg         [list action_target         [ACTION_ARGS_PORTS]] \
+    portpkg     [list action_target         [ACTION_ARGS_PORTS]] \
+    rpm         [list action_target         [ACTION_ARGS_PORTS]] \
+    srpm        [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    quit        [list action_exit           [ACTION_ARGS_NONE]] \
+    exit        [list action_exit           [ACTION_ARGS_NONE]] \
+]
+
+# Expand "action".
+# Returns an action proc, or a list of matching action procs, or the action passed in
+proc find_action { action } {
+    global action_array
+    
+    if { ! [info exists action_array($action)] } {
+        set guess [guess_action $action]
+        if { [info exists action_array($guess)] } {
+            return $guess
+        }
+        return $guess
+    }
+    
+    return $action
+}
+
+# Expand action
+# If there's more than one match, return the next possibility
+proc find_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    } else {
+        set action [complete_action $action]
+        if { [info exists action_array($action)] } {
+            set action_proc [lindex $action_array($action) 0]
+        }
+    }
+    
+    return $action_proc
+}
+
+proc get_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    }
+    
+    return $action_proc
+}
+
+# Returns whether an action expects text arguments at all,
+# expects text arguments or wants an expanded list of ports
+# Return values are constants:
+#   [ACTION_ARGS_NONE]     Does not expect any text argument
+#   [ACTION_ARGS_STRINGS]  Expects some strings as text argument
+#   [ACTION_ARGS_PORTS]    Wants an expanded list of ports as text argument
+proc action_needs_portlist { action } {
+    global action_array
+
+    set ret 0
+    if {[info exists action_array($action)]} {
+        set ret [lindex $action_array($action) 1]
+    }
+
+    return $ret
+}
+
+# cmd_opts_array specifies which arguments the commands accept
+# Commands not listed here do not accept any arguments
+# Syntax if {option argn}
+# Where option is the name of the option and argn specifies how many arguments
+# this argument takes
+global cmd_opts_array
+array set cmd_opts_array {
+    edit        {{editor 1}}
+    info        {category categories depends_fetch depends_extract
+                 depends_build depends_lib depends_run
+                 depends description epoch fullname heading homepage index license
+                 line long_description
+                 maintainer maintainers name platform platforms portdir pretty
+                 replaced_by revision subports variant variants version}
+    contents    {size {units 1}}
+    deps        {index no-build}
+    rdeps       {index no-build full}
+    rdependents {full}
+    search      {case-sensitive category categories depends_fetch
+                 depends_extract depends_build depends_lib depends_run
+                 depends description epoch exact glob homepage line
+                 long_description maintainer maintainers name platform
+                 platforms portdir regex revision variant variants version}
+    selfupdate  {nosync}
+    space       {{units 1} total}
+    activate    {no-exec}
+    deactivate  {no-exec}
+    install     {no-rev-upgrade unrequested}
+    uninstall   {follow-dependents follow-dependencies no-exec}
+    variants    {index}
+    clean       {all archive dist work logs gsoc14}
+    mirror      {new}
+    lint        {nitpick}
+    select      {list set show summary}
+    log         {{phase 1} {level 1}}
+    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 option the prefix of the option to check
+# @return list of pairs {name argc} for all matching options
+proc cmd_option_matches {action option} {
+    global cmd_opts_array
+
+    # This could be so easy with lsearch -index,
+    # but that's only available as of Tcl 8.5
+
+    if {![info exists cmd_opts_array($action)]} {
+        return {}
+    }
+
+    set result {}
+
+    foreach item $cmd_opts_array($action) {
+        if {[llength $item] == 1} {
+            set name $item
+            set argc 0
+        } else {
+            set name [lindex $item 0]
+            set argc [lindex $item 1]
+        }
+
+        if {$name == $option} {
+            set result [list [list $name $argc]]
+            break
+        } elseif {[string first $option $name] == 0} {
+            lappend result [list $name $argc]
+        }
+    }
+
+    return $result
+}
+
+# Parse global options
+#
+# Note that this is called several times:
+#   (1) Initially, to parse options that will be constant across all commands
+#       (options that come prior to any command, frozen into global_options_base)
+#   (2) Following each command (to parse options that will be unique to that command
+#       (the global_options array is reset to global_options_base prior to each command)
+#
+proc parse_options { action ui_options_name global_options_name } {
+    upvar $ui_options_name ui_options
+    upvar $global_options_name global_options
+    global cmdname cmd_opts_array
+    
+    while {[moreargs]} {
+        set arg [lookahead]
+        
+        if {[string index $arg 0] ne "-"} {
+            break
+        } elseif {[string index $arg 1] eq "-"} {
+            # Process long arguments
+            switch -- $arg {
+                -- { # This is the options terminator; do no further option processing
+                    advance; break
+                }
+                default {
+                    set key [string range $arg 2 end]
+                    set kopts [cmd_option_matches $action $key]
+                    if {[llength $kopts] == 0} {
+                        return -code error "${action} does not accept --${key}"
+                    } elseif {[llength $kopts] > 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst "--[lindex $e 0]"
+                        }
+                        return -code error "\"port ${action} --${key}\" is ambiguous: \n  port ${action} [join $errlst "\n  port ${action} "]"
+                    }
+                    set key   [lindex $kopts 0 0]
+                    set kargc [lindex $kopts 0 1]
+                    if {$kargc == 0} {
+                        set global_options(ports_${action}_${key}) yes
+                    } else {
+                        set args {}
+                        while {[moreargs] && $kargc > 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc > 0} {
+                            return -code error "--${key} expects [expr {$kargc + [llength $args]}] parameters!"
+                        }
+                        set global_options(ports_${action}_${key}) $args
+                    }
+                }
+            }
+        } else {
+            # Process short arg(s)
+            set opts [string range $arg 1 end]
+            foreach c [split $opts {}] {
+                switch -- $c {
+                    v {
+                        set ui_options(ports_verbose) yes
+                    }
+                    d {
+                        set ui_options(ports_debug) yes
+                        # debug implies verbose
+                        set ui_options(ports_verbose) yes
+                    }
+                    q {
+                        set ui_options(ports_quiet) yes
+                    }
+                    p {
+                        # Ignore errors while processing within a command
+                        set ui_options(ports_processall) yes
+                    }
+                    f {
+                        set global_options(ports_force) yes
+                    }
+                    o {
+                        set global_options(ports_ignore_different) yes
+                    }
+                    n {
+                        set global_options(ports_nodeps) yes
+                    }
+                    u {
+                        set global_options(port_uninstall_old) yes
+                    }
+                    R {
+                        set global_options(ports_do_dependents) yes
+                    }
+                    s {
+                        set global_options(ports_source_only) yes
+                    }
+                    b {
+                        set global_options(ports_binary_only) yes
+                    }
+                    c {
+                        set global_options(ports_autoclean) yes
+                    }
+                    k {
+                        set global_options(ports_autoclean) no
+                    }
+                    t {
+                        set global_options(ports_trace) yes
+                    }
+                    y {
+                        set global_options(ports_dryrun) yes
+                    }
+                    F {
+                        # Name a command file to process
+                        advance
+                        if {[moreargs]} {
+                            lappend ui_options(ports_commandfiles) [lookahead]
+                        }
+                    }
+                    D {
+                        advance
+                        if {[moreargs]} {
+                            cd [lookahead]
+                        }
+                        break
+                    }
+                    default {
+                        print_usage; exit 1
+                    }
+                }
+            }
+        }
+
+        advance
+    }
+}
+
+# acquire exclusive registry lock for actions that need it
+# returns 1 if locked, 0 otherwise
+proc lock_reg_if_needed {action} {
+    switch -- $action {
+        activate -
+        deactivate -
+        setrequested -
+        unsetrequested -
+        upgrade -
+        uninstall -
+        install {
+            registry::exclusive_lock
+            return 1
+        }
+    }
+    return 0
+}
+
+proc process_cmd { argv } {
+    global cmd_argc cmd_argv cmd_argn \
+           global_options global_options_base private_options ui_options \
+           current_portdir
+    set cmd_argv $argv
+    set cmd_argc [llength $argv]
+    set cmd_argn 0
+
+    set action_status 0
+
+    # Process an action if there is one
+    while {($action_status == 0 || [macports::ui_isset ports_processall]) && [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == ";" } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == "#" } {
+            while { [moreargs] } { advance }
+            break
+        }
+
+        set locked [lock_reg_if_needed $action]
+        # Always start out processing an action in current_portdir
+        cd $current_portdir
+        
+        # Reset global_options from base before each action, as we munge it just below...
+        array unset global_options
+        array set global_options $global_options_base
+        
+        # Find an action to execute
+        set actions [find_action $action]
+        if {[llength $actions] == 1} {
+            set action [lindex $actions 0]
+            set action_proc [get_action_proc $action]
+        } else {
+            if {[llength $actions] > 1} {
+                ui_error "\"port ${action}\" is ambiguous: \n  port [join $actions "\n  port "]"
+            } else {
+                ui_error "Unrecognized action \"port $action\""
+            }
+            set action_status 1
+            break
+        }
+
+        # Parse options that will be unique to this action
+        # (to avoid abiguity with -variants and a default port, either -- must be
+        # used to terminate option processing, or the pseudo-port current must be specified).
+        if {[catch {parse_options $action ui_options global_options} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            ui_error $result
+            set action_status 1
+            break
+        }
+
+        # What kind of arguments does the command expect?
+        set expand [action_needs_portlist $action]
+
+        # Parse action arguments, setting a special flag if there were none
+        # We otherwise can't tell the difference between arguments that evaluate
+        # to the empty set, and the empty set itself.
+        set portlist {}
+        switch -- [lookahead] {
+            ;       -
+            _EOF_ {
+                set private_options(ports_no_args) yes
+            }
+            default {
+                if {[ACTION_ARGS_NONE] == $expand} {
+                    ui_error "$action does not accept string arguments"
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] && ![match ";"] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error "Improper expression syntax while processing parameters"
+                        set action_status 1
+                        break
+                    }
+                }
+            }
+        }
+        
+        # execute the action
+        set action_status [$action_proc $action $portlist [array get global_options]]
+
+        # unlock if needed
+        if {$locked} {
+            registry::exclusive_unlock
+        }
+
+        # Print notifications of just-activated ports.
+        portclient::notifications::display
+
+        # semaphore to exit
+        if {$action_status == -999} break
+    }
+    
+    return $action_status
+}
+
+
+proc complete_portname { text state } { 
+    global complete_choices complete_position
+    
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices {}
+
+        # Build a list of ports with text as their prefix
+        if {[catch {set res [mportsearch "${text}*" false glob]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "search for portname $pattern failed: $result"
+        }
+        foreach {name info} $res {
+            lappend complete_choices $name
+        }
+    }
+    
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+    
+    return $word
+}
+
+
+# return text action beginning with $text
+proc complete_action { text state } {   
+    global action_array complete_choices complete_position
+
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices [array names action_array "[string tolower $text]*"]
+    }
+
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+
+    return $word
+}
+
+# return all actions beginning with $text
+proc guess_action { text } {   
+    global action_array
+
+    return [array names action_array "[string tolower $text]*"]
+
+    if { [llength $complete_choices ] == 1 } {
+        return [lindex $complete_choices 0]
+    }
+
+    return {}
+}
+
+proc attempt_completion { text word start end } {
+    # If the word starts with '~', or contains '.' or '/', then use the build-in
+    # completion to complete the word
+    if { [regexp {^~|[/.]} $word] } {
+        return ""
+    }
+
+    # Decide how to do completion based on where we are in the string
+    set prefix [string range $text 0 [expr {$start - 1}]]
+    
+    # If only whitespace characters preceed us, or if the
+    # previous non-whitespace character was a ;, then we're
+    # an action (the first word of a command)
+    if { [regexp {(^\s*$)|(;\s*$)} $prefix] } {
+        return complete_action
+    }
+    
+    # Otherwise, do completion on portname
+    return complete_portname
+}
+
+
+proc get_next_cmdline { in out use_readline prompt linename } {
+    upvar $linename line
+    
+    set line ""
+    while { $line eq "" } {
+
+        if {$use_readline} {
+            set len [readline read -attempted_completion attempt_completion line $prompt]
+        } else {
+            puts -nonewline $out $prompt
+            flush $out
+            set len [gets $in line]
+        }
+
+        if { $len < 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline && $line ne "" } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in "stdin"]
+    set name "port"
+    set use_readline [expr {$isstdin && [readline init $name]}]
+    set history_file [file normalize "${macports::macports_user_dir}/history"]
+
+    # Read readline history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin && ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts "MacPorts [macports::version]"
+        puts "Entering interactive mode... (\"help\" for help, \"quit\" to quit)"
+    }
+
+    # Main command loop
+    set exit_status 0
+    while { $exit_status == 0 || $isstdin || [macports::ui_isset ports_processall] } {
+
+        # Calculate our prompt
+        if { $noisy } {
+            set shortdir [eval file join [lrange [file split $current_portdir] end-1 end]]
+            set prompt "\[$shortdir\] > "
+        } else {
+            set prompt ""
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] <= 0  } {
+            puts ""
+            break
+        }
+
+        # Process the command
+        set exit_status [process_cmd $line]
+        
+        # Check for semaphore to exit
+        if {$exit_status == -999} {
+            set exit_status 0
+            break
+        }
+    }
+
+    # Create macports user directory if it does not exist yet
+    if {$use_readline && ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts "Goodbye"
+    }
+
+    return $exit_status
+}
+
+
+proc process_command_files { filelist } {
+    set exit_status 0
+
+    # For each file in the command list, process commands
+    # in the file
+    foreach file $filelist {
+        if {$file eq "-"} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal "Failed to open command file; $result"
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne "stdin"} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 && ![macports::ui_isset ports_processall]} {
+            return $exit_status
+        }
+    }
+
+    return $exit_status
+}
+
+namespace eval portclient::progress {
+    ##
+    # Maximum width of the progress bar or indicator when displaying it.
+    variable maxWidth 50
+
+    ##
+    # The start time of the last progress callback as returned by [clock time].
+    # Since only one progress indicator is active at a time, this variable is
+    # shared between the different variants of progress functions.
+    variable startTime
+
+    ##
+    # Delay in milliseconds after the start of the operation before deciding
+    # that showing a progress bar makes sense.
+    variable showTimeThreshold 500
+
+    ##
+    # Percentage value between 0 and 1 that must not have been reached yet when
+    # $showTimeThreshold has passed for a progress bar to be shown. If the
+    # operation has proceeded above e.g. 75% after 500ms we won't bother
+    # displaying a progress indicator anymore -- the operation will be finished
+    # in well below a second anyway.
+    variable showPercentageThreshold 0.75
+
+    ##
+    # Boolean indication whether the progress indicator should be shown or is
+    # still hidden because the current operation didn't need enough time for
+    # a progress indicator to make sense, yet.
+    variable show no
+
+    ##
+    # Initialize the progress bar display delay; call this from the start
+    # action of the progress functions.
+    proc initDelay {} {
+        variable show
+        variable startTime
+
+        set startTime [clock milliseconds]
+        set show no
+    }
+
+    ##
+    # Determine whether a progress bar should be shown for the current
+    # operation in its current state. You must have called initDelay for the
+    # current operation before calling this method.
+    #
+    # @param cur
+    #        Current progress in abstract units.
+    # @param total
+    #        Total number of abstract units to be processed, if known. Pass
+    #        0 if unknown.
+    # @return
+    #        "yes", if the progress indicator should be shown, "no" otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq "yes"} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] > $showTimeThreshold &&
+                ($total == 0 || [expr {double($cur) / double($total)}] < $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of "start", "update", "intermission" or "finish", where start
+    #        will be called before any number of update calls, interrupted by
+    #        any number of intermission calls (called because other output is
+    #        being produced), followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        "intermission" and "finish", the args are empty and unused. For
+    #        "update", args contains $cur and $total, where $cur is the current
+    #        number of units processed and $total is the total number of units
+    #        to be processed. If the total is not known, it is 0.
+    proc generic {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {now total} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            progressbar $now $total [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        } else {
+                            unprogressbar [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        }
+                    }
+                }
+            }
+            intermission -
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of "start", "update" or "finish", where start will be called
+    #        before any number of update calls, followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        contains a single argument "ul" or "dl" indicating whether this is
+    #        an up- or download. For "update", contains the arguments
+    #        ("ul"|"dl") $total $now $speed where ul/dl are as for start, and
+    #        total, now and speed are doubles indicating the total transfer
+    #        size, currently transferred amount and average speed per second in
+    #        bytes. Unused for "finish".
+    proc download {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {type total now speed} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format "        speed: %-13s" "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format " %-10s     speed: %-13s" [bytesize $now {} "%6.1f"] "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            unprogressbar $barLen $barPrefix $barSuffix
+                        }
+                    }
+                }
+            }
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Draw a progress bar using unicode block drawing characters
+    #
+    # @param current
+    #        The current progress value.
+    # @param total
+    #        The progress value representing 100%.
+    # @param width
+    #        The width in characters of the progress bar. This includes percentage
+    #        output, which takes up 8 characters.
+    # @param prefix
+    #        Prefix to be printed in front of the progress bar.
+    # @param suffix
+    #        Suffix to be printed after the progress bar.
+    proc progressbar {current total width {prefix ""} {suffix ""}} {
+        # Subtract the width of the percentage output, also subtract the two
+        # characters [ and ] bounding the progress bar.
+        set percentageWidth 8
+        set barWidth      [expr {entier($width) - $percentageWidth - 2}]
+
+        # Map the range (0, $total) to (0, 4 * $width) where $width is the maximum
+        # numebr of characters to be printed for the progress bar. Multiply the
+        # upper bound with 8 because we have 8 sub-states per character.
+        set barProgress   [expr {entier(round(($current * $barWidth * 8) / $total))}]
+
+        set barInteger    [expr {$barProgress / 8}]
+        #set barRemainder  [expr {$barProgress % 8}]
+
+        # Finally, also provide a percentage value to print behind the progress bar
+        set percentage [expr {double($current) * 100 / double($total)}]
+
+        # clear the current line, enable reverse video
+        set progressbar "\033\[7m"
+        for {set i 0} {$i < $barInteger} {incr i} {
+            # U+2588 FULL BLOCK doesn't match the other blocks in some fonts :/
+            # Two half blocks work better in some fonts, but not in others (because
+            # they leave ugly spaces). So, one or the other choice isn't better or
+            # worse and even just using full blocks looks ugly in a few fonts.
+
+            # Use pure ASCII until somebody fixes most of the default terminal fonts :/
+            append progressbar " "
+        }
+        # back to normal output
+        append progressbar "\033\[0m"
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger < $barWidth} {
+        #            append progressbar " "
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar "\u258f"
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar "\u258e"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar "\u258c"
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar "\u258b"
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar "\u258a"
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar "\u2589"
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i < $barWidth} {incr i} {
+            append progressbar " "
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format " %[expr {$percentageWidth - 3}].1f %%" $percentage]
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}"
+        flush stdout
+    }
+
+
+    ##
+    # Internal state of the progress indicator; unless you're hacking the
+    # unprogressbar code you should never touch this.
+    variable unprogressState 0
+
+    ##
+    # Draw a progress indicator
+    #
+    # @param width
+    #        The width in characters of the progress indicator.
+    # @param prefix
+    #        Prefix to be printed in front of the progress indicator.
+    # @param suffix
+    #        Suffix to be printed after the progress indicator.
+    proc unprogressbar {width {prefix ""} {suffix ""}} {
+        variable unprogressState
+
+        # Subtract the two characters [ and ] bounding the progress indicator
+        # from the width.
+        set barWidth [expr {int($width) - 2}]
+
+        # Number of states of the progress bar, or rather: the number of
+        # characters before the sequence repeats.
+        set numStates 4
+
+        set unprogressState [expr {($unprogressState + 1) % $numStates}]
+
+        set progressbar ""
+        for {set i 0} {$i < $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar "\u2022"
+            } else {
+                append progressbar " "
+            }
+        }
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${suffix}"
+        flush stdout
+    }
+}
+
+namespace eval portclient::notifications {
+    ##
+    # Ports whose notifications to display; these were either installed
+    # or requested to be installed.
+    variable notificationsToPrint
+    array set notificationsToPrint {}
+
+    ##
+    # Add a port to the list for printing notifications.
+    #
+    # @param name
+    #        The name of the port.
+    # @param note
+    #        A list of notes to be stored for the given port.
+    proc append {name notes} {
+        variable notificationsToPrint
+
+        set notificationsToPrint($name) $notes
+    }
+
+    ##
+    # Print port notifications.
+    #
+    proc display {} {
+        global env
+        variable notificationsToPrint
+
+        # Display notes at the end of the activation phase.
+        if {[array size notificationsToPrint] > 0} {
+            ui_notice "--->  Some of the ports you installed have notes:"
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice "  $name has the following notes:"
+
+                # If env(COLUMNS) exists, limit each line's width to this width.
+                if {[info exists env(COLUMNS)]} {
+                    set maxlen $env(COLUMNS)
+
+                    foreach note $notes {
+                        foreach line [split $note "\n"] {
+                            set joiner ""
+                            set lines ""
+                            set newline "    "
+
+                            foreach word [split $line " "] {
+                                if {[string length $newline] + [string length $word] >= $maxlen} {
+                                    lappend lines $newline
+                                    set newline "    "
+                                    set joiner ""
+                                }
+                                ::append newline $joiner $word
+                                set joiner " "
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines "\n"]
+                        }
+                    }
+                } else {
+                    foreach note $notes {
+                        ui_notice $note
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+##########################################
+# Main
+##########################################
+
+# Global arrays passed to the macports1.0 layer
+array set ui_options        {}
+array set global_options    {}
+array set global_variations {}
+
+# Global options private to this script
+array set private_options {}
+
+# Make sure we get the size of the terminal
+# We do this here to save it in the boot_env, in case we determined it manually
+term_init_size
+
+global env boot_env argv0 cmdname argc argv cmd_argc cmd_argv cmd_argn \
+       current_portdir global_options_base exit_status
+
+# Save off a copy of the environment before mportinit monkeys with it
+array set boot_env [array get env]
+
+set cmdname [file tail $argv0]
+
+# Setp cmd_argv to match argv
+set cmd_argv $argv
+set cmd_argc $argc
+set cmd_argn 0
+
+# make sure we're using a sane umask
+umask 022
+
+# If we've been invoked as portf, then the first argument is assumed
+# to be the name of a command file (i.e., there is an implicit -F
+# before any arguments).
+if {[moreargs] && $cmdname eq "portf"} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options "global" ui_options global_options} result]} {
+    puts "Error: $result"
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    && $portclient::progress::hasTermAnsiSend eq "yes"
+    && (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne "yes")} {
+    set ui_options(progress_download) portclient::progress::download
+    set ui_options(progress_generic)  portclient::progress::generic
+}
+
+set ui_options(notifications_append) portclient::notifications::append
+
+# Get arguments remaining after option processing
+set remaining_args [lrange $cmd_argv $cmd_argn end]
+
+# If we have no arguments remaining after option processing then force
+# interactive mode
+if { [llength $remaining_args] == 0 && ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq "selfupdate" || [lookahead] eq "sync"} {
+    # tell mportinit not to tell the user they should selfupdate
+    set ui_options(ports_no_old_index_warning) 1
+}
+
+# Initialize mport
+# This must be done following parse of global options, as some options are
+# evaluated by mportinit.
+if {[catch {mportinit ui_options global_options global_variations} result]} {
+    global errorInfo
+    puts "$errorInfo"
+    fatal "Failed to initialize MacPorts, $result"
+}
+
+# Set up some global state for our code
+set current_portdir [pwd]
+
+# Freeze global_options into global_options_base; global_options
+# will be reset to global_options_base prior to processing each command.
+set global_options_base [array get global_options]
+
+# First process any remaining args as action(s)
+set exit_status 0
+if { [llength $remaining_args] > 0 } {
+
+    # If there are remaining arguments, process those as a command
+    set exit_status [process_cmd $remaining_args]
+}
+
+# Process any prescribed command files, including standard input
+if { ($exit_status == 0 || [macports::ui_isset ports_processall]) && [info exists ui_options(ports_commandfiles)] } {
+    set exit_status [process_command_files $ui_options(ports_commandfiles)]
+}
+if {$exit_status == -999} {
+    set exit_status 0
+}
+
+# shut down macports1.0
+mportshutdown
+
+# Return with exit_status
+exit $exit_status

Added: branches/gsoc14-cleanup/src/port/port.LOCAL.23878
===================================================================
--- branches/gsoc14-cleanup/src/port/port.LOCAL.23878	                        (rev 0)
+++ branches/gsoc14-cleanup/src/port/port.LOCAL.23878	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,5348 @@
+#!/opt/local/libexec/macports/bin/tclsh8.5
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
+# $Id: port.tcl 119177 2014-04-18 22:35:29Z cal at macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw <rshaw at opendarwin.org>
+# Copyright (c) 2002-2003 Apple Inc.
+# 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.
+# 3. Neither the name of Apple Inc. nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+# Create a namespace for some local variables
+namespace eval portclient::progress {
+    ##
+    # Indicate whether the term::ansi::send tcllib package is available and was
+    # imported. "yes", if the package is available, "no" otherwise.
+    variable hasTermAnsiSend no
+}
+
+if {![catch {package require term::ansi::send}]} {
+    set portclient::progress::hasTermAnsiSend yes
+}
+
+package require macports
+package require Pextlib 1.0
+
+# Standard procedures
+proc print_usage {{verbose 1}} {
+    global cmdname
+    set syntax {
+        [-bcdfknopqRstuvy] [-D portdir] [-F cmdfile] action [privopts] [actionflags]
+        [[portname|pseudo-portname|port-url] [@version] [+-variant]... [option=value]...]...
+    }
+
+    if {$verbose} {
+        puts stderr "Usage: $cmdname$syntax"
+        puts stderr "\"$cmdname help\" or \"man 1 port\" for more information."
+    } else {
+        puts stderr "$cmdname$syntax"
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds ""
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen > 65} {
+            set cmds "$cmds,\n"
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new "$cmd"
+        } else {
+            set new ", $cmd"
+        }
+        incr lineLen [string length $new]
+        set cmds "$cmds$new"
+    }
+
+    set cmdText "Supported actions
+------------------
+$cmds
+"
+
+    set text {
+Pseudo-portnames
+----------------
+Pseudo-portnames are words that may be used in place of a portname, and
+which expand to some set of ports. The common pseudo-portnames are:
+all, current, active, inactive, actinact, installed, uninstalled, outdated,
+obsolete, requested, unrequested and leaves.
+These pseudo-portnames expand to the set of ports named.
+
+Pseudo-portnames starting with variants:, variant:, description:, depends:,
+depends_lib:, depends_run:, depends_build:, depends_fetch:, depends_extract:,
+portdir:, homepage:, epoch:, platforms:, platform:, name:, long_description:,
+maintainers:, maintainer:, categories:, category:, version:, revision:, and
+license: each select a set of ports based on a regex search of metadata
+about the ports. In all such cases, a standard regex pattern following
+the colon will be used to select the set of ports to which the
+pseudo-portname expands.
+
+Pseudo-portnames starting with depof:, rdepof:, dependentof:, and rdependentof:
+select ports that are direct or recursive dependencies or dependents of the
+following portname, respectively.
+
+Portnames that contain standard glob characters will be expanded to the
+set of ports matching the glob pattern.
+    
+Port expressions
+----------------
+Portnames, port glob patterns, and pseudo-portnames may be logically
+combined using expressions consisting of and, or, not, !, (, and ).
+    
+For more information
+--------------------
+See man pages: port(1), macports.conf(5), portfile(7), portgroup(7),
+porthier(7), portstyle(7). Also, see http://www.macports.org.
+    }
+
+    puts "$cmdText$text"
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error "$argv0: $s"
+    exit 1
+}
+
+##
+# Helper function to define constants
+#
+# Constants defined with const can simply be accessed in the same way as
+# calling a proc.
+#
+# Example:
+# const FOO 42
+# puts [FOO]
+#
+# @param name variable name
+# @param value constant variable value
+proc const {name args} {
+    proc $name {} [list return [expr $args]]
+}
+
+# Format an integer representing bytes using given units
+proc bytesize {siz {unit {}} {format {%.3f}}} {
+    if {$unit == {}} {
+        if {$siz > 0x40000000} {
+            set unit "GiB"
+        } elseif {$siz > 0x100000} {
+            set unit "MiB"
+        } elseif {$siz > 0x400} {
+            set unit "KiB"
+        } else {
+            set unit "B"
+        }
+    }
+    switch -- $unit {
+        KiB {
+            set siz [expr {$siz / 1024.0}]
+        }
+        kB {
+            set siz [expr {$siz / 1000.0}]
+        }
+        MiB {
+            set siz [expr {$siz / 1048576.0}]
+        }
+        MB {
+            set siz [expr {$siz / 1000000.0}]
+        }
+        GiB {
+            set siz [expr {$siz / 1073741824.0}]
+        }
+        GB {
+            set siz [expr {$siz / 1000000000.0}]
+        }
+        B { }
+        default {
+            ui_warn "Unknown file size unit '$unit' specified"
+            set unit "B"
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return "$siz $unit"
+}
+
+proc filesize {fil {unit {}}} {
+    set siz {@}
+    catch {
+        set siz [bytesize [file size $fil] $unit]
+    }
+    return $siz
+}
+
+# Produce an error message, and exit, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc fatal_softcontinue s {
+    if {[macports::global_option_isset ports_force]} {
+        ui_error $s
+        return -code continue
+    } else {
+        fatal $s
+    }
+}
+
+
+# Produce an error message, and break, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc break_softcontinue { msg status name_status } {
+    upvar $name_status status_var 
+    ui_error $msg
+    if {[macports::ui_isset ports_processall]} {
+        set status_var 0
+        return -code continue
+    } else {
+        set status_var $status
+        return -code break
+    }
+}
+
+# show the URL for the ticket reporting instructions
+proc print_tickets_url {args} {
+    if {${macports::prefix} ne "/usr/local" && ${macports::prefix} ne "/usr"} {
+        ui_error "Follow http://guide.macports.org/#project.tickets to report a bug."
+    }
+}
+
+# Form a composite version as is sometimes used for registry functions
+# This function sorts the variants and presents them in a canonical representation
+proc composite_version {version variations {emptyVersionOkay 0}} {
+    # Form a composite version out of the version and variations
+    
+    # Select the variations into positive and negative
+    set pos {}
+    set neg {}
+    foreach { key val } $variations {
+        if {$val eq "+"} {
+            lappend pos $key
+        } elseif {$val eq "-"} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version ""
+    if {$version ne "" || $emptyVersionOkay} {
+        set pos_str ""
+        set neg_str ""
+
+        if {[llength $pos]} {
+            set pos_str "+[join [lsort -ascii $pos] "+"]"
+        }
+        if {[llength $neg]} {
+            set neg_str "-[join [lsort -ascii $neg] "-"]"
+        }
+
+        set composite_version "$version$pos_str$neg_str"
+    }
+
+    return $composite_version
+}
+
+
+proc split_variants {variants} {
+    set result {}
+    set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
+    foreach { match sign variant } $l {
+        lappend result $variant $sign
+    }
+    return $result
+}
+
+
+##
+# Maps friendly field names to their real name
+# Names which do not need mapping are not changed.
+#
+# @param field friendly name
+# @return real name
+proc map_friendly_field_names { field } {
+    switch -- $field {
+        variant -
+        platform -
+        maintainer -
+        subport {
+            set field "${field}s"
+        }
+        category {
+            set field "categories"
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion ""}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] > 1 } {
+        # set portname again since the one we were passed may not have had the correct case
+        set portname [lindex $ilist 0 0]
+        ui_notice "The following versions of $portname are currently installed:"
+        foreach i [portlist_sortint $ilist] { 
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants} (active)"
+            }
+        }
+        return -code error "Registry error: Please specify the full version as recorded in the port registry."
+    } else {
+        return [lindex $ilist 0]
+    }
+}
+
+
+proc entry_for_portlist {portentry} {
+    global global_options global_variations
+
+    # Each portlist entry currently has the following elements in it:
+    #   url             if any
+    #   name
+    #   version         (version_revision)
+    #   variants array  (variant=>+-)
+    #   requested_variants array  (variant=>+-)
+    #   options array   (key=>value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) "" }
+    if {![info exists port(name)]}      { set port(name) "" }
+    if {![info exists port(version)]}   { set port(version) "" }
+    if {![info exists port(variants)]}  { set port(variants) "" }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) "" }
+    if {![info exists port(options)]}   { set port(options) [array get global_options] }
+
+    # If neither portname nor url is specified, then default to the current port
+    if { $port(url) eq "" && $port(name) eq "" } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq ""} {
+            ui_error "A default port name could not be supplied."
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) "$port(name)/[composite_version $port(version) $port(variants)]"
+    
+    return [array get port]
+}
+
+
+proc add_to_portlist {listname portentry} {
+    upvar $listname portlist
+    
+    # Form portlist entry and add to portlist
+    lappend portlist [entry_for_portlist $portentry]
+}
+
+
+proc add_ports_to_portlist {listname ports {overridelist ""}} {
+    upvar $listname portlist
+
+    array set overrides $overridelist
+
+    # Add each entry to the named portlist, overriding any values
+    # specified as overrides
+    foreach portentry $ports {
+        array set port $portentry
+        if ([info exists overrides(version)])   { set port(version) $overrides(version) }
+        if ([info exists overrides(variants)])  { set port(variants) $overrides(variants) }
+        if ([info exists overrides(requested_variants)])  { set port(requested_variants) $overrides(requested_variants) }
+        if ([info exists overrides(options)])   { set port(options) $overrides(options) }
+        add_to_portlist portlist [array get port]
+    }
+}
+
+
+proc url_to_portname { url {quiet 0} } {
+    # Save directory and restore the directory, since mportopen changes it
+    set savedir [pwd]
+    set portname ""
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg "Can't map the URL '$url' to a port description file (\"${result}\")."
+            ui_msg "Please verify that the directory and portfile syntax are correct."
+        }
+    } else {
+        array set portinfo [mportinfo $ctx]
+        set portname $portinfo(name)
+        mportclose $ctx
+    }
+    cd $savedir
+    return $portname
+}
+
+
+# Supply a default porturl/portname if the portlist is empty
+proc require_portlist { nameportlist {is_upgrade "no"} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 && (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        if {${is_upgrade} == "yes"} {
+            # $> port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # "upgrade", let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg "Nothing to upgrade."
+            return 1
+        }
+        ui_error "No ports matched the given expression"
+        return 1
+    }
+
+    if {[llength $portlist] == 0} {
+        set portlist [get_current_port]
+
+        if {[llength $portlist] == 0} {
+            # there was no port in current directory
+            return 1
+        }
+    }
+
+    return 0
+}
+
+
+# Execute the enclosed block once for every element in the portlist
+# When the block is entered, the following variables will have been set:
+#   portspec, porturl, portname, portversion, options, variations, requested_variations
+proc foreachport {portlist block} {
+    set savedir [pwd]
+    foreach portspec $portlist {
+    
+        # Set the variables for the block
+        uplevel 1 "array unset portspec; array set portspec { $portspec }"
+        uplevel 1 {
+            set porturl $portspec(url)
+            set portname $portspec(name)
+            set portversion $portspec(version)
+            array unset variations
+            array set variations $portspec(variants)
+            array unset requested_variations
+            array set requested_variations $portspec(requested_variants)
+            array unset options
+            array set options $portspec(options)
+        }
+        
+        # Invoke block
+        uplevel 1 $block
+        
+        # Restore cwd after each port, since mportopen changes it, and otherwise relative
+        # urls would break on subsequent passes
+        if {[file exists $savedir]} {
+            cd $savedir
+        } else {
+            cd ~
+        }
+    }
+}
+
+
+proc portlist_compare { a b } {
+    array set a_ $a
+    array set b_ $b
+    set namecmp [string equal -nocase $a_(name) $b_(name)]
+    if {$namecmp != 1} {
+        if {$a_(name) eq [lindex [lsort -dictionary [list $a_(name) $b_(name)]] 0]} {
+            return -1
+        }
+        return 1
+    }
+    set avr_ [split $a_(version) "_"]
+    set bvr_ [split $b_(version) "_"]
+    set versioncmp [vercmp [lindex $avr_ 0] [lindex $bvr_ 0]]
+    if {$versioncmp != 0} {
+        return $versioncmp
+    }
+    set ar_ [lindex $avr_ 1]
+    set br_ [lindex $bvr_ 1]
+    if {$ar_ < $br_} {
+        return -1
+    } elseif {$ar_ > $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name at version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list "name" [lindex $a 0] "version" "[lindex $a 1]_[lindex $a 2]"]
+    array set b_ [list "name" [lindex $b 0] "version" "[lindex $b 1]_[lindex $b 2]"]
+    return [portlist_compare [array get a_] [array get b_]]
+}
+
+# Same as portlist_sort, but with numeric indexes {name version revision}
+proc portlist_sortint { list } {
+    return [lsort -command portlist_compareint $list]
+}
+
+# sort portlist so dependents come before their dependencies
+proc portlist_sortdependents { portlist } {
+    foreach p $portlist {
+        array set pvals $p
+        lappend entries($pvals(name)) $p
+        if {![info exists dependents($pvals(name))]} {
+            set dependents($pvals(name)) {}
+            foreach result [registry::list_dependents $pvals(name)] {
+                lappend dependents($pvals(name)) [lindex $result 2]
+            }
+        }
+        array unset pvals
+    }
+    set ret {}
+    foreach p $portlist {
+        portlist_sortdependents_helper $p entries dependents seen ret
+    }
+    return $ret
+}
+
+proc portlist_sortdependents_helper {p up_entries up_dependents up_seen up_retlist} {
+    upvar $up_seen seen
+    if {![info exists seen($p)]} {
+        set seen($p) 1
+        upvar $up_entries entries $up_dependents dependents $up_retlist retlist
+        array set pvals $p
+        foreach dependent $dependents($pvals(name)) {
+            if {[info exists entries($dependent)]} {
+                foreach entry $entries($dependent) {
+                    portlist_sortdependents_helper $entry entries dependents seen retlist
+                }
+            }
+        }
+        lappend retlist $p
+    }
+}
+
+proc regex_pat_sanitize { s } {
+    set sanitized [regsub -all {[\\(){}+$.^]} $s {\\&}]
+    return $sanitized
+}
+
+##
+# Makes sure we get the current terminal size
+proc term_init_size {} {
+    global env
+
+    if {![info exists env(COLUMNS)] || ![info exists env(LINES)]} {
+        if {[isatty stdout]} {
+            set size [term_get_size stdout]
+
+            if {![info exists env(LINES)] && [lindex $size 0] > 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] && [lindex $size 1] > 0} {
+                set env(COLUMNS) [lindex $size 1]
+            }
+        }
+    }
+}
+
+##
+# Wraps a multi-line string at specified textwidth
+#
+# @see wrapline
+#
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrap {string maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set splitstring {}
+    set indentline $indentfirstline
+    foreach line [split $string "\n"] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring "\n"]
+}
+
+##
+# Wraps a line at specified textwidth
+#
+# @see wrap
+#
+# @param line input line
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrapline {line maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set string [split $line " "]
+    if {$indentfirstline == 0} {
+        set newline ""
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner " "
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] >= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner ""
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 && $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner " "
+    }
+    lappend lines $newline
+    return [join $lines "\n"]
+}
+
+##
+# Wraps a line at a specified width with a label in front
+#
+# @see wrap
+#
+# @param label label for output
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @return wrapped string
+proc wraplabel {label string maxlen {indent ""}} {
+    append label ": [string repeat " " [expr {[string length $indent] - [string length "$label: "]}]]"
+    return "$label[wrap $string $maxlen $indent 0]"
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first "@" $m] < 0} {
+            if {[string first ":" $m] >= 0} {
+                set m [regsub -- "(.*):(.*)" $m "\\2@\\1"] 
+            } else {
+                set m "$m at macports.org"
+            }
+        }
+        lappend result $m
+    }
+    return $result
+}
+
+
+##########################################
+# Port selection
+##########################################
+proc unique_results_to_portlist {infos} {
+    set result {}
+    array unset unique
+    foreach {name info} $infos {
+        array unset portinfo
+        array set portinfo $info
+        
+        set portentry [entry_for_portlist [list url $portinfo(porturl) name $name]]
+        
+        array unset entry
+        array set entry $portentry
+        
+        if {[info exists unique($entry(fullname))]} continue
+        set unique($entry(fullname)) 1
+        
+        lappend result $portentry
+    }
+    return $result
+}
+
+
+proc get_matching_ports {pattern {casesensitive no} {matchstyle glob} {field name}} {
+    if {[catch {set res [mportsearch $pattern $casesensitive $matchstyle $field]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        fatal "search for portname $pattern failed: $result"
+    }
+    set results [unique_results_to_portlist $res]
+    
+    # Return the list of all ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_all_ports {} {
+    global all_ports_cache
+
+    if {![info exists all_ports_cache]} {
+         if {[catch {set res [mportlistall]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "listing all ports failed: $result"
+        }
+        set results [unique_results_to_portlist $res]
+        set all_ports_cache [portlist_sort $results]
+    }
+    return $all_ports_cache
+}
+
+
+proc get_current_ports {} {
+    # This is just a synonym for get_current_port that
+    # works with the regex in element
+    return [get_current_port]
+}
+
+
+proc get_current_port {} {
+    set url file://.
+    set portname [url_to_portname $url]
+    if {$portname eq ""} {
+        ui_msg "To use the current port, you must be in a port's directory."
+        return [list]
+    }
+
+    set results {}
+    add_to_portlist results [list url $url name $portname]
+    return $results
+}
+
+
+proc get_installed_ports { {ignore_active yes} {active yes} } {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [split_variants [lindex $i 3]]
+        set iactive [lindex $i 4]
+
+        if { ${ignore_active} == "yes" || (${active} == "yes") == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants $ivariants]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_uninstalled_ports {} {
+    # Return all - installed
+    set all [get_all_ports]
+    set installed [get_installed_ports]
+    return [opComplement $all $installed]
+}
+
+
+proc get_active_ports {} {
+    return [get_installed_ports no yes]
+}
+
+
+proc get_inactive_ports {} {
+    return [get_installed_ports no no]
+}
+
+proc get_actinact_ports {} {
+    set inactive_ports [get_inactive_ports]
+    set active_ports [get_active_ports]
+    set results {}
+
+    foreach port $inactive_ports {
+        array set portspec $port
+        set portname $portspec(name)
+        lappend inact($portname) $port
+    }
+
+    foreach port $active_ports {
+        array set portspec $port
+        set portname $portspec(name)
+
+        if {[info exists inact($portname)]} {
+            if {![info exists added_inact($portname)]} {
+                foreach inact_spec $inact($portname) {
+                    lappend results $inact_spec
+                }
+                set added_inact($portname) 1
+            }
+            lappend results $port
+        }
+    }
+    return $results
+}
+
+
+proc get_outdated_ports {} {
+    # Get the list of installed ports
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] > 0 } {
+        foreach i $ilist {
+
+            # Get information about the installed port
+            set portname            [lindex $i 0]
+            set installed_version   [lindex $i 1]
+            set installed_revision  [lindex $i 2]
+            set installed_compound  "${installed_version}_${installed_revision}"
+            set installed_variants  [lindex $i 3]
+
+            set is_active           [lindex $i 4]
+            if {$is_active == 0} continue
+
+            set installed_epoch     [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                fatal "lookup of portname $portname failed: $result"
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+
+            # Get information about latest available version and revision
+            set latest_version $portinfo(version)
+            set latest_revision     0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     "${latest_version}_${latest_revision}"
+            set latest_epoch        0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch    $portinfo(epoch)
+            }
+
+            # Compare versions, first checking epoch, then version, then revision
+            set comp_result 0
+            if {$installed_version != $latest_version} {
+                set comp_result [expr {$installed_epoch - $latest_epoch}]
+                if { $comp_result == 0 } {
+                    set comp_result [vercmp $installed_version $latest_version]
+                }
+            }
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            if {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision $installed_variants $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                }
+            }
+
+            # Add outdated ports to our results list
+            if { $comp_result < 0 } {
+                add_to_portlist results [list name $portname version $installed_compound variants [split_variants $installed_variants]]
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_obsolete_ports {} {
+    set ilist [get_installed_ports]
+    set results {}
+
+    foreach i $ilist {
+        array set port $i
+
+        if {[catch {mportlookup $port(name)} result]} {
+            ui_debug "$::errorInfo"
+            break_softcontinue "lookup of portname $portname failed: $result" 1 status
+        }
+
+        if {[llength $result] < 2} {
+            lappend results $i
+        }
+    }
+
+    # Return the list of ports, already sorted
+    return [portlist_sort $results]
+}
+
+# return ports that have registry property $propname set to $propval
+proc get_ports_with_prop {propname propval} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [lindex $i 3]
+        set iepoch [lindex $i 5]
+        set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
+        if {[registry::property_retrieve $regref $propname] == $propval} {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants [split_variants $ivariants]]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+proc get_requested_ports {} {
+    return [get_ports_with_prop requested 1]
+}
+
+proc get_unrequested_ports {} {
+    return [get_ports_with_prop requested 0]
+}
+
+proc get_leaves_ports {} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq ""} {
+            add_to_portlist results [list name $iname version "[lindex $i 1]_[lindex $i 2]" variants [split_variants [lindex $i 3]]]
+        }
+    }
+    return [portlist_sort [opIntersection $results [get_unrequested_ports]]]
+}
+
+proc get_dependent_ports {portname recursive} {
+    registry::open_dep_map
+    set deplist [registry::list_dependents $portname]
+    # could return specific versions here using registry2.0 features
+    set results {}
+    foreach dep $deplist {
+        add_to_portlist results [list name [lindex $dep 2]]
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex $dep 2]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    set rdeplist [registry::list_dependents $depname]
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex $rdep 2]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_dep_ports {portname recursive} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its deps
+    set results {}
+    set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+
+    set deplist {}
+    foreach type $deptypes {
+        if {[info exists portinfo($type)]} {
+            foreach dep $portinfo($type) {
+                add_to_portlist results [list name [lindex [split $dep :] end]]
+                lappend deplist $dep
+            }
+        }
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        return -code error "lookup of portname $depname failed: $result"
+                    }
+                    if {[llength $result] < 2} {
+                        ui_error "Port $depname not found"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                
+                    # open its portfile
+                    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+                        ui_debug "$::errorInfo"
+                        ui_error "Unable to open port: $result"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [mportinfo $mport]
+                    mportclose $mport
+
+                    # collect its deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                add_to_portlist results [list name [lindex [split $rdep :] end]]
+                                lappend rdeplist $rdep
+                            }
+                        }
+                    }
+
+                    # add them to the lists
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex [split $rdep :] end]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+proc get_subports {portname} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its subports
+    set results {}
+
+    if {[info exists portinfo(subports)]} {
+        foreach subport $portinfo(subports) {
+            add_to_portlist results [list name $subport]
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+##########################################
+# Port expressions
+##########################################
+proc portExpr { resname } {
+    upvar $resname reslist
+    set result [seqExpr reslist]
+    return $result
+}
+
+
+proc seqExpr { resname } {
+    upvar $resname reslist
+    
+    # Evaluate a sequence of expressions a b c...
+    # These act the same as a or b or c
+
+    set result 1
+    while {$result} {
+        switch -- [lookahead] {
+            ;       -
+            )       -
+            _EOF_   { break }
+        }
+
+        set blist {}
+        set result [orExpr blist]
+        if {$result} {
+            # Calculate the union of result and b
+            set reslist [opUnion $reslist $blist]
+        }
+    }
+    
+    return $result
+}
+
+
+proc orExpr { resname } {
+    upvar $resname reslist
+    
+    set a [andExpr reslist]
+    while ($a) {
+        switch -- [lookahead] {
+            or {
+                    advance
+                    set blist {}
+                    if {![andExpr blist]} {
+                        return 0
+                    }
+                        
+                    # Calculate a union b
+                    set reslist [opUnion $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc andExpr { resname } {
+    upvar $resname reslist
+    
+    set a [unaryExpr reslist]
+    while {$a} {
+        switch -- [lookahead] {
+            and {
+                    advance
+                    
+                    set blist {}
+                    set b [unaryExpr blist]
+                    if {!$b} {
+                        return 0
+                    }
+                    
+                    # Calculate a intersect b
+                    set reslist [opIntersection $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc unaryExpr { resname } {
+    upvar $resname reslist
+    set result 0
+
+    switch -- [lookahead] {
+        !   -
+        not {
+                advance
+                set blist {}
+                set result [unaryExpr blist]
+                if {$result} {
+                    set all [get_all_ports]
+                    set reslist [opComplement $all $blist]
+                }
+            }
+        default {
+                set result [element reslist]
+            }
+    }
+    
+    return $result
+}
+
+
+proc element { resname } {
+    upvar $resname reslist
+    set el 0
+    
+    set url ""
+    set name ""
+    set version ""
+    array unset requested_variants
+    array unset options
+    
+    set token [lookahead]
+    switch -regex -- $token {
+        ^\\)$               -
+        ^\;                 -
+        ^_EOF_$             { # End of expression/cmd/file
+        }
+
+        ^\\($               { # Parenthesized Expression
+            advance
+            set el [portExpr reslist]
+            if {!$el || ![match ")"]} {
+                set el 0
+            }
+        }
+
+        ^all(@.*)?$         -
+        ^installed(@.*)?$   -
+        ^uninstalled(@.*)?$ -
+        ^active(@.*)?$      -
+        ^inactive(@.*)?$    -
+        ^actinact(@.*)?$    -
+        ^leaves(@.*)?$      -
+        ^outdated(@.*)?$    -
+        ^obsolete(@.*)?$    -
+        ^requested(@.*)?$   -
+        ^unrequested(@.*)?$ -
+        ^current(@.*)?$     {
+            # A simple pseudo-port name
+            advance
+
+            # Break off the version component, if there is one
+            regexp {^(\w+)(@.*)?} $token matchvar name remainder
+
+            add_multiple_ports reslist [get_${name}_ports] $remainder
+
+            set el 1
+        }
+
+        ^variants:          -
+        ^variant:           -
+        ^description:       -
+        ^portdir:           -
+        ^homepage:          -
+        ^epoch:             -
+        ^platforms:         -
+        ^platform:          -
+        ^name:              -
+        ^long_description:  -
+        ^maintainers:       -
+        ^maintainer:        -
+        ^categories:        -
+        ^category:          -
+        ^version:           -
+        ^depends_lib:       -
+        ^depends_build:     -
+        ^depends_run:       -
+        ^depends_extract:   -
+        ^depends_fetch:     -
+        ^replaced_by:       -
+        ^revision:          -
+        ^subport:           -
+        ^subports:          -
+        ^license:           { # Handle special port selectors
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            # Remap friendly names to actual names
+            set field [map_friendly_field_names $field]
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp $field]
+            set el 1
+        }
+
+        ^depends:           { # A port selector shorthand for depends_{lib,build,run,fetch,extract}
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_lib"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_build"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_run"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_extract"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_fetch"]
+
+            set el 1
+        }
+
+        ^dependentof:       -
+        ^rdependentof:      {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdependentof"]
+            add_multiple_ports reslist [get_dependent_ports $portname $recursive]
+            
+            set el 1
+        }
+        
+        ^depof:             -
+        ^rdepof:            {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdepof"]
+            add_multiple_ports reslist [get_dep_ports $portname $recursive]
+            
+            set el 1
+        }
+
+        ^subportof:         {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            add_multiple_ports reslist [get_subports $portname]
+
+            set el 1
+        }
+
+        [][?*]              { # Handle portname glob patterns
+            advance; add_multiple_ports reslist [get_matching_ports $token no glob]
+            set el 1
+        }
+
+        ^\\w+:.+            { # Handle a url by trying to open it as a port and mapping the name
+            advance
+            set name [url_to_portname $token]
+            if {$name ne ""} {
+                parsePortSpec version requested_variants options
+                add_to_portlist reslist [list url $token \
+                  name $name \
+                  version $version \
+                  requested_variants [array get requested_variants] \
+                  variants [array get requested_variants] \
+                  options [array get options]]
+                set el 1
+            } else {
+                ui_error "Can't open URL '$token' as a port"
+                set el 0
+            }
+        }
+
+        default             { # Treat anything else as a portspec (portname, version, variants, options
+            # or some combination thereof).
+            parseFullPortSpec url name version requested_variants options
+            add_to_portlist reslist [list url $url \
+              name $name \
+              version $version \
+              requested_variants [array get requested_variants] \
+              variants [array get requested_variants] \
+              options [array get options]]
+            set el 1
+        }
+    }
+
+    return $el
+}
+
+
+proc add_multiple_ports { resname ports {remainder ""} } {
+    upvar $resname reslist
+    
+    set version ""
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne ""} { set overrides(version) $version }
+    if {[array size variants]} {
+        # we always record the requested variants separately,
+        # but requested ones always override existing ones
+        set overrides(requested_variants) [array get variants]
+        set overrides(variants) [array get variants]
+    }
+    if {[array size options]} { set overrides(options) [array get options] }
+
+    add_ports_to_portlist reslist $ports [array get overrides]
+}
+
+
+proc unique_entries { entries } {
+    # Form the list of all the unique elements in the list a,
+    # considering only the port fullname, and taking the first
+    # found element first
+    set result {}
+    array unset unique
+    foreach item $entries {
+        array set port $item
+        if {[info exists unique($port(fullname))]} continue
+        set unique($port(fullname)) 1
+        lappend result $item
+    }
+    return $result
+}
+
+
+proc opUnion { a b } {
+    # Return the unique elements in the combined two lists
+    return [unique_entries [concat $a $b]]
+}
+
+
+proc opIntersection { a b } {
+    set result {}
+    
+    # Rules we follow in performing the intersection of two port lists:
+    #
+    #   a/, a/          ==> a/
+    #   a/, b/          ==>
+    #   a/, a/1.0       ==> a/1.0
+    #   a/1.0, a/       ==> a/1.0
+    #   a/1.0, a/2.0    ==>
+    #
+    #   If there's an exact match, we take it.
+    #   If there's a match between simple and discriminated, we take the later.
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem [unique_entries $b] {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, matching against b
+    foreach aitem [unique_entries $a] {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+        foreach match $matches {
+            if {$simpleform} {
+                set i $bfull($match)
+                lappend result [lindex $b $i]
+            } else {
+                lappend result $aitem
+            }
+        }
+    }
+    
+    return $result
+}
+
+
+proc opComplement { a b } {
+    set result {}
+    
+    # Return all elements of a not matching elements in b
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem $b {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, taking all those items that don't match b
+    foreach aitem $a {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+
+        # We copy this element to result only if it didn't match against b
+        if {![llength $matches]} {
+            lappend result $aitem
+        }
+    }
+    
+    return $result
+}
+
+
+proc parseFullPortSpec { urlname namename vername varname optname } {
+    upvar $urlname porturl
+    upvar $namename portname
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    set portname ""
+    set portversion ""
+    array unset portvariants
+    array unset portoptions
+    
+    if { [moreargs] } {
+        # Look first for a potential portname
+        #
+        # We need to allow a wide variety of tokens here, because of actions like "provides"
+        # so we take a rather lenient view of what a "portname" is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder ""
+        if {![regexp {^(@|[-+]([[:alpha:]_]+[\w\.]*)|[[:alpha:]_]+[\w\.]*=)} $token match]} {
+            advance
+            regexp {^([^@]+)(@.*)?} $token match portname remainder
+            
+            # If the portname contains a /, then try to use it as a URL
+            if {[string match "*/*" $portname]} {
+                set url "file://$portname"
+                set name [url_to_portname $url 1]
+                if { $name ne "" } {
+                    # We mapped the url to valid port
+                    set porturl $url
+                    set portname $name
+                    # Continue to parse rest of portspec....
+                } else {
+                    # We didn't map the url to a port; treat it
+                    # as a raw string for something like port contents
+                    # or cd
+                    set porturl ""
+                    # Since this isn't a port, we don't try to parse
+                    # any remaining portspec....
+                    return
+                }
+            }
+        }
+        
+        # Now parse the rest of the spec
+        parsePortSpec portversion portvariants portoptions $remainder
+    }
+}
+
+# check if the install prefix is writable
+# should be called by actions that will modify it
+proc prefix_unwritable {} {
+    global macports::portdbpath
+    if {[file writable $portdbpath]} {
+        return 0
+    } else {
+        ui_error "Insufficient privileges to write to MacPorts install prefix."
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder ""} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion ""
+    array unset portoptions
+    array set portoptions [array get global_options]
+    array unset portvariants
+    
+    # Parse port version/variants/options
+    set opt $remainder
+    set adv 0
+    set consumed 0
+    for {set firstTime 1} {$opt ne "" || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq ""} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime && [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first "/" $opt]
+            if {$sepPos >= 0} {
+                # Version terminated by "/" to disambiguate -variant from part of version
+                set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                set opt [string range $opt [expr {$sepPos + 1}] end]
+            } else {
+                # Version terminated by "+", or else is complete
+                set sepPos [string first "+" $opt]
+                if {$sepPos >= 0} {
+                    # Version terminated by "+"
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt ""
+                }
+            }
+            set consumed 1
+        } else {
+            # Parse all other options
+            
+            # Look first for a variable setting: VARNAME=VALUE
+            if {[regexp {^([[:alpha:]_]+[\w\.]*)=(.*)} $opt match key val] == 1} {
+                # It's a variable setting
+                set portoptions($key) "\"$val\""
+                set opt ""
+                set consumed 1
+            } elseif {[regexp {^([-+])([[:alpha:]_]+[\w\.]*)} $opt match sign variant] == 1} {
+                # It's a variant
+                set portvariants($variant) $sign
+                set opt [string range $opt [expr {[string length $variant] + 1}] end]
+                set consumed 1
+            } else {
+                # Not an option we recognize, so break from port option processing
+                if { $consumed && $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds ""
+        if {[info exists cmd_opts_array($action)]} {
+            foreach opt $cmd_opts_array($action) {
+                if {[llength $opt] == 1} {
+                    set name $opt
+                    set optc 0
+                } else {
+                    set name [lindex $opt 0]
+                    set optc [lindex $opt 1]
+                }
+
+                append cmds " --$name"
+
+                for {set i 1} {$i <= $optc} {incr i} {
+                    append cmds " <arg$i>"
+                }
+            }
+        }
+        set args ""
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <arguments>"
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <portlist>"
+        }
+
+        set ret "Usage: "
+        set len [string length $action]
+        append ret [wrap "$action$cmds$args" 0 [string repeat " " [expr {8 + $len}]] 0]
+        append ret "\n"
+
+        return $ret
+    }
+
+    return -1
+}
+
+proc action_usage { action portlist opts } {
+    if {[llength $portlist] == 0} {
+        print_usage
+        return 0
+    }
+
+    foreach topic $portlist {
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile "$macports::prefix/var/macports/port-help.tcl"
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr "Error reading helpfile $helpfile: $err"
+            return 1
+        }
+    } else {
+        puts stderr "Unable to open help file $helpfile"
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr "No help for topic $topic"
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+
+        puts stderr $porthelp($topic)
+    }
+
+    return 0
+}
+
+
+proc action_log { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array unset portinfo
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+            set portname $portinfo(name)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            array unset portinfo
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] "main.log"]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue "Could not open file $logfile: $result" 1 status
+            }
+            set data [read $fp]
+            set data [split $data "\n"]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase "\[a-z\]*"
+            }
+
+            if {[info exists global_options(ports_log_level)]} {
+                set index [lsearch -exact ${macports::ui_priorities} $global_options(ports_log_level)]
+                if {$index == -1} {
+                    set prefix ""
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] "|"]
+                }
+            } else {
+                set prefix "\[a-z\]*"
+            }
+            foreach line $data {
+                set exp "^:($prefix|any):($phase|any) (.*)$"
+                if {[regexp $exp $line -> lpriority lphase lmsg] == 1} {
+                    puts "[macports::ui_prefix_default $lpriority]$lmsg"
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue "Log file for port $portname not found" 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator ""
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] && $options(ports_info_index)} {
+            set index_only 1
+        }
+        puts -nonewline $separator
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq "" || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!$index_only} {
+            # Add any global_variations to the variations
+            # specified for the port (so we get e.g. dependencies right)
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+ 
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            unset options(subport)
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "no PortIndex entry found for $portname"
+            continue
+        }
+        array unset options ports_info_index
+
+        # Understand which info items are actually lists
+        # (this could be overloaded to provide a generic formatting code to
+        # allow us to, say, split off the prefix on libs)
+        array set list_map "
+            categories      1
+            depends_fetch   1
+            depends_extract 1
+            depends_build   1
+            depends_lib     1
+            depends_run     1
+            maintainers     1
+            platforms       1
+            variants        1
+            conflicts       1
+            subports        1
+        "
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     ""
+            variants    Variants
+            depends_fetch "Fetch Dependencies"
+            depends_extract "Extract Dependencies"
+            depends_build "Build Dependencies"
+            depends_run "Runtime Dependencies"
+            depends_lib "Library Dependencies"
+            description "Brief Description"
+            long_description "Description"
+            fullname    "Full Name: "
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   "Conflicts with"
+            replaced_by "Replaced by"
+            subports    "Sub-ports"
+        }
+
+        # Wrap-length map for pretty printing
+        array set pretty_wrap {
+            heading 0
+            replaced_by 22
+            variants 22
+            depends_fetch 22
+            depends_extract 22
+            depends_build 22
+            depends_run 22
+            depends_lib 22
+            description 22
+            long_description 22
+            homepage 22
+            platforms 22
+            license 22
+            conflicts 22
+            maintainers 22
+            subports 22
+        }
+
+        # Interpret a convenient field abbreviation
+        if {[info exists options(ports_info_depends)] && $options(ports_info_depends) eq "yes"} {
+            array unset options ports_info_depends
+            set options(ports_info_depends_fetch) yes
+            set options(ports_info_depends_extract) yes
+            set options(ports_info_depends_build) yes
+            set options(ports_info_depends_lib) yes
+            set options(ports_info_depends_run) yes
+        }
+                
+        # Set up our field separators
+        set show_label 1
+        set field_sep "\n"
+        set subfield_sep ", "
+        set pretty_print 0
+        
+        # For human-readable summary, which is the default with no options
+        if {[llength [array get options ports_info_*]] == 0} {
+            set pretty_print 1
+        } elseif {[info exists options(ports_info_pretty)]} {
+            set pretty_print 1
+            array unset options ports_info_pretty
+        }
+
+        # Tune for sort(1)
+        if {[info exists options(ports_info_line)]} {
+            array unset options ports_info_line
+            set noseparator 1
+            set show_label 0
+            set field_sep "\t"
+            set subfield_sep ","
+        }
+        
+        # Figure out whether to show field name
+        set quiet [macports::ui_isset ports_quiet]
+        if {$quiet} {
+            set show_label 0
+        }
+        # In pretty-print mode we also suppress messages, even though we show
+        # most of the labels:
+        if {$pretty_print} {
+            set quiet 1
+        }
+
+        # Spin through action options, emitting information for any found
+        set fields {}
+        set opts_todo [array names options ports_info_*]
+        set fields_tried {}
+        if {![llength $opts_todo]} {
+            set opts_todo {ports_info_heading
+                ports_info_replaced_by
+                ports_info_subports
+                ports_info_variants 
+                ports_info_skip_line
+                ports_info_long_description ports_info_homepage 
+                ports_info_skip_line ports_info_depends_fetch
+                ports_info_depends_extract ports_info_depends_build
+                ports_info_depends_lib ports_info_depends_run
+                ports_info_conflicts
+                ports_info_platforms ports_info_license
+                ports_info_maintainers
+            }
+        }
+        foreach { option } $opts_todo {
+            set opt [string range $option 11 end]
+            # Artificial field name for formatting
+            if {$pretty_print && $opt eq "skip_line"} {
+                lappend fields ""
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq "heading"} {
+                set inf "$portinfo(name) @$portinfo(version)"
+                set ropt "heading"
+                if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                    append inf "_$portinfo(revision)"
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf " ([join $portinfo(categories) ", "])"
+                }
+            } elseif {$opt eq "fullname"} {
+                set inf "$portinfo(name) @"
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt "fullname"
+            } else {
+                # Map from friendly name
+                set ropt [map_friendly_field_names $opt]
+                
+                # If there's no such info, move on
+                if {![info exists portinfo($ropt)]} {
+                    set inf ""
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label ""
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label "$opt: "
+            }
+            
+            # Format the data
+            if { $ropt eq "maintainers" } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq "variants"} {
+                    # Use the new format for variants iff it exists in
+                    # PortInfo. This key currently does not exist outside of
+                    # trunk (1.8.0).
+                    array unset vinfo
+                    if {[info exists portinfo(vinfo)]} {
+                        array set vinfo $portinfo(vinfo)
+                    }
+
+                    set pi_vars $inf
+                    set inf {}
+                    foreach v [lsort $pi_vars] {
+                        set varmodifier ""
+                        if {[info exists variations($v)]} {
+                            # selected by command line, prefixed with +/-
+                            set varmodifier $variations($v)
+                        } elseif {[info exists global_variations($v)]} {
+                            # selected by variants.conf, prefixed with (+)/(-)
+                            set varmodifier "($global_variations($v))"
+                            # Retrieve additional information from the new key.
+                        } elseif {[info exists vinfo]} {
+                            array unset variant
+                            array set variant $vinfo($v)
+                            if {[info exists variant(is_default)]} {
+                                set varmodifier "\[$variant(is_default)]"
+                            }
+                        }
+                        lappend inf "$varmodifier$v"
+                    }
+                } elseif {[string match "depend*" $ropt] 
+                          && ![macports::ui_isset ports_verbose]} {
+                    set pi_deps $inf
+                    set inf {}
+                    foreach d $pi_deps {
+                        lappend inf [lindex [split $d :] end]
+                    }
+                }
+            } 
+            #End of special pretty-print formatting for certain fields
+            if {[info exists list_map($ropt)]} {
+                set field [join $inf $subfield_sep]
+            } else {
+                set field $inf
+            }
+            
+            # Assemble the entry
+            if {$pretty_print} {
+                # The two special fields are considered headings and are
+                # emitted immediately, rather than waiting. Also they are not
+                # recorded on the list of fields tried
+                if {$ropt eq "heading" || $ropt eq "fullname"} {
+                    puts "$label$field"
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq ""} {
+                    continue
+                }
+                if {$label eq ""} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat " " $wrap_len]]
+                } else {
+                    set wrap_len [string length $label]
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wraplabel $label $field 0 [string repeat " " $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields "$label$field"
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print && [llength $fields_tried]} {
+                puts -nonewline "$portinfo(name) has no "
+                puts [join $fields_tried ", "]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator "--\n"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_location { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        if { [catch {set ilist [registry_installed $portname [composite_version $portversion [array get variations]]]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port location failed: $result" 1 status
+        } else {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0]
+            set version [lindex $ilist 1]
+            set revision [lindex $ilist 2]
+            set variants [lindex $ilist 3]
+            set epoch [lindex $ilist 5]
+        }
+
+        set ref [registry::open_entry $portname $version $revision $variants $epoch]
+        set imagedir [registry::property_retrieve $ref location]
+        ui_notice "Port $portname ${version}_${revision}${variants} is installed as an image in:"
+        puts $imagedir
+    }
+    
+    return $status
+}
+
+
+proc action_notes { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set status 0
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue "The lookup of '$portname' failed: $result" \
+                                1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "The port '$portname' was not found" 1 status
+            }
+
+            # Retrieve the port's URL.
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        }
+        
+        # Add any global_variations to the variations
+        # specified for the port
+        array unset merged_variations
+        array set merged_variations [array get variations]
+        foreach { variation value } [array get global_variations] { 
+            if { ![info exists merged_variations($variation)] } { 
+                set merged_variations($variation) $value 
+            } 
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+
+        # Open the Portfile associated with this port.
+        if {[catch {set mport [mportopen $porturl [array get options] \
+                                         [array get merged_variations]]} \
+                   result]} {
+            ui_debug $::errorInfo
+            break_softcontinue [concat "The URL '$porturl' could not be" \
+                                       "opened: $result"] 1 status
+        }
+        array unset portinfo
+        array set portinfo [mportinfo $mport]
+        mportclose $mport
+
+        # Return the notes associated with this Portfile.
+        if {[info exists portinfo(notes)]} {
+            set portnotes $portinfo(notes)
+        } else {
+            set portnotes {}
+        }
+
+        # Retrieve the port's name once more to ensure it has the proper case.
+        set portname $portinfo(name)
+
+        # Display the notes.
+        if {$portnotes ne {}} {
+            ui_notice "$portname has the following notes:"
+            foreach note $portnotes {
+                puts [wrap $note 0 "  " 1]
+            }
+        } else {
+            puts "$portname has no notes."
+        }
+    }
+    return $status
+}
+
+
+proc action_provides { action portlist opts } {
+    # In this case, portname is going to be used for the filename... since
+    # that is the first argument we expect... perhaps there is a better way
+    # to do this?
+    if { ![llength $portlist] } {
+        ui_error "Please specify a filename to check which port provides that file."
+        return 1
+    }
+    foreach filename $portlist {
+        set file [file normalize $filename]
+        if {[file exists $file] || ![catch {file type $file}]} {
+            if {![file isdirectory $file] || [file type $file] eq "link"} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts "$file is provided by: $port"
+                } else {
+                    puts "$file is not provided by a MacPorts port."
+                }
+            } else {
+                puts "$file is a directory."
+            }
+        } else {
+            puts "$file does not exist."
+        }
+    }
+    registry::close_file_map
+    
+    return 0
+}
+
+
+proc action_activate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_activate_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[$regref installtype] eq "image" && [registry::run_target $regref activate [array get options]]} {
+                continue
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::activate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port activate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping activate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_deactivate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    set portlist [portlist_sortdependents $portlist]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_deactivate_no-exec)]
+            && ![catch {set ilist [registry::active $portname]}]} {
+
+            set i [lindex $ilist 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            if {$composite_version eq "" || $composite_version == "${iversion}_${irevision}${ivariants}"} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq "image" && [registry::run_target $regref deactivate [array get options]]} {
+                    continue
+                }
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::deactivate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port deactivate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping deactivate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug "action_select \[$portlist] \[$opts]..."
+
+    array set opts_array $opts
+    set commands [array names opts_array ports_select_*]
+    array unset opts_array
+
+    # Error out if no group is specified or command is not --summary.
+    if {[llength $portlist] < 1 && [string map {ports_select_ ""} [lindex $commands 0]] != "summary"} {
+        ui_error "port select \[--list|--set|--show|--summary] \<group> \[<version>]"
+        return 1
+    }
+
+    set group [lindex $portlist 0]
+    
+    # If no command (--set, --show, --list, --summary) is specified *but*
+    #  more than one argument is specified, default to the set command.
+    if {[llength $commands] < 1 && [llength $portlist] > 1} {
+        set command set
+        ui_debug [concat "Although no command was specified, more than " \
+                         "one argument was specified.  Defaulting to the " \
+                         "'set' command..."]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] < 1} {
+        set command list
+        ui_debug [concat "No command was specified. Defaulting to the " \
+                         "'list' command..."]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] > 1} {
+        ui_error [concat "Multiple commands were specified. Only one " \
+                         "command may be specified at a time."]
+        return 1
+    } else {
+        set command [string map {ports_select_ ""} [lindex $commands 0]]
+        ui_debug "The '$command' command was specified."
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'list' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn "Unable to get active selected version: $selected_version"
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error "The 'list' command failed: $versions"
+                return 1
+            }
+
+            ui_notice "Available versions for $group:"
+            foreach v $versions {
+                ui_notice -nonewline "\t"
+                if {$selected_version == $v} {
+                    ui_msg "$v (active)"
+                } else {
+                    ui_msg "$v"
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] < 2} {
+                ui_error [concat "The 'set' command expects two " \
+                                 "arguments: <group>, <version>"]
+                return 1
+            } elseif {[llength $portlist] > 2} {
+                ui_warn [concat "The 'set' command only expects two " \
+                                "arguments. Extra arguments will be " \
+                                "ignored."]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline "Selecting '$version' for '$group' "
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg "failed: $result"
+                return 1
+            }
+            ui_msg "succeeded. '$version' is now active."
+            return 0
+        }
+        show {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'show' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error "The 'show' command failed: $selected_version"
+                return 1
+            }
+            puts [concat "The currently selected version for '$group' is " \
+                         "'$selected_version'."]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] > 0} {
+                ui_warn [concat "The 'summary' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error "The 'summary' command failed: $portgroups"
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr "%-*s  %-*s  %s"
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn "The list of options for the select group $pg could not be obtained: $versions"
+                    continue
+                }
+                # remove "none", sort the list, append none at the end
+                set noneidx [lsearch -exact $versions "none"]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions "none"
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn "The currently selected option for the select group $pg could not be obtained: $selected_version"
+                    continue
+                }
+                set groupdesc(selected) $selected_version
+
+                set w1 [expr {max($w1, [string length $pg])}]
+                set w2 [expr {max($w2, [string length $selected_version])}]
+
+                lappend groups [array get groupdesc]
+                array unset groupdesc
+            }
+            puts [format $formatStr $w1 "Name" $w2 "Selected" "Options"]
+            puts [format $formatStr $w1 "====" $w2 "========" "======="]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) " "]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error "An unknown command '$command' was specified."
+            return 1
+        }
+    }
+}
+
+
+proc action_selfupdate { action portlist opts } {
+    global global_options
+    if { [catch {macports::selfupdate [array get global_options] base_updated} result ] } {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_error "$result"
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg "Please run `port -v selfupdate' for details."
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal "port selfupdate failed: $result"
+    }
+    
+    if {$base_updated} {
+        # exit immediately if in batch/interactive mode
+        return -999
+    } else {
+        return 0
+    }
+}
+
+
+proc action_setrequested { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    # set or unset?
+    set val [string equal $action "setrequested"]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info "Setting requested flag for $portname to $val"
+            foreach i $ilist {
+                set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+                registry::property_store $regref requested $val
+            }
+        } else {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist "yes"] || ([prefix_unwritable] && ![macports::global_option_isset ports_dryrun])} {
+        return 1
+    }
+
+    # shared depscache for all ports in the list
+    array set depscache {}
+    set status 0
+    foreachport $portlist {
+        if {![info exists depscache(port:$portname)]} {
+            set status [macports::upgrade $portname "port:$portname" [array get requested_variations] [array get options] depscache]
+            # status 2 means the port was not found in the index,
+            # status 3 means the port is not installed
+            if {$status != 0 && $status != 2 && $status != 3 && ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 && $status != 2 && $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] && ${macports::revupgrade_autorun} && ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+    macports::doctor_main
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+    macports::reclaim_main  
+    return 0
+}
+
+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 } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Version: "
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Platform: "
+    }
+    puts "${macports::os_platform} ${macports::os_major} ${macports::os_arch}"
+    return 0
+}
+
+
+proc action_dependents { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set ilist {}
+
+    registry::open_dep_map
+
+    set status 0
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if { [catch {set ilist [registry::installed $portname $composite_version]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        } else {
+            # choose the active version if there is one
+            set index 0
+            foreach i $ilist {
+                if {[lindex $i 4]} {
+                    set found 1
+                    break
+                }
+                incr index
+            }
+            if {![info exists found]} {
+                set index 0
+            }
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist $index 0]
+            set iversion [lindex $ilist $index 1]
+            set irevision [lindex $ilist $index 2]
+            set ivariants [lindex $ilist $index 3]
+        }
+        
+        set deplist [registry::list_dependents $portname $iversion $irevision $ivariants]
+        if { [llength $deplist] > 0 } {
+            if {$action eq "rdependents"} {
+                set toplist $deplist
+                while 1 {
+                    set newlist {}
+                    foreach dep $deplist {
+                        set depname [lindex $dep 2]
+                        if {![info exists seen($depname)]} {
+                            set seen($depname) 1
+                            set rdeplist [registry::list_dependents $depname]
+                            foreach rdep $rdeplist {
+                                lappend newlist $rdep
+                            }
+                            set dependentsof($depname) $rdeplist
+                        }
+                    }
+                    if {[llength $newlist] > 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice "The following ports are dependent on ${portname}:"
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos >= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] <= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] && [string is true -strict $options(ports_rdependents_full)])} {
+                        puts "${spaces}${cur_portname}"
+                        set seen($cur_portname) 1
+                        incr cur_pos
+                        set pos_stack [lreplace $pos_stack end end $cur_pos]
+                        if {[info exists dependentsof($cur_portname)]} {
+                            lappend portstack $dependentsof($cur_portname)
+                            lappend pos_stack 0
+                        }
+                        continue
+                    }
+                    incr cur_pos
+                    set pos_stack [lreplace $pos_stack end end $cur_pos]
+                }
+            } else {
+                foreach dep $deplist {
+                    set depport [lindex $dep 2]
+                    if {[macports::ui_isset ports_quiet]} {
+                        ui_msg "$depport"
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg "$depport depends on $portname"
+                    } else {
+                        ui_msg "$depport depends on $portname (by [lindex $dep 1]:)"
+                    }
+                }
+            }
+        } else {
+            ui_notice "$portname has no dependents."
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator ""
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] && [string is true -strict $options(ports_${action}_no-build)]} {
+            set deptypes {depends_lib depends_run}
+        } else {
+            set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+        }
+
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+            # Add any global_variations to the variations
+            # specified for the port, so we get dependencies right
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn "port ${action} --index does not work with the 'current' pseudo-port"
+            continue
+        }
+        set portname $portinfo(name)
+
+        set deplist {}
+        set deps_output {}
+        set ndeps 0
+        array set labeldict {depends_fetch Fetch depends_extract Extract depends_build Build depends_lib Library depends_run Runtime}
+        # get list of direct deps
+        foreach type $deptypes {
+            if {[info exists portinfo($type)]} {
+                if {$action eq "rdeps" || [macports::ui_isset ports_verbose]} {
+                    foreach dep $portinfo($type) {
+                        lappend deplist $dep
+                    }
+                } else {
+                    foreach dep $portinfo($type) {
+                        lappend deplist [lindex [split $dep :] end]
+                    }
+                }
+                if {$action eq "deps"} {
+                    set label "$labeldict($type) Dependencies"
+                    lappend deps_output [wraplabel $label [join $deplist ", "] 0 [string repeat " " 22]]
+                    incr ndeps [llength $deplist]
+                    set deplist {}
+                }
+            }
+        }
+
+        set version $portinfo(version)
+        set revision $portinfo(revision)
+        if {[info exists portinfo(canonical_active_variants)]} {
+            set variants $portinfo(canonical_active_variants)
+        } else {
+            set variants {}
+        }
+
+        puts -nonewline $separator
+        if {$action eq "deps"} {
+            if {$ndeps == 0} {
+                ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+            } else {
+                ui_notice "Full Name: $portname @${version}_${revision}${variants}"
+                puts [join $deps_output "\n"]
+            }
+            set separator "--\n"
+            continue
+        }
+
+        set toplist $deplist
+        # gather all the deps
+        while 1 {
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        break_softcontinue "lookup of portname $depname failed: $result" 1 status
+                    }
+                    if {[llength $result] < 2} {
+                        break_softcontinue "Port $depname not found" 1 status
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                    set options(subport) $portinfo(name)
+                    
+                    # open the portfile if requested
+                    if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug "$::errorInfo"
+                            break_softcontinue "Unable to open port: $result" 1 status
+                        }
+                        array unset portinfo
+                        array set portinfo [mportinfo $mport]
+                        mportclose $mport
+                    }
+                    
+                    # get list of the dep's deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                lappend rdeplist $rdep
+                                lappend newlist $rdep
+                            }
+                        }
+                    }
+                    set depsof($depname) $rdeplist
+                }
+            }
+            if {[llength $newlist] > 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] > 0} {
+            ui_notice "The following ports are dependencies of $portname @${version}_${revision}${variants}:"
+        } else {
+            ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos >= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] <= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] && [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts "${spaces}${cur_port}"
+                } else {
+                    puts "${spaces}${cur_portname}"
+                }
+                set seen($cur_portname) 1
+                incr cur_pos
+                set pos_stack [lreplace $pos_stack end end $cur_pos]
+                if {[info exists depsof($cur_portname)]} {
+                    lappend portstack $depsof($cur_portname)
+                    lappend pos_stack 0
+                }
+                continue
+            }
+            incr cur_pos
+            set pos_stack [lreplace $pos_stack end end $cur_pos]
+        }
+        set separator "--\n"
+    }
+    return $status
+}
+
+
+proc action_uninstall { action portlist opts } {
+    set status 0
+    if {[macports::global_option_isset port_uninstall_old]} {
+        # if -u then uninstall all inactive ports
+        # (union these to any other ports user has in the port list)
+        set portlist [opUnion $portlist [get_inactive_ports]]
+    } else {
+        # Otherwise the user hopefully supplied a portlist, or we'll default to the existing directory
+        if {[require_portlist portlist]} {
+            return 1
+        }
+    }
+    if {[prefix_unwritable]} {
+        return 1
+    }
+
+    set portlist [portlist_sortdependents $portlist]
+
+    foreachport $portlist {
+        if {![registry::entry_exists_for_name $portname]} {
+            # if the code path arrives here the port either isn't installed, or
+            # it doesn't exist at all. We can't be sure, but we can check the
+            # portindex whether a port by that name exists (in which case not
+            # uninstalling it is probably no problem). If there is no port by
+            # that name, alert the user in case of typos.
+            ui_info "$portname is not installed"
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn "no such port: $portname, skipping uninstall"
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set iactive [lindex $i 4]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[registry::run_target $regref uninstall [array get options]]} {
+                continue
+            }
+        }
+
+        if { [catch {registry_uninstall::uninstall_composite $portname $composite_version [array get options]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port uninstall failed: $result" 1 status
+        }
+    }
+
+    return $status
+}
+
+
+proc action_installed { action portlist opts } {
+    global private_options
+    set status 0
+    set restrictedList 0
+    set ilist {}
+    
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreachport $portlist {
+            set composite_version [composite_version $portversion [array get variations]]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port installed failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] > 0 } {
+        ui_notice "The following ports are currently installed:"
+        foreach i [portlist_sortint $ilist] {
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            set extra ""
+            set nvariants ""
+            if {[macports::ui_isset ports_verbose]} {
+                set regref [registry::open_entry $iname $iversion $irevision $ivariants [lindex $i 5]]
+                set nvariants [registry::property_retrieve $regref negated_variants]
+                if {$nvariants == 0} {
+                    set nvariants ""
+                }
+                set os_platform [registry::property_retrieve $regref os_platform]
+                set os_major [registry::property_retrieve $regref os_major]
+                set archs [registry::property_retrieve $regref archs]
+                if {$os_platform != 0 && $os_platform ne "" && $os_major != 0 && $os_major ne ""} {
+                    append extra " platform='$os_platform $os_major'"
+                }
+                if {$archs != 0 && $archs ne ""} {
+                    append extra " archs='$archs'"
+                }
+            }
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}"
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are installed."
+    } else {
+        ui_notice "No ports are installed."
+    }
+
+    return $status
+}
+
+
+proc action_outdated { action portlist opts } {
+    global private_options
+    set status 0
+
+    # If port names were supplied, limit ourselves to those ports, else check all installed ports
+    set ilist {}
+    set restrictedList 0
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreach portspec $portlist {
+            array set port $portspec
+            set portname $port(name)
+            set composite_version [composite_version $port(version) $port(variants)]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port outdated failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] > 0 } {
+        foreach i [portlist_sortint $ilist] {
+        
+            # Get information about the installed port
+            set portname [lindex $i 0]
+            set installed_version [lindex $i 1]
+            set installed_revision [lindex $i 2]
+            set installed_compound "${installed_version}_${installed_revision}"
+
+            set is_active [lindex $i 4]
+            if {$is_active == 0} {
+                continue
+            }
+            set installed_epoch [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+            
+            # Get information about latest available version and revision
+            if {![info exists portinfo(version)]} {
+                ui_warn "$portname has no version field"
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound "${latest_version}_${latest_revision}"
+            set latest_epoch 0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch $portinfo(epoch)
+            }
+            
+            # Compare versions, first checking epoch, then version, then revision
+            set epoch_comp_result [expr {$installed_epoch - $latest_epoch}]
+            set comp_result [vercmp $installed_version $latest_version]
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            set reason ""
+            if {$epoch_comp_result != 0 && $installed_version != $latest_version} {
+                if {($comp_result >= 0 && $epoch_comp_result < 0) || ($comp_result <= 0 && $epoch_comp_result > 0)} {
+                    set reason { (epoch $installed_epoch $relation $latest_epoch)}
+                }
+                set comp_result $epoch_comp_result
+            } elseif {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision [lindex $i 3] $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                    set reason { (platform $os_platform_installed $os_major_installed != ${macports::os_platform} ${macports::os_major})}
+                }
+            }
+            
+            # Report outdated (or, for verbose, predated) versions
+            if { $comp_result != 0 } {
+                            
+                # Form a relation between the versions
+                set flag ""
+                if { $comp_result > 0 } {
+                    set relation ">"
+                    set flag "!"
+                } else {
+                    set relation "<"
+                }
+                
+                # Emit information
+                if {$comp_result < 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice "The following installed ports are outdated:"
+                    }
+                    incr num_outdated
+
+                    puts [format "%-30s %-24s %1s" $portname "$installed_compound $relation $latest_compound [subst $reason]" $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice "No installed ports are outdated."
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are outdated."
+    } else {
+        ui_notice "No ports are installed."
+    }
+    
+    return $status
+}
+
+
+proc action_contents { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {[info exists global_options(ports_contents_size)]} {
+        set units {}
+        if {[info exists global_options(ports_contents_units)]} {
+            set units [complete_size_units $global_options(ports_contents_units)]
+        }
+        set outstring {[format "%12s $file" [filesize $file $units]]}
+    } else {
+        set outstring {  $file}
+    }
+
+    foreachport $portlist {
+        if { ![catch {set ilist [registry::installed $portname]} result] } {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0 0]
+        }
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                ui_notice "Port $portname contains:"
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice "Port $portname does not contain any files or is not active."
+            }
+        } else {
+            ui_notice "Port $portname is not installed."
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq "K" || $units eq "Ki"} {
+        return "KiB"
+    } elseif {$units eq "k"} {
+        return "kB"
+    } elseif {$units eq "Mi"} {
+        return "MiB"
+    } elseif {$units eq "M"} {
+        return "MB"
+    } elseif {$units eq "Gi"} {
+        return "GiB"
+    } elseif {$units eq "G"} {
+        return "GB"
+    } else {
+        return $units
+    }
+}
+
+# Show space used by the given ports' files
+proc action_space {action portlist opts} {
+    global global_options
+    require_portlist portlist
+
+    set units {}
+    if {[info exists global_options(ports_space_units)]} {
+        set units [complete_size_units $global_options(ports_space_units)]
+    }
+    set spaceall 0.0
+    foreachport $portlist {
+        set space 0.0
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne "yes"} {
+                    set msg "[bytesize $space $units] $portname"
+                    if { $portversion != {} } {
+                        append msg " @$portversion"
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr "Port $portname does not contain any file or is not active."
+            }
+        } else {
+            puts stderr "Port $portname is not installed."
+        }
+    }
+    if {[llength $portlist] > 1 || ([info exists options(ports_space_total)] && $options(ports_space_total) eq "yes")} {
+        puts "[bytesize $spaceall $units] total"
+    }
+    return 0
+}
+
+proc action_variants { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] && $options(ports_variants_index) eq "yes")} {
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "port variants --index does not work with 'current' pseudo-port"
+            continue
+        }
+
+        # set portname again since the one we were passed may not have had the correct case
+        set portname $portinfo(name)
+
+        # if this fails the port doesn't have any variants
+        if {![info exists portinfo(variants)]} {
+            ui_notice "$portname has no variants"
+        } else {
+            array unset vinfo
+            # Use the new format if it exists.
+            if {[info exists portinfo(vinfo)]} {
+                array set vinfo $portinfo(vinfo)
+            # Otherwise fall back to the old format.
+            } elseif {[info exists portinfo(variant_desc)]} {
+                array set vdescriptions $portinfo(variant_desc)
+            }
+
+            # print out all the variants
+            ui_notice "$portname has the variants:"
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier "   "
+                # Retrieve variants' information from the new format.
+                if {[info exists vinfo]} {
+                    array unset variant
+                    array set variant $vinfo($v)
+
+                    # Retrieve conflicts, description, is_default, and
+                    # vrequires.
+                    if {[info exists variant(conflicts)]} {
+                        set vconflicts $variant(conflicts)
+                    }
+                    if {[info exists variant(description)]} {
+                        set vdescription $variant(description)
+                    }
+
+                    # XXX Keep these varmodifiers in sync with action_info, or create a wrapper for it
+                    if {[info exists variations($v)]} {
+                        set varmodifier "  $variations($v)"
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier "($global_variations($v))"
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier "\[$variant(is_default)\]"
+                    }
+                    if {[info exists variant(requires)]} {
+                        set vrequires $variant(requires)
+                    }
+                # Retrieve variants' information from the old format,
+                # which only consists of the description.
+                } elseif {[info exists vdescriptions($v)]} {
+                    set vdescription $vdescriptions($v)
+                }
+
+                if {[info exists vdescription]} {
+                    puts [wraplabel "$varmodifier$v" [string trim $vdescription] 0 [string repeat " " [expr 5 + [string length $v]]]]
+                } else {
+                    puts "$varmodifier$v"
+                }
+                if {[info exists vconflicts]} {
+                    puts "     * conflicts with [string trim $vconflicts]"
+                }
+                if {[info exists vrequires]} {
+                    puts "     * requires [string trim $vrequires]"
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        ui_error "You must specify a search pattern"
+        return 1
+    }
+
+    # Copy global options as we are going to modify the array
+    array set options [array get global_options]
+
+    if {[info exists options(ports_search_depends)] && $options(ports_search_depends) eq "yes"} {
+        array unset options ports_search_depends
+        set options(ports_search_depends_fetch) yes
+        set options(ports_search_depends_extract) yes
+        set options(ports_search_depends_build) yes
+        set options(ports_search_depends_lib) yes
+        set options(ports_search_depends_run) yes
+    }
+
+    # Array to hold given filters
+    array set filters {}
+    # Default matchstyle
+    set filter_matchstyle "none"
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne "yes" } {
+            continue
+        }
+        switch -- $opt {
+            exact -
+            glob {
+                set filter_matchstyle $opt
+                continue
+            }
+            regex {
+                set filter_matchstyle regexp
+                continue
+            }
+            case-sensitive {
+                set filter_case yes
+                continue
+            }
+            line {
+                continue
+            }
+        }
+
+        set filters($opt) "yes"
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) "yes"
+        set filters(description) "yes"
+    }
+
+    set separator ""
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq "none"} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first "*" $portname] == -1 && [string first "?" $portname] == -1} {
+                set searchstring "*$portname*"
+            }
+            set matchstyle glob
+        }
+
+        set res {}
+        set portfound 0
+        foreach { opt } [array get filters] {
+            # Map from friendly name
+            set opt [map_friendly_field_names $opt]
+
+            if {[catch {eval set matches \[mportsearch \$searchstring $filter_case \$matchstyle $opt\]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for name $portname failed: $result" 1 status
+            }
+
+            set tmp {}
+            foreach {name info} $matches {
+                add_to_portlist tmp [concat [list name $name] $info]
+            }
+            set res [opUnion $res $tmp]
+        }
+        set res [portlist_sort $res]
+
+        set joiner ""
+        foreach info $res {
+            array unset portinfo
+            array set portinfo $info
+
+            # XXX is this the right place to verify an entry?
+            if {![info exists portinfo(name)]} {
+                puts stderr "Invalid port entry, missing portname"
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing description"
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing version"
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        && $options(ports_search_line) eq "yes"} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts "$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)"
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts "$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)"
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline "$portinfo(name) @$portinfo(version)"
+                    if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                        puts -nonewline "_$portinfo(revision)"
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline " ([join $portinfo(categories) ", "])"
+                    }
+                    puts ""
+                    puts [wrap [join $portinfo(description)] 0 [string repeat " " 4]]
+                }
+            }
+
+            set joiner "\n"
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice "No match for $portname found"
+        } elseif {[llength $res] > 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne "yes")} {
+                ui_notice "\nFound [llength $res] ports."
+            }
+        }
+
+        set separator "--\n"
+    }
+
+    array unset options
+    array unset filters
+
+    return $status
+}
+
+
+proc action_list { action portlist opts } {
+    global private_options
+    set status 0
+    
+    # Default to list all ports if no portnames are supplied
+    if { ![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        add_to_portlist portlist [list name "-all-"]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq "-all-"} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "listing all ports failed: $result" 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $search_string failed: $result" 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir ""
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format "%-30s @%-14s %s" $portinfo(name) $portinfo(version) $outdir]
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_echo { action portlist opts } {
+    global global_options
+
+    # Simply echo back the port specs given to this command
+    foreachport $portlist {
+        if {![macports::ui_isset ports_quiet]} {
+            set opts {}
+            foreach { key value } [array get options] {
+                if {![info exists global_options($key)]} {
+                    lappend opts "$key=$value"
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne "" } {
+                set ver_field "@$composite_version"
+            } else {
+                set ver_field ""
+            }
+            puts [format "%-30s %s %s" $portname $ver_field  [join $opts " "]]
+        } else {
+            puts "$portname"
+        }
+    }
+
+    return 0
+}
+
+
+proc action_portcmds { action portlist opts } {
+    # Operations on the port's directory and Portfile
+    global env boot_env current_portdir
+
+    array set local_options $opts
+    
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific, otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+            set portname $portinfo(name)
+        }
+        
+        
+        # Calculate portdir, porturl, and portfile from initial porturl
+        set portdir [file normalize [macports::getportdir $porturl]]
+        set porturl "file://${portdir}";    # Rebuild url so it's fully qualified
+        set portfile "${portdir}/Portfile"
+        
+        # Now execute the specific action
+        if {[file readable $portfile]} {
+            switch -- $action {
+                cat {
+                    # Copy the portfile to standard output
+                    set f [open $portfile RDONLY]
+                    while { ![eof $f] } {
+                        puts -nonewline [read $f 4096]
+                    }
+                    close $f
+                }
+                
+                edit {
+                    # Edit the port's portfile with the user's editor
+                    
+                    # Restore our entire environment from start time.
+                    # We need it to evaluate the editor, and the editor
+                    # may want stuff from it as well, like TERM.
+                    array unset env_save; array set env_save [array get env]
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor ""
+                    set editor_var "ports_${action}_editor"
+                    if {[info exists local_options($editor_var)]} {
+                        set editor [join $local_options($editor_var)]
+                    } else {
+                        foreach ed { MP_EDITOR VISUAL EDITOR } {
+                            if {[info exists env($ed)]} {
+                                set editor $env($ed)
+                                break
+                            }
+                        }
+                    }
+                    
+                    # Use a reasonable canned default if no editor specified or set in env
+                    if { $editor eq "" } { set editor "/usr/bin/vi" }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec >@stdout <@stdin 2>@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug "$errorInfo"
+                        break_softcontinue "unable to invoke editor $editor: $result" 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get env_save]
+                }
+
+                dir {
+                    # output the path to the port's directory
+                    puts $portdir
+                }
+
+                work {
+                    # output the path to the port's work directory
+                    set workpath [macports::getportworkpath_from_portdir $portdir $portname]
+                    if {[file exists $workpath]} {
+                        puts $workpath
+                    }
+                }
+
+                cd {
+                    # Change to the port's directory, making it the default
+                    # port for any future commands
+                    set current_portdir $portdir
+                }
+
+                url {
+                    # output the url of the port's directory, suitable to feed back in later as a port descriptor
+                    puts $porturl
+                }
+
+                file {
+                    # output the path to the port's portfile
+                    puts $portfile
+                }
+
+                logfile {
+                    set logfile [file join [macports::getportlogpath $portdir $portname] "main.log"]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error "Log file not found for port in $portdir"
+                    }
+                }
+
+                gohome {
+                    set homepage ""
+
+                    # Get the homepage as read from PortIndex
+                    if {[info exists portinfo(homepage)]} {
+                        set homepage $portinfo(homepage)
+                    }
+
+                    # If not available, get the homepage for the port by opening the Portfile
+                    if {$homepage eq "" && ![catch {set ctx [mportopen $porturl]} result]} {
+                        array set portinfo [mportinfo $ctx]
+                        if {[info exists portinfo(homepage)]} {
+                            set homepage $portinfo(homepage)
+                        }
+                        mportclose $ctx
+                    }
+
+                    # Try to open a browser to the homepage for the given port
+                    if { $homepage ne "" } {
+                        if {[catch {system "${macports::autoconf::open_path} '$homepage'"} result]} {
+                            global errorInfo
+                            ui_debug "$errorInfo"
+                            break_softcontinue "unable to invoke browser using ${macports::autoconf::open_path}: $result" 1 status
+                        }
+                    } else {
+                        ui_error [format "No homepage for %s" $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue "Could not read $portfile" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_sync { action portlist opts } {
+    global global_options
+
+    set status 0
+    if {[catch {mportsync [array get global_options]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_msg "port sync failed: $result"
+        set status 1
+    }
+    
+    return $status
+}
+
+
+proc action_target { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {($action eq "install" || $action eq "archive") && [prefix_unwritable] && ![macports::global_option_isset ports_dryrun]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn "Skipping $portname (not in the ports tree)"
+                    continue
+                } else {
+                    break_softcontinue "Port $portname not found" 1 status
+                }
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+        }
+
+        # use existing variants iff none were explicitly requested
+        if {[array get requested_variations] eq "" && [array get variations] ne ""} {
+            array unset requested_variations
+            array set requested_variations [array get variations]
+        }
+
+        # Add any global_variations to the variations
+        # specified for the port
+        foreach { variation value } [array get global_variations] {
+            if { ![info exists requested_variations($variation)] } {
+                set requested_variations($variation) $value
+            }
+        }
+
+        # If version was specified, save it as a version glob for use
+        # in port actions (e.g. clean).
+        if {[string length $portversion]} {
+            set options(ports_version_glob) $portversion
+        }
+        # if installing, mark the port as explicitly requested
+        if {$action eq "install"} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq "archive"} {
+            set target install
+        } else {
+            set target $action
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+        if {[catch {set workername [mportopen $porturl [array get options] [array get requested_variations]]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to open port: $result" 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to execute port: $result" 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue "Processing of port $portname failed" 1 status
+        }
+    }
+    
+    if {$status == 0 && $action eq "install" && ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] && ![info exists options(ports_install_no-rev-upgrade)] && ${macports::revupgrade_autorun}} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+
+proc action_exit { action portlist opts } {
+    # Return a semaphore telling the main loop to quit
+    return -999
+}
+
+
+##########################################
+# Command Parsing
+##########################################
+proc moreargs {} {
+    global cmd_argn cmd_argc
+    return [expr {$cmd_argn < $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn < $cmd_argc} {
+        return [lindex $cmd_argv $cmd_argn]
+    } else {
+        return _EOF_
+    }
+}
+
+
+proc advance {} {
+    global cmd_argn
+    incr cmd_argn
+}
+
+
+proc match s {
+    if {[lookahead] == $s} {
+        advance
+        return 1
+    }
+    return 0
+}
+
+# action_array specifies which action to run on the given command
+# and if the action wants an expanded portlist.
+# The value is a list of the form {action expand},
+# where action is a string and expand a value:
+#   0 none        Does not expect any text argument
+#   1 strings     Expects some strings as text argument
+#   2 ports       Wants an expanded list of ports as text argument
+global action_array
+
+# Define global constants
+const ACTION_ARGS_NONE 0
+const ACTION_ARGS_STRINGS 1
+const ACTION_ARGS_PORTS 2
+
+array set action_array [list \
+    usage       [list action_usage          [ACTION_ARGS_STRINGS]] \
+    help        [list action_help           [ACTION_ARGS_STRINGS]] \
+    \
+    echo        [list action_echo           [ACTION_ARGS_PORTS]] \
+    \
+    info        [list action_info           [ACTION_ARGS_PORTS]] \
+    location    [list action_location       [ACTION_ARGS_PORTS]] \
+    notes       [list action_notes          [ACTION_ARGS_PORTS]] \
+    provides    [list action_provides       [ACTION_ARGS_STRINGS]] \
+    log         [list action_log            [ACTION_ARGS_PORTS]] \
+    \
+    activate    [list action_activate       [ACTION_ARGS_PORTS]] \
+    deactivate  [list action_deactivate     [ACTION_ARGS_PORTS]] \
+    \
+    select      [list action_select         [ACTION_ARGS_STRINGS]] \
+    \
+    sync        [list action_sync           [ACTION_ARGS_NONE]] \
+    selfupdate  [list action_selfupdate     [ACTION_ARGS_NONE]] \
+    \
+    setrequested   [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    unsetrequested [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    \
+    upgrade     [list action_upgrade        [ACTION_ARGS_PORTS]] \
+    rev-upgrade [list action_revupgrade     [ACTION_ARGS_NONE]] \
+    reclaim     [list action_reclaim        [ACTION_ARGS_NONE]] \
+    doctor      [list action_doctor         [ACTION_ARGS_NONE]] \
+    \
+    version     [list action_version        [ACTION_ARGS_NONE]] \
+    platform    [list action_platform       [ACTION_ARGS_NONE]] \
+    \
+    uninstall   [list action_uninstall      [ACTION_ARGS_PORTS]] \
+    \
+    installed   [list action_installed      [ACTION_ARGS_PORTS]] \
+    outdated    [list action_outdated       [ACTION_ARGS_PORTS]] \
+    contents    [list action_contents       [ACTION_ARGS_PORTS]] \
+    space       [list action_space          [ACTION_ARGS_PORTS]] \
+    dependents  [list action_dependents     [ACTION_ARGS_PORTS]] \
+    rdependents [list action_dependents     [ACTION_ARGS_PORTS]] \
+    deps        [list action_deps           [ACTION_ARGS_PORTS]] \
+    rdeps       [list action_deps           [ACTION_ARGS_PORTS]] \
+    variants    [list action_variants       [ACTION_ARGS_PORTS]] \
+    \
+    search      [list action_search         [ACTION_ARGS_STRINGS]] \
+    list        [list action_list           [ACTION_ARGS_PORTS]] \
+    \
+    edit        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cat         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    dir         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    work        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cd          [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    url         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    file        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    logfile     [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    gohome      [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    \
+    fetch       [list action_target         [ACTION_ARGS_PORTS]] \
+    checksum    [list action_target         [ACTION_ARGS_PORTS]] \
+    extract     [list action_target         [ACTION_ARGS_PORTS]] \
+    patch       [list action_target         [ACTION_ARGS_PORTS]] \
+    configure   [list action_target         [ACTION_ARGS_PORTS]] \
+    build       [list action_target         [ACTION_ARGS_PORTS]] \
+    destroot    [list action_target         [ACTION_ARGS_PORTS]] \
+    install     [list action_target         [ACTION_ARGS_PORTS]] \
+    clean       [list action_target         [ACTION_ARGS_PORTS]] \
+    test        [list action_target         [ACTION_ARGS_PORTS]] \
+    lint        [list action_target         [ACTION_ARGS_PORTS]] \
+    livecheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    distcheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    mirror      [list action_target         [ACTION_ARGS_PORTS]] \
+    load        [list action_target         [ACTION_ARGS_PORTS]] \
+    unload      [list action_target         [ACTION_ARGS_PORTS]] \
+    distfiles   [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    archivefetch [list action_target         [ACTION_ARGS_PORTS]] \
+    archive     [list action_target         [ACTION_ARGS_PORTS]] \
+    unarchive   [list action_target         [ACTION_ARGS_PORTS]] \
+    dmg         [list action_target         [ACTION_ARGS_PORTS]] \
+    mdmg        [list action_target         [ACTION_ARGS_PORTS]] \
+    dpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    mpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    pkg         [list action_target         [ACTION_ARGS_PORTS]] \
+    portpkg     [list action_target         [ACTION_ARGS_PORTS]] \
+    rpm         [list action_target         [ACTION_ARGS_PORTS]] \
+    srpm        [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    quit        [list action_exit           [ACTION_ARGS_NONE]] \
+    exit        [list action_exit           [ACTION_ARGS_NONE]] \
+]
+
+# Expand "action".
+# Returns an action proc, or a list of matching action procs, or the action passed in
+proc find_action { action } {
+    global action_array
+    
+    if { ! [info exists action_array($action)] } {
+        set guess [guess_action $action]
+        if { [info exists action_array($guess)] } {
+            return $guess
+        }
+        return $guess
+    }
+    
+    return $action
+}
+
+# Expand action
+# If there's more than one match, return the next possibility
+proc find_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    } else {
+        set action [complete_action $action]
+        if { [info exists action_array($action)] } {
+            set action_proc [lindex $action_array($action) 0]
+        }
+    }
+    
+    return $action_proc
+}
+
+proc get_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    }
+    
+    return $action_proc
+}
+
+# Returns whether an action expects text arguments at all,
+# expects text arguments or wants an expanded list of ports
+# Return values are constants:
+#   [ACTION_ARGS_NONE]     Does not expect any text argument
+#   [ACTION_ARGS_STRINGS]  Expects some strings as text argument
+#   [ACTION_ARGS_PORTS]    Wants an expanded list of ports as text argument
+proc action_needs_portlist { action } {
+    global action_array
+
+    set ret 0
+    if {[info exists action_array($action)]} {
+        set ret [lindex $action_array($action) 1]
+    }
+
+    return $ret
+}
+
+# cmd_opts_array specifies which arguments the commands accept
+# Commands not listed here do not accept any arguments
+# Syntax if {option argn}
+# Where option is the name of the option and argn specifies how many arguments
+# this argument takes
+global cmd_opts_array
+array set cmd_opts_array {
+    edit        {{editor 1}}
+    info        {category categories depends_fetch depends_extract
+                 depends_build depends_lib depends_run
+                 depends description epoch fullname heading homepage index license
+                 line long_description
+                 maintainer maintainers name platform platforms portdir pretty
+                 replaced_by revision subports variant variants version}
+    contents    {size {units 1}}
+    deps        {index no-build}
+    rdeps       {index no-build full}
+    rdependents {full}
+    search      {case-sensitive category categories depends_fetch
+                 depends_extract depends_build depends_lib depends_run
+                 depends description epoch exact glob homepage line
+                 long_description maintainer maintainers name platform
+                 platforms portdir regex revision variant variants version}
+    selfupdate  {nosync}
+    space       {{units 1} total}
+    activate    {no-exec}
+    deactivate  {no-exec}
+    install     {no-rev-upgrade unrequested}
+    uninstall   {follow-dependents follow-dependencies no-exec}
+    variants    {index}
+    clean       {all archive dist work logs}
+    mirror      {new}
+    lint        {nitpick}
+    select      {list set show summary}
+    log         {{phase 1} {level 1}}
+    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 option the prefix of the option to check
+# @return list of pairs {name argc} for all matching options
+proc cmd_option_matches {action option} {
+    global cmd_opts_array
+
+    # This could be so easy with lsearch -index,
+    # but that's only available as of Tcl 8.5
+
+    if {![info exists cmd_opts_array($action)]} {
+        return {}
+    }
+
+    set result {}
+
+    foreach item $cmd_opts_array($action) {
+        if {[llength $item] == 1} {
+            set name $item
+            set argc 0
+        } else {
+            set name [lindex $item 0]
+            set argc [lindex $item 1]
+        }
+
+        if {$name == $option} {
+            set result [list [list $name $argc]]
+            break
+        } elseif {[string first $option $name] == 0} {
+            lappend result [list $name $argc]
+        }
+    }
+
+    return $result
+}
+
+# Parse global options
+#
+# Note that this is called several times:
+#   (1) Initially, to parse options that will be constant across all commands
+#       (options that come prior to any command, frozen into global_options_base)
+#   (2) Following each command (to parse options that will be unique to that command
+#       (the global_options array is reset to global_options_base prior to each command)
+#
+proc parse_options { action ui_options_name global_options_name } {
+    upvar $ui_options_name ui_options
+    upvar $global_options_name global_options
+    global cmdname cmd_opts_array
+    
+    while {[moreargs]} {
+        set arg [lookahead]
+        
+        if {[string index $arg 0] ne "-"} {
+            break
+        } elseif {[string index $arg 1] eq "-"} {
+            # Process long arguments
+            switch -- $arg {
+                -- { # This is the options terminator; do no further option processing
+                    advance; break
+                }
+                default {
+                    set key [string range $arg 2 end]
+                    set kopts [cmd_option_matches $action $key]
+                    if {[llength $kopts] == 0} {
+                        return -code error "${action} does not accept --${key}"
+                    } elseif {[llength $kopts] > 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst "--[lindex $e 0]"
+                        }
+                        return -code error "\"port ${action} --${key}\" is ambiguous: \n  port ${action} [join $errlst "\n  port ${action} "]"
+                    }
+                    set key   [lindex $kopts 0 0]
+                    set kargc [lindex $kopts 0 1]
+                    if {$kargc == 0} {
+                        set global_options(ports_${action}_${key}) yes
+                    } else {
+                        set args {}
+                        while {[moreargs] && $kargc > 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc > 0} {
+                            return -code error "--${key} expects [expr {$kargc + [llength $args]}] parameters!"
+                        }
+                        set global_options(ports_${action}_${key}) $args
+                    }
+                }
+            }
+        } else {
+            # Process short arg(s)
+            set opts [string range $arg 1 end]
+            foreach c [split $opts {}] {
+                switch -- $c {
+                    v {
+                        set ui_options(ports_verbose) yes
+                    }
+                    d {
+                        set ui_options(ports_debug) yes
+                        # debug implies verbose
+                        set ui_options(ports_verbose) yes
+                    }
+                    q {
+                        set ui_options(ports_quiet) yes
+                    }
+                    p {
+                        # Ignore errors while processing within a command
+                        set ui_options(ports_processall) yes
+                    }
+                    f {
+                        set global_options(ports_force) yes
+                    }
+                    o {
+                        set global_options(ports_ignore_different) yes
+                    }
+                    n {
+                        set global_options(ports_nodeps) yes
+                    }
+                    u {
+                        set global_options(port_uninstall_old) yes
+                    }
+                    R {
+                        set global_options(ports_do_dependents) yes
+                    }
+                    s {
+                        set global_options(ports_source_only) yes
+                    }
+                    b {
+                        set global_options(ports_binary_only) yes
+                    }
+                    c {
+                        set global_options(ports_autoclean) yes
+                    }
+                    k {
+                        set global_options(ports_autoclean) no
+                    }
+                    t {
+                        set global_options(ports_trace) yes
+                    }
+                    y {
+                        set global_options(ports_dryrun) yes
+                    }
+                    F {
+                        # Name a command file to process
+                        advance
+                        if {[moreargs]} {
+                            lappend ui_options(ports_commandfiles) [lookahead]
+                        }
+                    }
+                    D {
+                        advance
+                        if {[moreargs]} {
+                            cd [lookahead]
+                        }
+                        break
+                    }
+                    default {
+                        print_usage; exit 1
+                    }
+                }
+            }
+        }
+
+        advance
+    }
+}
+
+# acquire exclusive registry lock for actions that need it
+# returns 1 if locked, 0 otherwise
+proc lock_reg_if_needed {action} {
+    switch -- $action {
+        activate -
+        deactivate -
+        setrequested -
+        unsetrequested -
+        upgrade -
+        uninstall -
+        install {
+            registry::exclusive_lock
+            return 1
+        }
+    }
+    return 0
+}
+
+proc process_cmd { argv } {
+    global cmd_argc cmd_argv cmd_argn \
+           global_options global_options_base private_options ui_options \
+           current_portdir
+    set cmd_argv $argv
+    set cmd_argc [llength $argv]
+    set cmd_argn 0
+
+    set action_status 0
+
+    # Process an action if there is one
+    while {($action_status == 0 || [macports::ui_isset ports_processall]) && [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == ";" } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == "#" } {
+            while { [moreargs] } { advance }
+            break
+        }
+
+        set locked [lock_reg_if_needed $action]
+        # Always start out processing an action in current_portdir
+        cd $current_portdir
+        
+        # Reset global_options from base before each action, as we munge it just below...
+        array unset global_options
+        array set global_options $global_options_base
+        
+        # Find an action to execute
+        set actions [find_action $action]
+        if {[llength $actions] == 1} {
+            set action [lindex $actions 0]
+            set action_proc [get_action_proc $action]
+        } else {
+            if {[llength $actions] > 1} {
+                ui_error "\"port ${action}\" is ambiguous: \n  port [join $actions "\n  port "]"
+            } else {
+                ui_error "Unrecognized action \"port $action\""
+            }
+            set action_status 1
+            break
+        }
+
+        # Parse options that will be unique to this action
+        # (to avoid abiguity with -variants and a default port, either -- must be
+        # used to terminate option processing, or the pseudo-port current must be specified).
+        if {[catch {parse_options $action ui_options global_options} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            ui_error $result
+            set action_status 1
+            break
+        }
+
+        # What kind of arguments does the command expect?
+        set expand [action_needs_portlist $action]
+
+        # Parse action arguments, setting a special flag if there were none
+        # We otherwise can't tell the difference between arguments that evaluate
+        # to the empty set, and the empty set itself.
+        set portlist {}
+        switch -- [lookahead] {
+            ;       -
+            _EOF_ {
+                set private_options(ports_no_args) yes
+            }
+            default {
+                if {[ACTION_ARGS_NONE] == $expand} {
+                    ui_error "$action does not accept string arguments"
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] && ![match ";"] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error "Improper expression syntax while processing parameters"
+                        set action_status 1
+                        break
+                    }
+                }
+            }
+        }
+        
+        # execute the action
+        set action_status [$action_proc $action $portlist [array get global_options]]
+
+        # unlock if needed
+        if {$locked} {
+            registry::exclusive_unlock
+        }
+
+        # Print notifications of just-activated ports.
+        portclient::notifications::display
+
+        # semaphore to exit
+        if {$action_status == -999} break
+    }
+    
+    return $action_status
+}
+
+
+proc complete_portname { text state } { 
+    global complete_choices complete_position
+    
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices {}
+
+        # Build a list of ports with text as their prefix
+        if {[catch {set res [mportsearch "${text}*" false glob]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "search for portname $pattern failed: $result"
+        }
+        foreach {name info} $res {
+            lappend complete_choices $name
+        }
+    }
+    
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+    
+    return $word
+}
+
+
+# return text action beginning with $text
+proc complete_action { text state } {   
+    global action_array complete_choices complete_position
+
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices [array names action_array "[string tolower $text]*"]
+    }
+
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+
+    return $word
+}
+
+# return all actions beginning with $text
+proc guess_action { text } {   
+    global action_array
+
+    return [array names action_array "[string tolower $text]*"]
+
+    if { [llength $complete_choices ] == 1 } {
+        return [lindex $complete_choices 0]
+    }
+
+    return {}
+}
+
+proc attempt_completion { text word start end } {
+    # If the word starts with '~', or contains '.' or '/', then use the build-in
+    # completion to complete the word
+    if { [regexp {^~|[/.]} $word] } {
+        return ""
+    }
+
+    # Decide how to do completion based on where we are in the string
+    set prefix [string range $text 0 [expr {$start - 1}]]
+    
+    # If only whitespace characters preceed us, or if the
+    # previous non-whitespace character was a ;, then we're
+    # an action (the first word of a command)
+    if { [regexp {(^\s*$)|(;\s*$)} $prefix] } {
+        return complete_action
+    }
+    
+    # Otherwise, do completion on portname
+    return complete_portname
+}
+
+
+proc get_next_cmdline { in out use_readline prompt linename } {
+    upvar $linename line
+    
+    set line ""
+    while { $line eq "" } {
+
+        if {$use_readline} {
+            set len [readline read -attempted_completion attempt_completion line $prompt]
+        } else {
+            puts -nonewline $out $prompt
+            flush $out
+            set len [gets $in line]
+        }
+
+        if { $len < 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline && $line ne "" } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in "stdin"]
+    set name "port"
+    set use_readline [expr {$isstdin && [readline init $name]}]
+    set history_file [file normalize "${macports::macports_user_dir}/history"]
+
+    # Read readline history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin && ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts "MacPorts [macports::version]"
+        puts "Entering interactive mode... (\"help\" for help, \"quit\" to quit)"
+    }
+
+    # Main command loop
+    set exit_status 0
+    while { $exit_status == 0 || $isstdin || [macports::ui_isset ports_processall] } {
+
+        # Calculate our prompt
+        if { $noisy } {
+            set shortdir [eval file join [lrange [file split $current_portdir] end-1 end]]
+            set prompt "\[$shortdir\] > "
+        } else {
+            set prompt ""
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] <= 0  } {
+            puts ""
+            break
+        }
+
+        # Process the command
+        set exit_status [process_cmd $line]
+        
+        # Check for semaphore to exit
+        if {$exit_status == -999} {
+            set exit_status 0
+            break
+        }
+    }
+
+    # Create macports user directory if it does not exist yet
+    if {$use_readline && ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts "Goodbye"
+    }
+
+    return $exit_status
+}
+
+
+proc process_command_files { filelist } {
+    set exit_status 0
+
+    # For each file in the command list, process commands
+    # in the file
+    foreach file $filelist {
+        if {$file eq "-"} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal "Failed to open command file; $result"
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne "stdin"} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 && ![macports::ui_isset ports_processall]} {
+            return $exit_status
+        }
+    }
+
+    return $exit_status
+}
+
+namespace eval portclient::progress {
+    ##
+    # Maximum width of the progress bar or indicator when displaying it.
+    variable maxWidth 50
+
+    ##
+    # The start time of the last progress callback as returned by [clock time].
+    # Since only one progress indicator is active at a time, this variable is
+    # shared between the different variants of progress functions.
+    variable startTime
+
+    ##
+    # Delay in milliseconds after the start of the operation before deciding
+    # that showing a progress bar makes sense.
+    variable showTimeThreshold 500
+
+    ##
+    # Percentage value between 0 and 1 that must not have been reached yet when
+    # $showTimeThreshold has passed for a progress bar to be shown. If the
+    # operation has proceeded above e.g. 75% after 500ms we won't bother
+    # displaying a progress indicator anymore -- the operation will be finished
+    # in well below a second anyway.
+    variable showPercentageThreshold 0.75
+
+    ##
+    # Boolean indication whether the progress indicator should be shown or is
+    # still hidden because the current operation didn't need enough time for
+    # a progress indicator to make sense, yet.
+    variable show no
+
+    ##
+    # Initialize the progress bar display delay; call this from the start
+    # action of the progress functions.
+    proc initDelay {} {
+        variable show
+        variable startTime
+
+        set startTime [clock milliseconds]
+        set show no
+    }
+
+    ##
+    # Determine whether a progress bar should be shown for the current
+    # operation in its current state. You must have called initDelay for the
+    # current operation before calling this method.
+    #
+    # @param cur
+    #        Current progress in abstract units.
+    # @param total
+    #        Total number of abstract units to be processed, if known. Pass
+    #        0 if unknown.
+    # @return
+    #        "yes", if the progress indicator should be shown, "no" otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq "yes"} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] > $showTimeThreshold &&
+                ($total == 0 || [expr {double($cur) / double($total)}] < $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of "start", "update", "intermission" or "finish", where start
+    #        will be called before any number of update calls, interrupted by
+    #        any number of intermission calls (called because other output is
+    #        being produced), followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        "intermission" and "finish", the args are empty and unused. For
+    #        "update", args contains $cur and $total, where $cur is the current
+    #        number of units processed and $total is the total number of units
+    #        to be processed. If the total is not known, it is 0.
+    proc generic {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {now total} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            progressbar $now $total [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        } else {
+                            unprogressbar [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        }
+                    }
+                }
+            }
+            intermission -
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of "start", "update" or "finish", where start will be called
+    #        before any number of update calls, followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        contains a single argument "ul" or "dl" indicating whether this is
+    #        an up- or download. For "update", contains the arguments
+    #        ("ul"|"dl") $total $now $speed where ul/dl are as for start, and
+    #        total, now and speed are doubles indicating the total transfer
+    #        size, currently transferred amount and average speed per second in
+    #        bytes. Unused for "finish".
+    proc download {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {type total now speed} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format "        speed: %-13s" "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format " %-10s     speed: %-13s" [bytesize $now {} "%6.1f"] "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            unprogressbar $barLen $barPrefix $barSuffix
+                        }
+                    }
+                }
+            }
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Draw a progress bar using unicode block drawing characters
+    #
+    # @param current
+    #        The current progress value.
+    # @param total
+    #        The progress value representing 100%.
+    # @param width
+    #        The width in characters of the progress bar. This includes percentage
+    #        output, which takes up 8 characters.
+    # @param prefix
+    #        Prefix to be printed in front of the progress bar.
+    # @param suffix
+    #        Suffix to be printed after the progress bar.
+    proc progressbar {current total width {prefix ""} {suffix ""}} {
+        # Subtract the width of the percentage output, also subtract the two
+        # characters [ and ] bounding the progress bar.
+        set percentageWidth 8
+        set barWidth      [expr {entier($width) - $percentageWidth - 2}]
+
+        # Map the range (0, $total) to (0, 4 * $width) where $width is the maximum
+        # numebr of characters to be printed for the progress bar. Multiply the
+        # upper bound with 8 because we have 8 sub-states per character.
+        set barProgress   [expr {entier(round(($current * $barWidth * 8) / $total))}]
+
+        set barInteger    [expr {$barProgress / 8}]
+        #set barRemainder  [expr {$barProgress % 8}]
+
+        # Finally, also provide a percentage value to print behind the progress bar
+        set percentage [expr {double($current) * 100 / double($total)}]
+
+        # clear the current line, enable reverse video
+        set progressbar "\033\[7m"
+        for {set i 0} {$i < $barInteger} {incr i} {
+            # U+2588 FULL BLOCK doesn't match the other blocks in some fonts :/
+            # Two half blocks work better in some fonts, but not in others (because
+            # they leave ugly spaces). So, one or the other choice isn't better or
+            # worse and even just using full blocks looks ugly in a few fonts.
+
+            # Use pure ASCII until somebody fixes most of the default terminal fonts :/
+            append progressbar " "
+        }
+        # back to normal output
+        append progressbar "\033\[0m"
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger < $barWidth} {
+        #            append progressbar " "
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar "\u258f"
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar "\u258e"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar "\u258c"
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar "\u258b"
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar "\u258a"
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar "\u2589"
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i < $barWidth} {incr i} {
+            append progressbar " "
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format " %[expr {$percentageWidth - 3}].1f %%" $percentage]
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}"
+        flush stdout
+    }
+
+
+    ##
+    # Internal state of the progress indicator; unless you're hacking the
+    # unprogressbar code you should never touch this.
+    variable unprogressState 0
+
+    ##
+    # Draw a progress indicator
+    #
+    # @param width
+    #        The width in characters of the progress indicator.
+    # @param prefix
+    #        Prefix to be printed in front of the progress indicator.
+    # @param suffix
+    #        Suffix to be printed after the progress indicator.
+    proc unprogressbar {width {prefix ""} {suffix ""}} {
+        variable unprogressState
+
+        # Subtract the two characters [ and ] bounding the progress indicator
+        # from the width.
+        set barWidth [expr {int($width) - 2}]
+
+        # Number of states of the progress bar, or rather: the number of
+        # characters before the sequence repeats.
+        set numStates 4
+
+        set unprogressState [expr {($unprogressState + 1) % $numStates}]
+
+        set progressbar ""
+        for {set i 0} {$i < $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar "\u2022"
+            } else {
+                append progressbar " "
+            }
+        }
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${suffix}"
+        flush stdout
+    }
+}
+
+namespace eval portclient::notifications {
+    ##
+    # Ports whose notifications to display; these were either installed
+    # or requested to be installed.
+    variable notificationsToPrint
+    array set notificationsToPrint {}
+
+    ##
+    # Add a port to the list for printing notifications.
+    #
+    # @param name
+    #        The name of the port.
+    # @param note
+    #        A list of notes to be stored for the given port.
+    proc append {name notes} {
+        variable notificationsToPrint
+
+        set notificationsToPrint($name) $notes
+    }
+
+    ##
+    # Print port notifications.
+    #
+    proc display {} {
+        global env
+        variable notificationsToPrint
+
+        # Display notes at the end of the activation phase.
+        if {[array size notificationsToPrint] > 0} {
+            ui_notice "--->  Some of the ports you installed have notes:"
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice "  $name has the following notes:"
+
+                # If env(COLUMNS) exists, limit each line's width to this width.
+                if {[info exists env(COLUMNS)]} {
+                    set maxlen $env(COLUMNS)
+
+                    foreach note $notes {
+                        foreach line [split $note "\n"] {
+                            set joiner ""
+                            set lines ""
+                            set newline "    "
+
+                            foreach word [split $line " "] {
+                                if {[string length $newline] + [string length $word] >= $maxlen} {
+                                    lappend lines $newline
+                                    set newline "    "
+                                    set joiner ""
+                                }
+                                ::append newline $joiner $word
+                                set joiner " "
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines "\n"]
+                        }
+                    }
+                } else {
+                    foreach note $notes {
+                        ui_notice $note
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+##########################################
+# Main
+##########################################
+
+# Global arrays passed to the macports1.0 layer
+array set ui_options        {}
+array set global_options    {}
+array set global_variations {}
+
+# Global options private to this script
+array set private_options {}
+
+# Make sure we get the size of the terminal
+# We do this here to save it in the boot_env, in case we determined it manually
+term_init_size
+
+global env boot_env argv0 cmdname argc argv cmd_argc cmd_argv cmd_argn \
+       current_portdir global_options_base exit_status
+
+# Save off a copy of the environment before mportinit monkeys with it
+array set boot_env [array get env]
+
+set cmdname [file tail $argv0]
+
+# Setp cmd_argv to match argv
+set cmd_argv $argv
+set cmd_argc $argc
+set cmd_argn 0
+
+# make sure we're using a sane umask
+umask 022
+
+# If we've been invoked as portf, then the first argument is assumed
+# to be the name of a command file (i.e., there is an implicit -F
+# before any arguments).
+if {[moreargs] && $cmdname eq "portf"} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options "global" ui_options global_options} result]} {
+    puts "Error: $result"
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    && $portclient::progress::hasTermAnsiSend eq "yes"
+    && (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne "yes")} {
+    set ui_options(progress_download) portclient::progress::download
+    set ui_options(progress_generic)  portclient::progress::generic
+}
+
+set ui_options(notifications_append) portclient::notifications::append
+
+# Get arguments remaining after option processing
+set remaining_args [lrange $cmd_argv $cmd_argn end]
+
+# If we have no arguments remaining after option processing then force
+# interactive mode
+if { [llength $remaining_args] == 0 && ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq "selfupdate" || [lookahead] eq "sync"} {
+    # tell mportinit not to tell the user they should selfupdate
+    set ui_options(ports_no_old_index_warning) 1
+}
+
+# Initialize mport
+# This must be done following parse of global options, as some options are
+# evaluated by mportinit.
+if {[catch {mportinit ui_options global_options global_variations} result]} {
+    global errorInfo
+    puts "$errorInfo"
+    fatal "Failed to initialize MacPorts, $result"
+}
+
+# Set up some global state for our code
+set current_portdir [pwd]
+
+# Freeze global_options into global_options_base; global_options
+# will be reset to global_options_base prior to processing each command.
+set global_options_base [array get global_options]
+
+# First process any remaining args as action(s)
+set exit_status 0
+if { [llength $remaining_args] > 0 } {
+
+    # If there are remaining arguments, process those as a command
+    set exit_status [process_cmd $remaining_args]
+}
+
+# Process any prescribed command files, including standard input
+if { ($exit_status == 0 || [macports::ui_isset ports_processall]) && [info exists ui_options(ports_commandfiles)] } {
+    set exit_status [process_command_files $ui_options(ports_commandfiles)]
+}
+if {$exit_status == -999} {
+    set exit_status 0
+}
+
+# shut down macports1.0
+mportshutdown
+
+# Return with exit_status
+exit $exit_status

Added: branches/gsoc14-cleanup/src/port/port.REMOTE.23878
===================================================================
--- branches/gsoc14-cleanup/src/port/port.REMOTE.23878	                        (rev 0)
+++ branches/gsoc14-cleanup/src/port/port.REMOTE.23878	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,5355 @@
+#!/opt/local/libexec/macports/bin/tclsh8.5
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
+# $Id: port.tcl 119177 2014-04-18 22:35:29Z cal at macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw <rshaw at opendarwin.org>
+# Copyright (c) 2002-2003 Apple Inc.
+# 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.
+# 3. Neither the name of Apple Inc. nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+# Create a namespace for some local variables
+namespace eval portclient::progress {
+    ##
+    # Indicate whether the term::ansi::send tcllib package is available and was
+    # imported. "yes", if the package is available, "no" otherwise.
+    variable hasTermAnsiSend no
+}
+
+if {![catch {package require term::ansi::send}]} {
+    set portclient::progress::hasTermAnsiSend yes
+}
+
+package require macports
+package require Pextlib 1.0
+
+# Standard procedures
+proc print_usage {{verbose 1}} {
+    global cmdname
+    set syntax {
+        [-bcdfknopqRstuvy] [-D portdir] [-F cmdfile] action [privopts] [actionflags]
+        [[portname|pseudo-portname|port-url] [@version] [+-variant]... [option=value]...]...
+    }
+
+    if {$verbose} {
+        puts stderr "Usage: $cmdname$syntax"
+        puts stderr "\"$cmdname help\" or \"man 1 port\" for more information."
+    } else {
+        puts stderr "$cmdname$syntax"
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds ""
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen > 65} {
+            set cmds "$cmds,\n"
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new "$cmd"
+        } else {
+            set new ", $cmd"
+        }
+        incr lineLen [string length $new]
+        set cmds "$cmds$new"
+    }
+
+    set cmdText "Supported actions
+------------------
+$cmds
+"
+
+    set text {
+Pseudo-portnames
+----------------
+Pseudo-portnames are words that may be used in place of a portname, and
+which expand to some set of ports. The common pseudo-portnames are:
+all, current, active, inactive, actinact, installed, uninstalled, outdated,
+obsolete, requested, unrequested and leaves.
+These pseudo-portnames expand to the set of ports named.
+
+Pseudo-portnames starting with variants:, variant:, description:, depends:,
+depends_lib:, depends_run:, depends_build:, depends_fetch:, depends_extract:,
+portdir:, homepage:, epoch:, platforms:, platform:, name:, long_description:,
+maintainers:, maintainer:, categories:, category:, version:, revision:, and
+license: each select a set of ports based on a regex search of metadata
+about the ports. In all such cases, a standard regex pattern following
+the colon will be used to select the set of ports to which the
+pseudo-portname expands.
+
+Pseudo-portnames starting with depof:, rdepof:, dependentof:, and rdependentof:
+select ports that are direct or recursive dependencies or dependents of the
+following portname, respectively.
+
+Portnames that contain standard glob characters will be expanded to the
+set of ports matching the glob pattern.
+    
+Port expressions
+----------------
+Portnames, port glob patterns, and pseudo-portnames may be logically
+combined using expressions consisting of and, or, not, !, (, and ).
+    
+For more information
+--------------------
+See man pages: port(1), macports.conf(5), portfile(7), portgroup(7),
+porthier(7), portstyle(7). Also, see http://www.macports.org.
+    }
+
+    puts "$cmdText$text"
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error "$argv0: $s"
+    exit 1
+}
+
+##
+# Helper function to define constants
+#
+# Constants defined with const can simply be accessed in the same way as
+# calling a proc.
+#
+# Example:
+# const FOO 42
+# puts [FOO]
+#
+# @param name variable name
+# @param value constant variable value
+proc const {name args} {
+    proc $name {} [list return [expr $args]]
+}
+
+# Format an integer representing bytes using given units
+proc bytesize {siz {unit {}} {format {%.3f}}} {
+    if {$unit == {}} {
+        if {$siz > 0x40000000} {
+            set unit "GiB"
+        } elseif {$siz > 0x100000} {
+            set unit "MiB"
+        } elseif {$siz > 0x400} {
+            set unit "KiB"
+        } else {
+            set unit "B"
+        }
+    }
+    switch -- $unit {
+        KiB {
+            set siz [expr {$siz / 1024.0}]
+        }
+        kB {
+            set siz [expr {$siz / 1000.0}]
+        }
+        MiB {
+            set siz [expr {$siz / 1048576.0}]
+        }
+        MB {
+            set siz [expr {$siz / 1000000.0}]
+        }
+        GiB {
+            set siz [expr {$siz / 1073741824.0}]
+        }
+        GB {
+            set siz [expr {$siz / 1000000000.0}]
+        }
+        B { }
+        default {
+            ui_warn "Unknown file size unit '$unit' specified"
+            set unit "B"
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return "$siz $unit"
+}
+
+proc filesize {fil {unit {}}} {
+    set siz {@}
+    catch {
+        set siz [bytesize [file size $fil] $unit]
+    }
+    return $siz
+}
+
+# Produce an error message, and exit, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc fatal_softcontinue s {
+    if {[macports::global_option_isset ports_force]} {
+        ui_error $s
+        return -code continue
+    } else {
+        fatal $s
+    }
+}
+
+
+# Produce an error message, and break, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc break_softcontinue { msg status name_status } {
+    upvar $name_status status_var 
+    ui_error $msg
+    if {[macports::ui_isset ports_processall]} {
+        set status_var 0
+        return -code continue
+    } else {
+        set status_var $status
+        return -code break
+    }
+}
+
+# show the URL for the ticket reporting instructions
+proc print_tickets_url {args} {
+    if {${macports::prefix} ne "/usr/local" && ${macports::prefix} ne "/usr"} {
+        ui_error "Follow http://guide.macports.org/#project.tickets to report a bug."
+    }
+}
+
+# Form a composite version as is sometimes used for registry functions
+# This function sorts the variants and presents them in a canonical representation
+proc composite_version {version variations {emptyVersionOkay 0}} {
+    # Form a composite version out of the version and variations
+    
+    # Select the variations into positive and negative
+    set pos {}
+    set neg {}
+    foreach { key val } $variations {
+        if {$val eq "+"} {
+            lappend pos $key
+        } elseif {$val eq "-"} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version ""
+    if {$version ne "" || $emptyVersionOkay} {
+        set pos_str ""
+        set neg_str ""
+
+        if {[llength $pos]} {
+            set pos_str "+[join [lsort -ascii $pos] "+"]"
+        }
+        if {[llength $neg]} {
+            set neg_str "-[join [lsort -ascii $neg] "-"]"
+        }
+
+        set composite_version "$version$pos_str$neg_str"
+    }
+
+    return $composite_version
+}
+
+
+proc split_variants {variants} {
+    set result {}
+    set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
+    foreach { match sign variant } $l {
+        lappend result $variant $sign
+    }
+    return $result
+}
+
+
+##
+# Maps friendly field names to their real name
+# Names which do not need mapping are not changed.
+#
+# @param field friendly name
+# @return real name
+proc map_friendly_field_names { field } {
+    switch -- $field {
+        variant -
+        platform -
+        maintainer -
+        subport {
+            set field "${field}s"
+        }
+        category {
+            set field "categories"
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion ""}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] > 1 } {
+        # set portname again since the one we were passed may not have had the correct case
+        set portname [lindex $ilist 0 0]
+        ui_notice "The following versions of $portname are currently installed:"
+        foreach i [portlist_sortint $ilist] { 
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants} (active)"
+            }
+        }
+        return -code error "Registry error: Please specify the full version as recorded in the port registry."
+    } else {
+        return [lindex $ilist 0]
+    }
+}
+
+
+proc entry_for_portlist {portentry} {
+    global global_options global_variations
+
+    # Each portlist entry currently has the following elements in it:
+    #   url             if any
+    #   name
+    #   version         (version_revision)
+    #   variants array  (variant=>+-)
+    #   requested_variants array  (variant=>+-)
+    #   options array   (key=>value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) "" }
+    if {![info exists port(name)]}      { set port(name) "" }
+    if {![info exists port(version)]}   { set port(version) "" }
+    if {![info exists port(variants)]}  { set port(variants) "" }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) "" }
+    if {![info exists port(options)]}   { set port(options) [array get global_options] }
+
+    # If neither portname nor url is specified, then default to the current port
+    if { $port(url) eq "" && $port(name) eq "" } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq ""} {
+            ui_error "A default port name could not be supplied."
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) "$port(name)/[composite_version $port(version) $port(variants)]"
+    
+    return [array get port]
+}
+
+
+proc add_to_portlist {listname portentry} {
+    upvar $listname portlist
+    
+    # Form portlist entry and add to portlist
+    lappend portlist [entry_for_portlist $portentry]
+}
+
+
+proc add_ports_to_portlist {listname ports {overridelist ""}} {
+    upvar $listname portlist
+
+    array set overrides $overridelist
+
+    # Add each entry to the named portlist, overriding any values
+    # specified as overrides
+    foreach portentry $ports {
+        array set port $portentry
+        if ([info exists overrides(version)])   { set port(version) $overrides(version) }
+        if ([info exists overrides(variants)])  { set port(variants) $overrides(variants) }
+        if ([info exists overrides(requested_variants)])  { set port(requested_variants) $overrides(requested_variants) }
+        if ([info exists overrides(options)])   { set port(options) $overrides(options) }
+        add_to_portlist portlist [array get port]
+    }
+}
+
+
+proc url_to_portname { url {quiet 0} } {
+    # Save directory and restore the directory, since mportopen changes it
+    set savedir [pwd]
+    set portname ""
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg "Can't map the URL '$url' to a port description file (\"${result}\")."
+            ui_msg "Please verify that the directory and portfile syntax are correct."
+        }
+    } else {
+        array set portinfo [mportinfo $ctx]
+        set portname $portinfo(name)
+        mportclose $ctx
+    }
+    cd $savedir
+    return $portname
+}
+
+
+# Supply a default porturl/portname if the portlist is empty
+proc require_portlist { nameportlist {is_upgrade "no"} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 && (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        if {${is_upgrade} == "yes"} {
+            # $> port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # "upgrade", let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg "Nothing to upgrade."
+            return 1
+        }
+        ui_error "No ports matched the given expression"
+        return 1
+    }
+
+    if {[llength $portlist] == 0} {
+        set portlist [get_current_port]
+
+        if {[llength $portlist] == 0} {
+            # there was no port in current directory
+            return 1
+        }
+    }
+
+    return 0
+}
+
+
+# Execute the enclosed block once for every element in the portlist
+# When the block is entered, the following variables will have been set:
+#   portspec, porturl, portname, portversion, options, variations, requested_variations
+proc foreachport {portlist block} {
+    set savedir [pwd]
+    foreach portspec $portlist {
+    
+        # Set the variables for the block
+        uplevel 1 "array unset portspec; array set portspec { $portspec }"
+        uplevel 1 {
+            set porturl $portspec(url)
+            set portname $portspec(name)
+            set portversion $portspec(version)
+            array unset variations
+            array set variations $portspec(variants)
+            array unset requested_variations
+            array set requested_variations $portspec(requested_variants)
+            array unset options
+            array set options $portspec(options)
+        }
+        
+        # Invoke block
+        uplevel 1 $block
+        
+        # Restore cwd after each port, since mportopen changes it, and otherwise relative
+        # urls would break on subsequent passes
+        if {[file exists $savedir]} {
+            cd $savedir
+        } else {
+            cd ~
+        }
+    }
+}
+
+
+proc portlist_compare { a b } {
+    array set a_ $a
+    array set b_ $b
+    set namecmp [string equal -nocase $a_(name) $b_(name)]
+    if {$namecmp != 1} {
+        if {$a_(name) eq [lindex [lsort -dictionary [list $a_(name) $b_(name)]] 0]} {
+            return -1
+        }
+        return 1
+    }
+    set avr_ [split $a_(version) "_"]
+    set bvr_ [split $b_(version) "_"]
+    set versioncmp [vercmp [lindex $avr_ 0] [lindex $bvr_ 0]]
+    if {$versioncmp != 0} {
+        return $versioncmp
+    }
+    set ar_ [lindex $avr_ 1]
+    set br_ [lindex $bvr_ 1]
+    if {$ar_ < $br_} {
+        return -1
+    } elseif {$ar_ > $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name at version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list "name" [lindex $a 0] "version" "[lindex $a 1]_[lindex $a 2]"]
+    array set b_ [list "name" [lindex $b 0] "version" "[lindex $b 1]_[lindex $b 2]"]
+    return [portlist_compare [array get a_] [array get b_]]
+}
+
+# Same as portlist_sort, but with numeric indexes {name version revision}
+proc portlist_sortint { list } {
+    return [lsort -command portlist_compareint $list]
+}
+
+# sort portlist so dependents come before their dependencies
+proc portlist_sortdependents { portlist } {
+    foreach p $portlist {
+        array set pvals $p
+        lappend entries($pvals(name)) $p
+        if {![info exists dependents($pvals(name))]} {
+            set dependents($pvals(name)) {}
+            foreach result [registry::list_dependents $pvals(name)] {
+                lappend dependents($pvals(name)) [lindex $result 2]
+            }
+        }
+        array unset pvals
+    }
+    set ret {}
+    foreach p $portlist {
+        portlist_sortdependents_helper $p entries dependents seen ret
+    }
+    return $ret
+}
+
+proc portlist_sortdependents_helper {p up_entries up_dependents up_seen up_retlist} {
+    upvar $up_seen seen
+    if {![info exists seen($p)]} {
+        set seen($p) 1
+        upvar $up_entries entries $up_dependents dependents $up_retlist retlist
+        array set pvals $p
+        foreach dependent $dependents($pvals(name)) {
+            if {[info exists entries($dependent)]} {
+                foreach entry $entries($dependent) {
+                    portlist_sortdependents_helper $entry entries dependents seen retlist
+                }
+            }
+        }
+        lappend retlist $p
+    }
+}
+
+proc regex_pat_sanitize { s } {
+    set sanitized [regsub -all {[\\(){}+$.^]} $s {\\&}]
+    return $sanitized
+}
+
+##
+# Makes sure we get the current terminal size
+proc term_init_size {} {
+    global env
+
+    if {![info exists env(COLUMNS)] || ![info exists env(LINES)]} {
+        if {[isatty stdout]} {
+            set size [term_get_size stdout]
+
+            if {![info exists env(LINES)] && [lindex $size 0] > 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] && [lindex $size 1] > 0} {
+                set env(COLUMNS) [lindex $size 1]
+            }
+        }
+    }
+}
+
+##
+# Wraps a multi-line string at specified textwidth
+#
+# @see wrapline
+#
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrap {string maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set splitstring {}
+    set indentline $indentfirstline
+    foreach line [split $string "\n"] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring "\n"]
+}
+
+##
+# Wraps a line at specified textwidth
+#
+# @see wrap
+#
+# @param line input line
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrapline {line maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set string [split $line " "]
+    if {$indentfirstline == 0} {
+        set newline ""
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner " "
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] >= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner ""
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 && $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner " "
+    }
+    lappend lines $newline
+    return [join $lines "\n"]
+}
+
+##
+# Wraps a line at a specified width with a label in front
+#
+# @see wrap
+#
+# @param label label for output
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @return wrapped string
+proc wraplabel {label string maxlen {indent ""}} {
+    append label ": [string repeat " " [expr {[string length $indent] - [string length "$label: "]}]]"
+    return "$label[wrap $string $maxlen $indent 0]"
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first "@" $m] < 0} {
+            if {[string first ":" $m] >= 0} {
+                set m [regsub -- "(.*):(.*)" $m "\\2@\\1"] 
+            } else {
+                set m "$m at macports.org"
+            }
+        }
+        lappend result $m
+    }
+    return $result
+}
+
+
+##########################################
+# Port selection
+##########################################
+proc unique_results_to_portlist {infos} {
+    set result {}
+    array unset unique
+    foreach {name info} $infos {
+        array unset portinfo
+        array set portinfo $info
+        
+        set portentry [entry_for_portlist [list url $portinfo(porturl) name $name]]
+        
+        array unset entry
+        array set entry $portentry
+        
+        if {[info exists unique($entry(fullname))]} continue
+        set unique($entry(fullname)) 1
+        
+        lappend result $portentry
+    }
+    return $result
+}
+
+
+proc get_matching_ports {pattern {casesensitive no} {matchstyle glob} {field name}} {
+    if {[catch {set res [mportsearch $pattern $casesensitive $matchstyle $field]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        fatal "search for portname $pattern failed: $result"
+    }
+    set results [unique_results_to_portlist $res]
+    
+    # Return the list of all ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_all_ports {} {
+    global all_ports_cache
+
+    if {![info exists all_ports_cache]} {
+         if {[catch {set res [mportlistall]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "listing all ports failed: $result"
+        }
+        set results [unique_results_to_portlist $res]
+        set all_ports_cache [portlist_sort $results]
+    }
+    return $all_ports_cache
+}
+
+
+proc get_current_ports {} {
+    # This is just a synonym for get_current_port that
+    # works with the regex in element
+    return [get_current_port]
+}
+
+
+proc get_current_port {} {
+    set url file://.
+    set portname [url_to_portname $url]
+    if {$portname eq ""} {
+        ui_msg "To use the current port, you must be in a port's directory."
+        return [list]
+    }
+
+    set results {}
+    add_to_portlist results [list url $url name $portname]
+    return $results
+}
+
+
+proc get_installed_ports { {ignore_active yes} {active yes} } {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [split_variants [lindex $i 3]]
+        set iactive [lindex $i 4]
+
+        if { ${ignore_active} == "yes" || (${active} == "yes") == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants $ivariants]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_uninstalled_ports {} {
+    # Return all - installed
+    set all [get_all_ports]
+    set installed [get_installed_ports]
+    return [opComplement $all $installed]
+}
+
+
+proc get_active_ports {} {
+    return [get_installed_ports no yes]
+}
+
+
+proc get_inactive_ports {} {
+    return [get_installed_ports no no]
+}
+
+proc get_actinact_ports {} {
+    set inactive_ports [get_inactive_ports]
+    set active_ports [get_active_ports]
+    set results {}
+
+    foreach port $inactive_ports {
+        array set portspec $port
+        set portname $portspec(name)
+        lappend inact($portname) $port
+    }
+
+    foreach port $active_ports {
+        array set portspec $port
+        set portname $portspec(name)
+
+        if {[info exists inact($portname)]} {
+            if {![info exists added_inact($portname)]} {
+                foreach inact_spec $inact($portname) {
+                    lappend results $inact_spec
+                }
+                set added_inact($portname) 1
+            }
+            lappend results $port
+        }
+    }
+    return $results
+}
+
+
+proc get_outdated_ports {} {
+    # Get the list of installed ports
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] > 0 } {
+        foreach i $ilist {
+
+            # Get information about the installed port
+            set portname            [lindex $i 0]
+            set installed_version   [lindex $i 1]
+            set installed_revision  [lindex $i 2]
+            set installed_compound  "${installed_version}_${installed_revision}"
+            set installed_variants  [lindex $i 3]
+
+            set is_active           [lindex $i 4]
+            if {$is_active == 0} continue
+
+            set installed_epoch     [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                fatal "lookup of portname $portname failed: $result"
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+
+            # Get information about latest available version and revision
+            set latest_version $portinfo(version)
+            set latest_revision     0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     "${latest_version}_${latest_revision}"
+            set latest_epoch        0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch    $portinfo(epoch)
+            }
+
+            # Compare versions, first checking epoch, then version, then revision
+            set comp_result 0
+            if {$installed_version != $latest_version} {
+                set comp_result [expr {$installed_epoch - $latest_epoch}]
+                if { $comp_result == 0 } {
+                    set comp_result [vercmp $installed_version $latest_version]
+                }
+            }
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            if {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision $installed_variants $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                }
+            }
+
+            # Add outdated ports to our results list
+            if { $comp_result < 0 } {
+                add_to_portlist results [list name $portname version $installed_compound variants [split_variants $installed_variants]]
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_obsolete_ports {} {
+    set ilist [get_installed_ports]
+    set results {}
+
+    foreach i $ilist {
+        array set port $i
+
+        if {[catch {mportlookup $port(name)} result]} {
+            ui_debug "$::errorInfo"
+            break_softcontinue "lookup of portname $portname failed: $result" 1 status
+        }
+
+        if {[llength $result] < 2} {
+            lappend results $i
+        }
+    }
+
+    # Return the list of ports, already sorted
+    return [portlist_sort $results]
+}
+
+# return ports that have registry property $propname set to $propval
+proc get_ports_with_prop {propname propval} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [lindex $i 3]
+        set iepoch [lindex $i 5]
+        set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
+        if {[registry::property_retrieve $regref $propname] == $propval} {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants [split_variants $ivariants]]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+proc get_requested_ports {} {
+    return [get_ports_with_prop requested 1]
+}
+
+proc get_unrequested_ports {} {
+    return [get_ports_with_prop requested 0]
+}
+
+proc get_leaves_ports {} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq ""} {
+            add_to_portlist results [list name $iname version "[lindex $i 1]_[lindex $i 2]" variants [split_variants [lindex $i 3]]]
+        }
+    }
+    return [portlist_sort [opIntersection $results [get_unrequested_ports]]]
+}
+
+proc get_dependent_ports {portname recursive} {
+    registry::open_dep_map
+    set deplist [registry::list_dependents $portname]
+    # could return specific versions here using registry2.0 features
+    set results {}
+    foreach dep $deplist {
+        add_to_portlist results [list name [lindex $dep 2]]
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex $dep 2]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    set rdeplist [registry::list_dependents $depname]
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex $rdep 2]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_dep_ports {portname recursive} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its deps
+    set results {}
+    set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+
+    set deplist {}
+    foreach type $deptypes {
+        if {[info exists portinfo($type)]} {
+            foreach dep $portinfo($type) {
+                add_to_portlist results [list name [lindex [split $dep :] end]]
+                lappend deplist $dep
+            }
+        }
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        return -code error "lookup of portname $depname failed: $result"
+                    }
+                    if {[llength $result] < 2} {
+                        ui_error "Port $depname not found"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                
+                    # open its portfile
+                    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+                        ui_debug "$::errorInfo"
+                        ui_error "Unable to open port: $result"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [mportinfo $mport]
+                    mportclose $mport
+
+                    # collect its deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                add_to_portlist results [list name [lindex [split $rdep :] end]]
+                                lappend rdeplist $rdep
+                            }
+                        }
+                    }
+
+                    # add them to the lists
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex [split $rdep :] end]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+proc get_subports {portname} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its subports
+    set results {}
+
+    if {[info exists portinfo(subports)]} {
+        foreach subport $portinfo(subports) {
+            add_to_portlist results [list name $subport]
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+##########################################
+# Port expressions
+##########################################
+proc portExpr { resname } {
+    upvar $resname reslist
+    set result [seqExpr reslist]
+    return $result
+}
+
+
+proc seqExpr { resname } {
+    upvar $resname reslist
+    
+    # Evaluate a sequence of expressions a b c...
+    # These act the same as a or b or c
+
+    set result 1
+    while {$result} {
+        switch -- [lookahead] {
+            ;       -
+            )       -
+            _EOF_   { break }
+        }
+
+        set blist {}
+        set result [orExpr blist]
+        if {$result} {
+            # Calculate the union of result and b
+            set reslist [opUnion $reslist $blist]
+        }
+    }
+    
+    return $result
+}
+
+
+proc orExpr { resname } {
+    upvar $resname reslist
+    
+    set a [andExpr reslist]
+    while ($a) {
+        switch -- [lookahead] {
+            or {
+                    advance
+                    set blist {}
+                    if {![andExpr blist]} {
+                        return 0
+                    }
+                        
+                    # Calculate a union b
+                    set reslist [opUnion $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc andExpr { resname } {
+    upvar $resname reslist
+    
+    set a [unaryExpr reslist]
+    while {$a} {
+        switch -- [lookahead] {
+            and {
+                    advance
+                    
+                    set blist {}
+                    set b [unaryExpr blist]
+                    if {!$b} {
+                        return 0
+                    }
+                    
+                    # Calculate a intersect b
+                    set reslist [opIntersection $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc unaryExpr { resname } {
+    upvar $resname reslist
+    set result 0
+
+    switch -- [lookahead] {
+        !   -
+        not {
+                advance
+                set blist {}
+                set result [unaryExpr blist]
+                if {$result} {
+                    set all [get_all_ports]
+                    set reslist [opComplement $all $blist]
+                }
+            }
+        default {
+                set result [element reslist]
+            }
+    }
+    
+    return $result
+}
+
+
+proc element { resname } {
+    upvar $resname reslist
+    set el 0
+    
+    set url ""
+    set name ""
+    set version ""
+    array unset requested_variants
+    array unset options
+    
+    set token [lookahead]
+    switch -regex -- $token {
+        ^\\)$               -
+        ^\;                 -
+        ^_EOF_$             { # End of expression/cmd/file
+        }
+
+        ^\\($               { # Parenthesized Expression
+            advance
+            set el [portExpr reslist]
+            if {!$el || ![match ")"]} {
+                set el 0
+            }
+        }
+
+        ^all(@.*)?$         -
+        ^installed(@.*)?$   -
+        ^uninstalled(@.*)?$ -
+        ^active(@.*)?$      -
+        ^inactive(@.*)?$    -
+        ^actinact(@.*)?$    -
+        ^leaves(@.*)?$      -
+        ^outdated(@.*)?$    -
+        ^obsolete(@.*)?$    -
+        ^requested(@.*)?$   -
+        ^unrequested(@.*)?$ -
+        ^current(@.*)?$     {
+            # A simple pseudo-port name
+            advance
+
+            # Break off the version component, if there is one
+            regexp {^(\w+)(@.*)?} $token matchvar name remainder
+
+            add_multiple_ports reslist [get_${name}_ports] $remainder
+
+            set el 1
+        }
+
+        ^variants:          -
+        ^variant:           -
+        ^description:       -
+        ^portdir:           -
+        ^homepage:          -
+        ^epoch:             -
+        ^platforms:         -
+        ^platform:          -
+        ^name:              -
+        ^long_description:  -
+        ^maintainers:       -
+        ^maintainer:        -
+        ^categories:        -
+        ^category:          -
+        ^version:           -
+        ^depends_lib:       -
+        ^depends_build:     -
+        ^depends_run:       -
+        ^depends_extract:   -
+        ^depends_fetch:     -
+        ^replaced_by:       -
+        ^revision:          -
+        ^subport:           -
+        ^subports:          -
+        ^license:           { # Handle special port selectors
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            # Remap friendly names to actual names
+            set field [map_friendly_field_names $field]
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp $field]
+            set el 1
+        }
+
+        ^depends:           { # A port selector shorthand for depends_{lib,build,run,fetch,extract}
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_lib"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_build"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_run"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_extract"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_fetch"]
+
+            set el 1
+        }
+
+        ^dependentof:       -
+        ^rdependentof:      {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdependentof"]
+            add_multiple_ports reslist [get_dependent_ports $portname $recursive]
+            
+            set el 1
+        }
+        
+        ^depof:             -
+        ^rdepof:            {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdepof"]
+            add_multiple_ports reslist [get_dep_ports $portname $recursive]
+            
+            set el 1
+        }
+
+        ^subportof:         {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            add_multiple_ports reslist [get_subports $portname]
+
+            set el 1
+        }
+
+        [][?*]              { # Handle portname glob patterns
+            advance; add_multiple_ports reslist [get_matching_ports $token no glob]
+            set el 1
+        }
+
+        ^\\w+:.+            { # Handle a url by trying to open it as a port and mapping the name
+            advance
+            set name [url_to_portname $token]
+            if {$name ne ""} {
+                parsePortSpec version requested_variants options
+                add_to_portlist reslist [list url $token \
+                  name $name \
+                  version $version \
+                  requested_variants [array get requested_variants] \
+                  variants [array get requested_variants] \
+                  options [array get options]]
+                set el 1
+            } else {
+                ui_error "Can't open URL '$token' as a port"
+                set el 0
+            }
+        }
+
+        default             { # Treat anything else as a portspec (portname, version, variants, options
+            # or some combination thereof).
+            parseFullPortSpec url name version requested_variants options
+            add_to_portlist reslist [list url $url \
+              name $name \
+              version $version \
+              requested_variants [array get requested_variants] \
+              variants [array get requested_variants] \
+              options [array get options]]
+            set el 1
+        }
+    }
+
+    return $el
+}
+
+
+proc add_multiple_ports { resname ports {remainder ""} } {
+    upvar $resname reslist
+    
+    set version ""
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne ""} { set overrides(version) $version }
+    if {[array size variants]} {
+        # we always record the requested variants separately,
+        # but requested ones always override existing ones
+        set overrides(requested_variants) [array get variants]
+        set overrides(variants) [array get variants]
+    }
+    if {[array size options]} { set overrides(options) [array get options] }
+
+    add_ports_to_portlist reslist $ports [array get overrides]
+}
+
+
+proc unique_entries { entries } {
+    # Form the list of all the unique elements in the list a,
+    # considering only the port fullname, and taking the first
+    # found element first
+    set result {}
+    array unset unique
+    foreach item $entries {
+        array set port $item
+        if {[info exists unique($port(fullname))]} continue
+        set unique($port(fullname)) 1
+        lappend result $item
+    }
+    return $result
+}
+
+
+proc opUnion { a b } {
+    # Return the unique elements in the combined two lists
+    return [unique_entries [concat $a $b]]
+}
+
+
+proc opIntersection { a b } {
+    set result {}
+    
+    # Rules we follow in performing the intersection of two port lists:
+    #
+    #   a/, a/          ==> a/
+    #   a/, b/          ==>
+    #   a/, a/1.0       ==> a/1.0
+    #   a/1.0, a/       ==> a/1.0
+    #   a/1.0, a/2.0    ==>
+    #
+    #   If there's an exact match, we take it.
+    #   If there's a match between simple and discriminated, we take the later.
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem [unique_entries $b] {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, matching against b
+    foreach aitem [unique_entries $a] {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+        foreach match $matches {
+            if {$simpleform} {
+                set i $bfull($match)
+                lappend result [lindex $b $i]
+            } else {
+                lappend result $aitem
+            }
+        }
+    }
+    
+    return $result
+}
+
+
+proc opComplement { a b } {
+    set result {}
+    
+    # Return all elements of a not matching elements in b
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem $b {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, taking all those items that don't match b
+    foreach aitem $a {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+
+        # We copy this element to result only if it didn't match against b
+        if {![llength $matches]} {
+            lappend result $aitem
+        }
+    }
+    
+    return $result
+}
+
+
+proc parseFullPortSpec { urlname namename vername varname optname } {
+    upvar $urlname porturl
+    upvar $namename portname
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    set portname ""
+    set portversion ""
+    array unset portvariants
+    array unset portoptions
+    
+    if { [moreargs] } {
+        # Look first for a potential portname
+        #
+        # We need to allow a wide variety of tokens here, because of actions like "provides"
+        # so we take a rather lenient view of what a "portname" is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder ""
+        if {![regexp {^(@|[-+]([[:alpha:]_]+[\w\.]*)|[[:alpha:]_]+[\w\.]*=)} $token match]} {
+            advance
+            regexp {^([^@]+)(@.*)?} $token match portname remainder
+            
+            # If the portname contains a /, then try to use it as a URL
+            if {[string match "*/*" $portname]} {
+                set url "file://$portname"
+                set name [url_to_portname $url 1]
+                if { $name ne "" } {
+                    # We mapped the url to valid port
+                    set porturl $url
+                    set portname $name
+                    # Continue to parse rest of portspec....
+                } else {
+                    # We didn't map the url to a port; treat it
+                    # as a raw string for something like port contents
+                    # or cd
+                    set porturl ""
+                    # Since this isn't a port, we don't try to parse
+                    # any remaining portspec....
+                    return
+                }
+            }
+        }
+        
+        # Now parse the rest of the spec
+        parsePortSpec portversion portvariants portoptions $remainder
+    }
+}
+
+# check if the install prefix is writable
+# should be called by actions that will modify it
+proc prefix_unwritable {} {
+    global macports::portdbpath
+    if {[file writable $portdbpath]} {
+        return 0
+    } else {
+        ui_error "Insufficient privileges to write to MacPorts install prefix."
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder ""} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion ""
+    array unset portoptions
+    array set portoptions [array get global_options]
+    array unset portvariants
+    
+    # Parse port version/variants/options
+    set opt $remainder
+    set adv 0
+    set consumed 0
+    for {set firstTime 1} {$opt ne "" || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq ""} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime && [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first "/" $opt]
+            if {$sepPos >= 0} {
+                # Version terminated by "/" to disambiguate -variant from part of version
+                set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                set opt [string range $opt [expr {$sepPos + 1}] end]
+            } else {
+                # Version terminated by "+", or else is complete
+                set sepPos [string first "+" $opt]
+                if {$sepPos >= 0} {
+                    # Version terminated by "+"
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt ""
+                }
+            }
+            set consumed 1
+        } else {
+            # Parse all other options
+            
+            # Look first for a variable setting: VARNAME=VALUE
+            if {[regexp {^([[:alpha:]_]+[\w\.]*)=(.*)} $opt match key val] == 1} {
+                # It's a variable setting
+                set portoptions($key) "\"$val\""
+                set opt ""
+                set consumed 1
+            } elseif {[regexp {^([-+])([[:alpha:]_]+[\w\.]*)} $opt match sign variant] == 1} {
+                # It's a variant
+                set portvariants($variant) $sign
+                set opt [string range $opt [expr {[string length $variant] + 1}] end]
+                set consumed 1
+            } else {
+                # Not an option we recognize, so break from port option processing
+                if { $consumed && $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds ""
+        if {[info exists cmd_opts_array($action)]} {
+            foreach opt $cmd_opts_array($action) {
+                if {[llength $opt] == 1} {
+                    set name $opt
+                    set optc 0
+                } else {
+                    set name [lindex $opt 0]
+                    set optc [lindex $opt 1]
+                }
+
+                append cmds " --$name"
+
+                for {set i 1} {$i <= $optc} {incr i} {
+                    append cmds " <arg$i>"
+                }
+            }
+        }
+        set args ""
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <arguments>"
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <portlist>"
+        }
+
+        set ret "Usage: "
+        set len [string length $action]
+        append ret [wrap "$action$cmds$args" 0 [string repeat " " [expr {8 + $len}]] 0]
+        append ret "\n"
+
+        return $ret
+    }
+
+    return -1
+}
+
+proc action_usage { action portlist opts } {
+    if {[llength $portlist] == 0} {
+        print_usage
+        return 0
+    }
+
+    foreach topic $portlist {
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile "$macports::prefix/var/macports/port-help.tcl"
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr "Error reading helpfile $helpfile: $err"
+            return 1
+        }
+    } else {
+        puts stderr "Unable to open help file $helpfile"
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr "No help for topic $topic"
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+
+        puts stderr $porthelp($topic)
+    }
+
+    return 0
+}
+
+
+proc action_log { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array unset portinfo
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+            set portname $portinfo(name)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            array unset portinfo
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] "main.log"]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue "Could not open file $logfile: $result" 1 status
+            }
+            set data [read $fp]
+            set data [split $data "\n"]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase "\[a-z\]*"
+            }
+
+            if {[info exists global_options(ports_log_level)]} {
+                set index [lsearch -exact ${macports::ui_priorities} $global_options(ports_log_level)]
+                if {$index == -1} {
+                    set prefix ""
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] "|"]
+                }
+            } else {
+                set prefix "\[a-z\]*"
+            }
+            foreach line $data {
+                set exp "^:($prefix|any):($phase|any) (.*)$"
+                if {[regexp $exp $line -> lpriority lphase lmsg] == 1} {
+                    puts "[macports::ui_prefix_default $lpriority]$lmsg"
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue "Log file for port $portname not found" 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator ""
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] && $options(ports_info_index)} {
+            set index_only 1
+        }
+        puts -nonewline $separator
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq "" || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!$index_only} {
+            # Add any global_variations to the variations
+            # specified for the port (so we get e.g. dependencies right)
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+ 
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            unset options(subport)
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "no PortIndex entry found for $portname"
+            continue
+        }
+        array unset options ports_info_index
+
+        # Understand which info items are actually lists
+        # (this could be overloaded to provide a generic formatting code to
+        # allow us to, say, split off the prefix on libs)
+        array set list_map "
+            categories      1
+            depends_fetch   1
+            depends_extract 1
+            depends_build   1
+            depends_lib     1
+            depends_run     1
+            maintainers     1
+            platforms       1
+            variants        1
+            conflicts       1
+            subports        1
+        "
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     ""
+            variants    Variants
+            depends_fetch "Fetch Dependencies"
+            depends_extract "Extract Dependencies"
+            depends_build "Build Dependencies"
+            depends_run "Runtime Dependencies"
+            depends_lib "Library Dependencies"
+            description "Brief Description"
+            long_description "Description"
+            fullname    "Full Name: "
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   "Conflicts with"
+            replaced_by "Replaced by"
+            subports    "Sub-ports"
+        }
+
+        # Wrap-length map for pretty printing
+        array set pretty_wrap {
+            heading 0
+            replaced_by 22
+            variants 22
+            depends_fetch 22
+            depends_extract 22
+            depends_build 22
+            depends_run 22
+            depends_lib 22
+            description 22
+            long_description 22
+            homepage 22
+            platforms 22
+            license 22
+            conflicts 22
+            maintainers 22
+            subports 22
+        }
+
+        # Interpret a convenient field abbreviation
+        if {[info exists options(ports_info_depends)] && $options(ports_info_depends) eq "yes"} {
+            array unset options ports_info_depends
+            set options(ports_info_depends_fetch) yes
+            set options(ports_info_depends_extract) yes
+            set options(ports_info_depends_build) yes
+            set options(ports_info_depends_lib) yes
+            set options(ports_info_depends_run) yes
+        }
+                
+        # Set up our field separators
+        set show_label 1
+        set field_sep "\n"
+        set subfield_sep ", "
+        set pretty_print 0
+        
+        # For human-readable summary, which is the default with no options
+        if {[llength [array get options ports_info_*]] == 0} {
+            set pretty_print 1
+        } elseif {[info exists options(ports_info_pretty)]} {
+            set pretty_print 1
+            array unset options ports_info_pretty
+        }
+
+        # Tune for sort(1)
+        if {[info exists options(ports_info_line)]} {
+            array unset options ports_info_line
+            set noseparator 1
+            set show_label 0
+            set field_sep "\t"
+            set subfield_sep ","
+        }
+        
+        # Figure out whether to show field name
+        set quiet [macports::ui_isset ports_quiet]
+        if {$quiet} {
+            set show_label 0
+        }
+        # In pretty-print mode we also suppress messages, even though we show
+        # most of the labels:
+        if {$pretty_print} {
+            set quiet 1
+        }
+
+        # Spin through action options, emitting information for any found
+        set fields {}
+        set opts_todo [array names options ports_info_*]
+        set fields_tried {}
+        if {![llength $opts_todo]} {
+            set opts_todo {ports_info_heading
+                ports_info_replaced_by
+                ports_info_subports
+                ports_info_variants 
+                ports_info_skip_line
+                ports_info_long_description ports_info_homepage 
+                ports_info_skip_line ports_info_depends_fetch
+                ports_info_depends_extract ports_info_depends_build
+                ports_info_depends_lib ports_info_depends_run
+                ports_info_conflicts
+                ports_info_platforms ports_info_license
+                ports_info_maintainers
+            }
+        }
+        foreach { option } $opts_todo {
+            set opt [string range $option 11 end]
+            # Artificial field name for formatting
+            if {$pretty_print && $opt eq "skip_line"} {
+                lappend fields ""
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq "heading"} {
+                set inf "$portinfo(name) @$portinfo(version)"
+                set ropt "heading"
+                if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                    append inf "_$portinfo(revision)"
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf " ([join $portinfo(categories) ", "])"
+                }
+            } elseif {$opt eq "fullname"} {
+                set inf "$portinfo(name) @"
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt "fullname"
+            } else {
+                # Map from friendly name
+                set ropt [map_friendly_field_names $opt]
+                
+                # If there's no such info, move on
+                if {![info exists portinfo($ropt)]} {
+                    set inf ""
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label ""
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label "$opt: "
+            }
+            
+            # Format the data
+            if { $ropt eq "maintainers" } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq "variants"} {
+                    # Use the new format for variants iff it exists in
+                    # PortInfo. This key currently does not exist outside of
+                    # trunk (1.8.0).
+                    array unset vinfo
+                    if {[info exists portinfo(vinfo)]} {
+                        array set vinfo $portinfo(vinfo)
+                    }
+
+                    set pi_vars $inf
+                    set inf {}
+                    foreach v [lsort $pi_vars] {
+                        set varmodifier ""
+                        if {[info exists variations($v)]} {
+                            # selected by command line, prefixed with +/-
+                            set varmodifier $variations($v)
+                        } elseif {[info exists global_variations($v)]} {
+                            # selected by variants.conf, prefixed with (+)/(-)
+                            set varmodifier "($global_variations($v))"
+                            # Retrieve additional information from the new key.
+                        } elseif {[info exists vinfo]} {
+                            array unset variant
+                            array set variant $vinfo($v)
+                            if {[info exists variant(is_default)]} {
+                                set varmodifier "\[$variant(is_default)]"
+                            }
+                        }
+                        lappend inf "$varmodifier$v"
+                    }
+                } elseif {[string match "depend*" $ropt] 
+                          && ![macports::ui_isset ports_verbose]} {
+                    set pi_deps $inf
+                    set inf {}
+                    foreach d $pi_deps {
+                        lappend inf [lindex [split $d :] end]
+                    }
+                }
+            } 
+            #End of special pretty-print formatting for certain fields
+            if {[info exists list_map($ropt)]} {
+                set field [join $inf $subfield_sep]
+            } else {
+                set field $inf
+            }
+            
+            # Assemble the entry
+            if {$pretty_print} {
+                # The two special fields are considered headings and are
+                # emitted immediately, rather than waiting. Also they are not
+                # recorded on the list of fields tried
+                if {$ropt eq "heading" || $ropt eq "fullname"} {
+                    puts "$label$field"
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq ""} {
+                    continue
+                }
+                if {$label eq ""} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat " " $wrap_len]]
+                } else {
+                    set wrap_len [string length $label]
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wraplabel $label $field 0 [string repeat " " $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields "$label$field"
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print && [llength $fields_tried]} {
+                puts -nonewline "$portinfo(name) has no "
+                puts [join $fields_tried ", "]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator "--\n"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_location { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        if { [catch {set ilist [registry_installed $portname [composite_version $portversion [array get variations]]]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port location failed: $result" 1 status
+        } else {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0]
+            set version [lindex $ilist 1]
+            set revision [lindex $ilist 2]
+            set variants [lindex $ilist 3]
+            set epoch [lindex $ilist 5]
+        }
+
+        set ref [registry::open_entry $portname $version $revision $variants $epoch]
+        set imagedir [registry::property_retrieve $ref location]
+        ui_notice "Port $portname ${version}_${revision}${variants} is installed as an image in:"
+        puts $imagedir
+    }
+    
+    return $status
+}
+
+
+proc action_notes { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set status 0
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue "The lookup of '$portname' failed: $result" \
+                                1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "The port '$portname' was not found" 1 status
+            }
+
+            # Retrieve the port's URL.
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        }
+        
+        # Add any global_variations to the variations
+        # specified for the port
+        array unset merged_variations
+        array set merged_variations [array get variations]
+        foreach { variation value } [array get global_variations] { 
+            if { ![info exists merged_variations($variation)] } { 
+                set merged_variations($variation) $value 
+            } 
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+
+        # Open the Portfile associated with this port.
+        if {[catch {set mport [mportopen $porturl [array get options] \
+                                         [array get merged_variations]]} \
+                   result]} {
+            ui_debug $::errorInfo
+            break_softcontinue [concat "The URL '$porturl' could not be" \
+                                       "opened: $result"] 1 status
+        }
+        array unset portinfo
+        array set portinfo [mportinfo $mport]
+        mportclose $mport
+
+        # Return the notes associated with this Portfile.
+        if {[info exists portinfo(notes)]} {
+            set portnotes $portinfo(notes)
+        } else {
+            set portnotes {}
+        }
+
+        # Retrieve the port's name once more to ensure it has the proper case.
+        set portname $portinfo(name)
+
+        # Display the notes.
+        if {$portnotes ne {}} {
+            ui_notice "$portname has the following notes:"
+            foreach note $portnotes {
+                puts [wrap $note 0 "  " 1]
+            }
+        } else {
+            puts "$portname has no notes."
+        }
+    }
+    return $status
+}
+
+
+proc action_provides { action portlist opts } {
+    # In this case, portname is going to be used for the filename... since
+    # that is the first argument we expect... perhaps there is a better way
+    # to do this?
+    if { ![llength $portlist] } {
+        ui_error "Please specify a filename to check which port provides that file."
+        return 1
+    }
+    foreach filename $portlist {
+        set file [file normalize $filename]
+        if {[file exists $file] || ![catch {file type $file}]} {
+            if {![file isdirectory $file] || [file type $file] eq "link"} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts "$file is provided by: $port"
+                } else {
+                    puts "$file is not provided by a MacPorts port."
+                }
+            } else {
+                puts "$file is a directory."
+            }
+        } else {
+            puts "$file does not exist."
+        }
+    }
+    registry::close_file_map
+    
+    return 0
+}
+
+
+proc action_activate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_activate_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[$regref installtype] eq "image" && [registry::run_target $regref activate [array get options]]} {
+                continue
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::activate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port activate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping activate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_deactivate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    set portlist [portlist_sortdependents $portlist]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_deactivate_no-exec)]
+            && ![catch {set ilist [registry::active $portname]}]} {
+
+            set i [lindex $ilist 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            if {$composite_version eq "" || $composite_version == "${iversion}_${irevision}${ivariants}"} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq "image" && [registry::run_target $regref deactivate [array get options]]} {
+                    continue
+                }
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::deactivate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port deactivate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping deactivate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug "action_select \[$portlist] \[$opts]..."
+
+    array set opts_array $opts
+    set commands [array names opts_array ports_select_*]
+    array unset opts_array
+
+    # Error out if no group is specified or command is not --summary.
+    if {[llength $portlist] < 1 && [string map {ports_select_ ""} [lindex $commands 0]] != "summary"} {
+        ui_error "port select \[--list|--set|--show|--summary] \<group> \[<version>]"
+        return 1
+    }
+
+    set group [lindex $portlist 0]
+    
+    # If no command (--set, --show, --list, --summary) is specified *but*
+    #  more than one argument is specified, default to the set command.
+    if {[llength $commands] < 1 && [llength $portlist] > 1} {
+        set command set
+        ui_debug [concat "Although no command was specified, more than " \
+                         "one argument was specified.  Defaulting to the " \
+                         "'set' command..."]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] < 1} {
+        set command list
+        ui_debug [concat "No command was specified. Defaulting to the " \
+                         "'list' command..."]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] > 1} {
+        ui_error [concat "Multiple commands were specified. Only one " \
+                         "command may be specified at a time."]
+        return 1
+    } else {
+        set command [string map {ports_select_ ""} [lindex $commands 0]]
+        ui_debug "The '$command' command was specified."
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'list' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn "Unable to get active selected version: $selected_version"
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error "The 'list' command failed: $versions"
+                return 1
+            }
+
+            ui_notice "Available versions for $group:"
+            foreach v $versions {
+                ui_notice -nonewline "\t"
+                if {$selected_version == $v} {
+                    ui_msg "$v (active)"
+                } else {
+                    ui_msg "$v"
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] < 2} {
+                ui_error [concat "The 'set' command expects two " \
+                                 "arguments: <group>, <version>"]
+                return 1
+            } elseif {[llength $portlist] > 2} {
+                ui_warn [concat "The 'set' command only expects two " \
+                                "arguments. Extra arguments will be " \
+                                "ignored."]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline "Selecting '$version' for '$group' "
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg "failed: $result"
+                return 1
+            }
+            ui_msg "succeeded. '$version' is now active."
+            return 0
+        }
+        show {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'show' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error "The 'show' command failed: $selected_version"
+                return 1
+            }
+            puts [concat "The currently selected version for '$group' is " \
+                         "'$selected_version'."]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] > 0} {
+                ui_warn [concat "The 'summary' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error "The 'summary' command failed: $portgroups"
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr "%-*s  %-*s  %s"
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn "The list of options for the select group $pg could not be obtained: $versions"
+                    continue
+                }
+                # remove "none", sort the list, append none at the end
+                set noneidx [lsearch -exact $versions "none"]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions "none"
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn "The currently selected option for the select group $pg could not be obtained: $selected_version"
+                    continue
+                }
+                set groupdesc(selected) $selected_version
+
+                set w1 [expr {max($w1, [string length $pg])}]
+                set w2 [expr {max($w2, [string length $selected_version])}]
+
+                lappend groups [array get groupdesc]
+                array unset groupdesc
+            }
+            puts [format $formatStr $w1 "Name" $w2 "Selected" "Options"]
+            puts [format $formatStr $w1 "====" $w2 "========" "======="]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) " "]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error "An unknown command '$command' was specified."
+            return 1
+        }
+    }
+}
+
+
+proc action_selfupdate { action portlist opts } {
+    global global_options
+    if { [catch {macports::selfupdate [array get global_options] base_updated} result ] } {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_error "$result"
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg "Please run `port -v selfupdate' for details."
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal "port selfupdate failed: $result"
+    }
+    
+    if {$base_updated} {
+        # exit immediately if in batch/interactive mode
+        return -999
+    } else {
+        return 0
+    }
+}
+
+
+proc action_setrequested { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    # set or unset?
+    set val [string equal $action "setrequested"]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info "Setting requested flag for $portname to $val"
+            foreach i $ilist {
+                set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+                registry::property_store $regref requested $val
+            }
+        } else {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist "yes"] || ([prefix_unwritable] && ![macports::global_option_isset ports_dryrun])} {
+        return 1
+    }
+
+    # shared depscache for all ports in the list
+    array set depscache {}
+    set status 0
+    foreachport $portlist {
+        if {![info exists depscache(port:$portname)]} {
+            set status [macports::upgrade $portname "port:$portname" [array get requested_variations] [array get options] depscache]
+            # status 2 means the port was not found in the index,
+            # status 3 means the port is not installed
+            if {$status != 0 && $status != 2 && $status != 3 && ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 && $status != 2 && $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] && ${macports::revupgrade_autorun} && ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::doctor_main $opts
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::reclaim_main  
+    return 0
+}
+
+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 } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Version: "
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Platform: "
+    }
+    puts "${macports::os_platform} ${macports::os_major} ${macports::os_arch}"
+    return 0
+}
+
+
+proc action_dependents { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set ilist {}
+
+    registry::open_dep_map
+
+    set status 0
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if { [catch {set ilist [registry::installed $portname $composite_version]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        } else {
+            # choose the active version if there is one
+            set index 0
+            foreach i $ilist {
+                if {[lindex $i 4]} {
+                    set found 1
+                    break
+                }
+                incr index
+            }
+            if {![info exists found]} {
+                set index 0
+            }
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist $index 0]
+            set iversion [lindex $ilist $index 1]
+            set irevision [lindex $ilist $index 2]
+            set ivariants [lindex $ilist $index 3]
+        }
+        
+        set deplist [registry::list_dependents $portname $iversion $irevision $ivariants]
+        if { [llength $deplist] > 0 } {
+            if {$action eq "rdependents"} {
+                set toplist $deplist
+                while 1 {
+                    set newlist {}
+                    foreach dep $deplist {
+                        set depname [lindex $dep 2]
+                        if {![info exists seen($depname)]} {
+                            set seen($depname) 1
+                            set rdeplist [registry::list_dependents $depname]
+                            foreach rdep $rdeplist {
+                                lappend newlist $rdep
+                            }
+                            set dependentsof($depname) $rdeplist
+                        }
+                    }
+                    if {[llength $newlist] > 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice "The following ports are dependent on ${portname}:"
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos >= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] <= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] && [string is true -strict $options(ports_rdependents_full)])} {
+                        puts "${spaces}${cur_portname}"
+                        set seen($cur_portname) 1
+                        incr cur_pos
+                        set pos_stack [lreplace $pos_stack end end $cur_pos]
+                        if {[info exists dependentsof($cur_portname)]} {
+                            lappend portstack $dependentsof($cur_portname)
+                            lappend pos_stack 0
+                        }
+                        continue
+                    }
+                    incr cur_pos
+                    set pos_stack [lreplace $pos_stack end end $cur_pos]
+                }
+            } else {
+                foreach dep $deplist {
+                    set depport [lindex $dep 2]
+                    if {[macports::ui_isset ports_quiet]} {
+                        ui_msg "$depport"
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg "$depport depends on $portname"
+                    } else {
+                        ui_msg "$depport depends on $portname (by [lindex $dep 1]:)"
+                    }
+                }
+            }
+        } else {
+            ui_notice "$portname has no dependents."
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator ""
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] && [string is true -strict $options(ports_${action}_no-build)]} {
+            set deptypes {depends_lib depends_run}
+        } else {
+            set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+        }
+
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+            # Add any global_variations to the variations
+            # specified for the port, so we get dependencies right
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn "port ${action} --index does not work with the 'current' pseudo-port"
+            continue
+        }
+        set portname $portinfo(name)
+
+        set deplist {}
+        set deps_output {}
+        set ndeps 0
+        array set labeldict {depends_fetch Fetch depends_extract Extract depends_build Build depends_lib Library depends_run Runtime}
+        # get list of direct deps
+        foreach type $deptypes {
+            if {[info exists portinfo($type)]} {
+                if {$action eq "rdeps" || [macports::ui_isset ports_verbose]} {
+                    foreach dep $portinfo($type) {
+                        lappend deplist $dep
+                    }
+                } else {
+                    foreach dep $portinfo($type) {
+                        lappend deplist [lindex [split $dep :] end]
+                    }
+                }
+                if {$action eq "deps"} {
+                    set label "$labeldict($type) Dependencies"
+                    lappend deps_output [wraplabel $label [join $deplist ", "] 0 [string repeat " " 22]]
+                    incr ndeps [llength $deplist]
+                    set deplist {}
+                }
+            }
+        }
+
+        set version $portinfo(version)
+        set revision $portinfo(revision)
+        if {[info exists portinfo(canonical_active_variants)]} {
+            set variants $portinfo(canonical_active_variants)
+        } else {
+            set variants {}
+        }
+
+        puts -nonewline $separator
+        if {$action eq "deps"} {
+            if {$ndeps == 0} {
+                ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+            } else {
+                ui_notice "Full Name: $portname @${version}_${revision}${variants}"
+                puts [join $deps_output "\n"]
+            }
+            set separator "--\n"
+            continue
+        }
+
+        set toplist $deplist
+        # gather all the deps
+        while 1 {
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        break_softcontinue "lookup of portname $depname failed: $result" 1 status
+                    }
+                    if {[llength $result] < 2} {
+                        break_softcontinue "Port $depname not found" 1 status
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                    set options(subport) $portinfo(name)
+                    
+                    # open the portfile if requested
+                    if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug "$::errorInfo"
+                            break_softcontinue "Unable to open port: $result" 1 status
+                        }
+                        array unset portinfo
+                        array set portinfo [mportinfo $mport]
+                        mportclose $mport
+                    }
+                    
+                    # get list of the dep's deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                lappend rdeplist $rdep
+                                lappend newlist $rdep
+                            }
+                        }
+                    }
+                    set depsof($depname) $rdeplist
+                }
+            }
+            if {[llength $newlist] > 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] > 0} {
+            ui_notice "The following ports are dependencies of $portname @${version}_${revision}${variants}:"
+        } else {
+            ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos >= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] <= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] && [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts "${spaces}${cur_port}"
+                } else {
+                    puts "${spaces}${cur_portname}"
+                }
+                set seen($cur_portname) 1
+                incr cur_pos
+                set pos_stack [lreplace $pos_stack end end $cur_pos]
+                if {[info exists depsof($cur_portname)]} {
+                    lappend portstack $depsof($cur_portname)
+                    lappend pos_stack 0
+                }
+                continue
+            }
+            incr cur_pos
+            set pos_stack [lreplace $pos_stack end end $cur_pos]
+        }
+        set separator "--\n"
+    }
+    return $status
+}
+
+
+proc action_uninstall { action portlist opts } {
+    set status 0
+    if {[macports::global_option_isset port_uninstall_old]} {
+        # if -u then uninstall all inactive ports
+        # (union these to any other ports user has in the port list)
+        set portlist [opUnion $portlist [get_inactive_ports]]
+    } else {
+        # Otherwise the user hopefully supplied a portlist, or we'll default to the existing directory
+        if {[require_portlist portlist]} {
+            return 1
+        }
+    }
+    if {[prefix_unwritable]} {
+        return 1
+    }
+
+    set portlist [portlist_sortdependents $portlist]
+
+    foreachport $portlist {
+        if {![registry::entry_exists_for_name $portname]} {
+            # if the code path arrives here the port either isn't installed, or
+            # it doesn't exist at all. We can't be sure, but we can check the
+            # portindex whether a port by that name exists (in which case not
+            # uninstalling it is probably no problem). If there is no port by
+            # that name, alert the user in case of typos.
+            ui_info "$portname is not installed"
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn "no such port: $portname, skipping uninstall"
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set iactive [lindex $i 4]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[registry::run_target $regref uninstall [array get options]]} {
+                continue
+            }
+        }
+
+        if { [catch {registry_uninstall::uninstall_composite $portname $composite_version [array get options]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port uninstall failed: $result" 1 status
+        }
+    }
+
+    return $status
+}
+
+
+proc action_installed { action portlist opts } {
+    global private_options
+    set status 0
+    set restrictedList 0
+    set ilist {}
+    
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreachport $portlist {
+            set composite_version [composite_version $portversion [array get variations]]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port installed failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] > 0 } {
+        ui_notice "The following ports are currently installed:"
+        foreach i [portlist_sortint $ilist] {
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            set extra ""
+            set nvariants ""
+            if {[macports::ui_isset ports_verbose]} {
+                set regref [registry::open_entry $iname $iversion $irevision $ivariants [lindex $i 5]]
+                set nvariants [registry::property_retrieve $regref negated_variants]
+                if {$nvariants == 0} {
+                    set nvariants ""
+                }
+                set os_platform [registry::property_retrieve $regref os_platform]
+                set os_major [registry::property_retrieve $regref os_major]
+                set archs [registry::property_retrieve $regref archs]
+                if {$os_platform != 0 && $os_platform ne "" && $os_major != 0 && $os_major ne ""} {
+                    append extra " platform='$os_platform $os_major'"
+                }
+                if {$archs != 0 && $archs ne ""} {
+                    append extra " archs='$archs'"
+                }
+            }
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}"
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are installed."
+    } else {
+        ui_notice "No ports are installed."
+    }
+
+    return $status
+}
+
+
+proc action_outdated { action portlist opts } {
+    global private_options
+    set status 0
+
+    # If port names were supplied, limit ourselves to those ports, else check all installed ports
+    set ilist {}
+    set restrictedList 0
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreach portspec $portlist {
+            array set port $portspec
+            set portname $port(name)
+            set composite_version [composite_version $port(version) $port(variants)]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port outdated failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] > 0 } {
+        foreach i [portlist_sortint $ilist] {
+        
+            # Get information about the installed port
+            set portname [lindex $i 0]
+            set installed_version [lindex $i 1]
+            set installed_revision [lindex $i 2]
+            set installed_compound "${installed_version}_${installed_revision}"
+
+            set is_active [lindex $i 4]
+            if {$is_active == 0} {
+                continue
+            }
+            set installed_epoch [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+            
+            # Get information about latest available version and revision
+            if {![info exists portinfo(version)]} {
+                ui_warn "$portname has no version field"
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound "${latest_version}_${latest_revision}"
+            set latest_epoch 0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch $portinfo(epoch)
+            }
+            
+            # Compare versions, first checking epoch, then version, then revision
+            set epoch_comp_result [expr {$installed_epoch - $latest_epoch}]
+            set comp_result [vercmp $installed_version $latest_version]
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            set reason ""
+            if {$epoch_comp_result != 0 && $installed_version != $latest_version} {
+                if {($comp_result >= 0 && $epoch_comp_result < 0) || ($comp_result <= 0 && $epoch_comp_result > 0)} {
+                    set reason { (epoch $installed_epoch $relation $latest_epoch)}
+                }
+                set comp_result $epoch_comp_result
+            } elseif {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision [lindex $i 3] $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                    set reason { (platform $os_platform_installed $os_major_installed != ${macports::os_platform} ${macports::os_major})}
+                }
+            }
+            
+            # Report outdated (or, for verbose, predated) versions
+            if { $comp_result != 0 } {
+                            
+                # Form a relation between the versions
+                set flag ""
+                if { $comp_result > 0 } {
+                    set relation ">"
+                    set flag "!"
+                } else {
+                    set relation "<"
+                }
+                
+                # Emit information
+                if {$comp_result < 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice "The following installed ports are outdated:"
+                    }
+                    incr num_outdated
+
+                    puts [format "%-30s %-24s %1s" $portname "$installed_compound $relation $latest_compound [subst $reason]" $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice "No installed ports are outdated."
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are outdated."
+    } else {
+        ui_notice "No ports are installed."
+    }
+    
+    return $status
+}
+
+
+proc action_contents { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {[info exists global_options(ports_contents_size)]} {
+        set units {}
+        if {[info exists global_options(ports_contents_units)]} {
+            set units [complete_size_units $global_options(ports_contents_units)]
+        }
+        set outstring {[format "%12s $file" [filesize $file $units]]}
+    } else {
+        set outstring {  $file}
+    }
+
+    foreachport $portlist {
+        if { ![catch {set ilist [registry::installed $portname]} result] } {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0 0]
+        }
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                ui_notice "Port $portname contains:"
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice "Port $portname does not contain any files or is not active."
+            }
+        } else {
+            ui_notice "Port $portname is not installed."
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq "K" || $units eq "Ki"} {
+        return "KiB"
+    } elseif {$units eq "k"} {
+        return "kB"
+    } elseif {$units eq "Mi"} {
+        return "MiB"
+    } elseif {$units eq "M"} {
+        return "MB"
+    } elseif {$units eq "Gi"} {
+        return "GiB"
+    } elseif {$units eq "G"} {
+        return "GB"
+    } else {
+        return $units
+    }
+}
+
+# Show space used by the given ports' files
+proc action_space {action portlist opts} {
+    global global_options
+    require_portlist portlist
+
+    set units {}
+    if {[info exists global_options(ports_space_units)]} {
+        set units [complete_size_units $global_options(ports_space_units)]
+    }
+    set spaceall 0.0
+    foreachport $portlist {
+        set space 0.0
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne "yes"} {
+                    set msg "[bytesize $space $units] $portname"
+                    if { $portversion != {} } {
+                        append msg " @$portversion"
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr "Port $portname does not contain any file or is not active."
+            }
+        } else {
+            puts stderr "Port $portname is not installed."
+        }
+    }
+    if {[llength $portlist] > 1 || ([info exists options(ports_space_total)] && $options(ports_space_total) eq "yes")} {
+        puts "[bytesize $spaceall $units] total"
+    }
+    return 0
+}
+
+proc action_variants { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] && $options(ports_variants_index) eq "yes")} {
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "port variants --index does not work with 'current' pseudo-port"
+            continue
+        }
+
+        # set portname again since the one we were passed may not have had the correct case
+        set portname $portinfo(name)
+
+        # if this fails the port doesn't have any variants
+        if {![info exists portinfo(variants)]} {
+            ui_notice "$portname has no variants"
+        } else {
+            array unset vinfo
+            # Use the new format if it exists.
+            if {[info exists portinfo(vinfo)]} {
+                array set vinfo $portinfo(vinfo)
+            # Otherwise fall back to the old format.
+            } elseif {[info exists portinfo(variant_desc)]} {
+                array set vdescriptions $portinfo(variant_desc)
+            }
+
+            # print out all the variants
+            ui_notice "$portname has the variants:"
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier "   "
+                # Retrieve variants' information from the new format.
+                if {[info exists vinfo]} {
+                    array unset variant
+                    array set variant $vinfo($v)
+
+                    # Retrieve conflicts, description, is_default, and
+                    # vrequires.
+                    if {[info exists variant(conflicts)]} {
+                        set vconflicts $variant(conflicts)
+                    }
+                    if {[info exists variant(description)]} {
+                        set vdescription $variant(description)
+                    }
+
+                    # XXX Keep these varmodifiers in sync with action_info, or create a wrapper for it
+                    if {[info exists variations($v)]} {
+                        set varmodifier "  $variations($v)"
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier "($global_variations($v))"
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier "\[$variant(is_default)\]"
+                    }
+                    if {[info exists variant(requires)]} {
+                        set vrequires $variant(requires)
+                    }
+                # Retrieve variants' information from the old format,
+                # which only consists of the description.
+                } elseif {[info exists vdescriptions($v)]} {
+                    set vdescription $vdescriptions($v)
+                }
+
+                if {[info exists vdescription]} {
+                    puts [wraplabel "$varmodifier$v" [string trim $vdescription] 0 [string repeat " " [expr 5 + [string length $v]]]]
+                } else {
+                    puts "$varmodifier$v"
+                }
+                if {[info exists vconflicts]} {
+                    puts "     * conflicts with [string trim $vconflicts]"
+                }
+                if {[info exists vrequires]} {
+                    puts "     * requires [string trim $vrequires]"
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        ui_error "You must specify a search pattern"
+        return 1
+    }
+
+    # Copy global options as we are going to modify the array
+    array set options [array get global_options]
+
+    if {[info exists options(ports_search_depends)] && $options(ports_search_depends) eq "yes"} {
+        array unset options ports_search_depends
+        set options(ports_search_depends_fetch) yes
+        set options(ports_search_depends_extract) yes
+        set options(ports_search_depends_build) yes
+        set options(ports_search_depends_lib) yes
+        set options(ports_search_depends_run) yes
+    }
+
+    # Array to hold given filters
+    array set filters {}
+    # Default matchstyle
+    set filter_matchstyle "none"
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne "yes" } {
+            continue
+        }
+        switch -- $opt {
+            exact -
+            glob {
+                set filter_matchstyle $opt
+                continue
+            }
+            regex {
+                set filter_matchstyle regexp
+                continue
+            }
+            case-sensitive {
+                set filter_case yes
+                continue
+            }
+            line {
+                continue
+            }
+        }
+
+        set filters($opt) "yes"
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) "yes"
+        set filters(description) "yes"
+    }
+
+    set separator ""
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq "none"} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first "*" $portname] == -1 && [string first "?" $portname] == -1} {
+                set searchstring "*$portname*"
+            }
+            set matchstyle glob
+        }
+
+        set res {}
+        set portfound 0
+        foreach { opt } [array get filters] {
+            # Map from friendly name
+            set opt [map_friendly_field_names $opt]
+
+            if {[catch {eval set matches \[mportsearch \$searchstring $filter_case \$matchstyle $opt\]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for name $portname failed: $result" 1 status
+            }
+
+            set tmp {}
+            foreach {name info} $matches {
+                add_to_portlist tmp [concat [list name $name] $info]
+            }
+            set res [opUnion $res $tmp]
+        }
+        set res [portlist_sort $res]
+
+        set joiner ""
+        foreach info $res {
+            array unset portinfo
+            array set portinfo $info
+
+            # XXX is this the right place to verify an entry?
+            if {![info exists portinfo(name)]} {
+                puts stderr "Invalid port entry, missing portname"
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing description"
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing version"
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        && $options(ports_search_line) eq "yes"} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts "$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)"
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts "$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)"
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline "$portinfo(name) @$portinfo(version)"
+                    if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                        puts -nonewline "_$portinfo(revision)"
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline " ([join $portinfo(categories) ", "])"
+                    }
+                    puts ""
+                    puts [wrap [join $portinfo(description)] 0 [string repeat " " 4]]
+                }
+            }
+
+            set joiner "\n"
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice "No match for $portname found"
+        } elseif {[llength $res] > 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne "yes")} {
+                ui_notice "\nFound [llength $res] ports."
+            }
+        }
+
+        set separator "--\n"
+    }
+
+    array unset options
+    array unset filters
+
+    return $status
+}
+
+
+proc action_list { action portlist opts } {
+    global private_options
+    set status 0
+    
+    # Default to list all ports if no portnames are supplied
+    if { ![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        add_to_portlist portlist [list name "-all-"]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq "-all-"} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "listing all ports failed: $result" 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $search_string failed: $result" 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir ""
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format "%-30s @%-14s %s" $portinfo(name) $portinfo(version) $outdir]
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_echo { action portlist opts } {
+    global global_options
+
+    # Simply echo back the port specs given to this command
+    foreachport $portlist {
+        if {![macports::ui_isset ports_quiet]} {
+            set opts {}
+            foreach { key value } [array get options] {
+                if {![info exists global_options($key)]} {
+                    lappend opts "$key=$value"
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne "" } {
+                set ver_field "@$composite_version"
+            } else {
+                set ver_field ""
+            }
+            puts [format "%-30s %s %s" $portname $ver_field  [join $opts " "]]
+        } else {
+            puts "$portname"
+        }
+    }
+
+    return 0
+}
+
+
+proc action_portcmds { action portlist opts } {
+    # Operations on the port's directory and Portfile
+    global env boot_env current_portdir
+
+    array set local_options $opts
+    
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific, otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+            set portname $portinfo(name)
+        }
+        
+        
+        # Calculate portdir, porturl, and portfile from initial porturl
+        set portdir [file normalize [macports::getportdir $porturl]]
+        set porturl "file://${portdir}";    # Rebuild url so it's fully qualified
+        set portfile "${portdir}/Portfile"
+        
+        # Now execute the specific action
+        if {[file readable $portfile]} {
+            switch -- $action {
+                cat {
+                    # Copy the portfile to standard output
+                    set f [open $portfile RDONLY]
+                    while { ![eof $f] } {
+                        puts -nonewline [read $f 4096]
+                    }
+                    close $f
+                }
+                
+                edit {
+                    # Edit the port's portfile with the user's editor
+                    
+                    # Restore our entire environment from start time.
+                    # We need it to evaluate the editor, and the editor
+                    # may want stuff from it as well, like TERM.
+                    array unset env_save; array set env_save [array get env]
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor ""
+                    set editor_var "ports_${action}_editor"
+                    if {[info exists local_options($editor_var)]} {
+                        set editor [join $local_options($editor_var)]
+                    } else {
+                        foreach ed { MP_EDITOR VISUAL EDITOR } {
+                            if {[info exists env($ed)]} {
+                                set editor $env($ed)
+                                break
+                            }
+                        }
+                    }
+                    
+                    # Use a reasonable canned default if no editor specified or set in env
+                    if { $editor eq "" } { set editor "/usr/bin/vi" }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec >@stdout <@stdin 2>@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug "$errorInfo"
+                        break_softcontinue "unable to invoke editor $editor: $result" 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get env_save]
+                }
+
+                dir {
+                    # output the path to the port's directory
+                    puts $portdir
+                }
+
+                work {
+                    # output the path to the port's work directory
+                    set workpath [macports::getportworkpath_from_portdir $portdir $portname]
+                    if {[file exists $workpath]} {
+                        puts $workpath
+                    }
+                }
+
+                cd {
+                    # Change to the port's directory, making it the default
+                    # port for any future commands
+                    set current_portdir $portdir
+                }
+
+                url {
+                    # output the url of the port's directory, suitable to feed back in later as a port descriptor
+                    puts $porturl
+                }
+
+                file {
+                    # output the path to the port's portfile
+                    puts $portfile
+                }
+
+                logfile {
+                    set logfile [file join [macports::getportlogpath $portdir $portname] "main.log"]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error "Log file not found for port in $portdir"
+                    }
+                }
+
+                gohome {
+                    set homepage ""
+
+                    # Get the homepage as read from PortIndex
+                    if {[info exists portinfo(homepage)]} {
+                        set homepage $portinfo(homepage)
+                    }
+
+                    # If not available, get the homepage for the port by opening the Portfile
+                    if {$homepage eq "" && ![catch {set ctx [mportopen $porturl]} result]} {
+                        array set portinfo [mportinfo $ctx]
+                        if {[info exists portinfo(homepage)]} {
+                            set homepage $portinfo(homepage)
+                        }
+                        mportclose $ctx
+                    }
+
+                    # Try to open a browser to the homepage for the given port
+                    if { $homepage ne "" } {
+                        if {[catch {system "${macports::autoconf::open_path} '$homepage'"} result]} {
+                            global errorInfo
+                            ui_debug "$errorInfo"
+                            break_softcontinue "unable to invoke browser using ${macports::autoconf::open_path}: $result" 1 status
+                        }
+                    } else {
+                        ui_error [format "No homepage for %s" $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue "Could not read $portfile" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_sync { action portlist opts } {
+    global global_options
+
+    set status 0
+    if {[catch {mportsync [array get global_options]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_msg "port sync failed: $result"
+        set status 1
+    }
+    
+    return $status
+}
+
+
+proc action_target { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {($action eq "install" || $action eq "archive") && [prefix_unwritable] && ![macports::global_option_isset ports_dryrun]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn "Skipping $portname (not in the ports tree)"
+                    continue
+                } else {
+                    break_softcontinue "Port $portname not found" 1 status
+                }
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+        }
+
+        # use existing variants iff none were explicitly requested
+        if {[array get requested_variations] eq "" && [array get variations] ne ""} {
+            array unset requested_variations
+            array set requested_variations [array get variations]
+        }
+
+        # Add any global_variations to the variations
+        # specified for the port
+        foreach { variation value } [array get global_variations] {
+            if { ![info exists requested_variations($variation)] } {
+                set requested_variations($variation) $value
+            }
+        }
+
+        # If version was specified, save it as a version glob for use
+        # in port actions (e.g. clean).
+        if {[string length $portversion]} {
+            set options(ports_version_glob) $portversion
+        }
+        # if installing, mark the port as explicitly requested
+        if {$action eq "install"} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq "archive"} {
+            set target install
+        } else {
+            set target $action
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+        if {[catch {set workername [mportopen $porturl [array get options] [array get requested_variations]]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to open port: $result" 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to execute port: $result" 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue "Processing of port $portname failed" 1 status
+        }
+    }
+    
+    if {$status == 0 && $action eq "install" && ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] && ![info exists options(ports_install_no-rev-upgrade)] && ${macports::revupgrade_autorun}} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+
+proc action_exit { action portlist opts } {
+    # Return a semaphore telling the main loop to quit
+    return -999
+}
+
+
+##########################################
+# Command Parsing
+##########################################
+proc moreargs {} {
+    global cmd_argn cmd_argc
+    return [expr {$cmd_argn < $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn < $cmd_argc} {
+        return [lindex $cmd_argv $cmd_argn]
+    } else {
+        return _EOF_
+    }
+}
+
+
+proc advance {} {
+    global cmd_argn
+    incr cmd_argn
+}
+
+
+proc match s {
+    if {[lookahead] == $s} {
+        advance
+        return 1
+    }
+    return 0
+}
+
+# action_array specifies which action to run on the given command
+# and if the action wants an expanded portlist.
+# The value is a list of the form {action expand},
+# where action is a string and expand a value:
+#   0 none        Does not expect any text argument
+#   1 strings     Expects some strings as text argument
+#   2 ports       Wants an expanded list of ports as text argument
+global action_array
+
+# Define global constants
+const ACTION_ARGS_NONE 0
+const ACTION_ARGS_STRINGS 1
+const ACTION_ARGS_PORTS 2
+
+array set action_array [list \
+    usage       [list action_usage          [ACTION_ARGS_STRINGS]] \
+    help        [list action_help           [ACTION_ARGS_STRINGS]] \
+    \
+    echo        [list action_echo           [ACTION_ARGS_PORTS]] \
+    \
+    info        [list action_info           [ACTION_ARGS_PORTS]] \
+    location    [list action_location       [ACTION_ARGS_PORTS]] \
+    notes       [list action_notes          [ACTION_ARGS_PORTS]] \
+    provides    [list action_provides       [ACTION_ARGS_STRINGS]] \
+    log         [list action_log            [ACTION_ARGS_PORTS]] \
+    \
+    activate    [list action_activate       [ACTION_ARGS_PORTS]] \
+    deactivate  [list action_deactivate     [ACTION_ARGS_PORTS]] \
+    \
+    select      [list action_select         [ACTION_ARGS_STRINGS]] \
+    \
+    sync        [list action_sync           [ACTION_ARGS_NONE]] \
+    selfupdate  [list action_selfupdate     [ACTION_ARGS_NONE]] \
+    \
+    setrequested   [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    unsetrequested [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    \
+    upgrade     [list action_upgrade        [ACTION_ARGS_PORTS]] \
+    rev-upgrade [list action_revupgrade     [ACTION_ARGS_NONE]] \
+    reclaim     [list action_reclaim        [ACTION_ARGS_NONE]] \
+    doctor      [list action_doctor         [ACTION_ARGS_NONE]] \
+    \
+    version     [list action_version        [ACTION_ARGS_NONE]] \
+    platform    [list action_platform       [ACTION_ARGS_NONE]] \
+    \
+    uninstall   [list action_uninstall      [ACTION_ARGS_PORTS]] \
+    \
+    installed   [list action_installed      [ACTION_ARGS_PORTS]] \
+    outdated    [list action_outdated       [ACTION_ARGS_PORTS]] \
+    contents    [list action_contents       [ACTION_ARGS_PORTS]] \
+    space       [list action_space          [ACTION_ARGS_PORTS]] \
+    dependents  [list action_dependents     [ACTION_ARGS_PORTS]] \
+    rdependents [list action_dependents     [ACTION_ARGS_PORTS]] \
+    deps        [list action_deps           [ACTION_ARGS_PORTS]] \
+    rdeps       [list action_deps           [ACTION_ARGS_PORTS]] \
+    variants    [list action_variants       [ACTION_ARGS_PORTS]] \
+    \
+    search      [list action_search         [ACTION_ARGS_STRINGS]] \
+    list        [list action_list           [ACTION_ARGS_PORTS]] \
+    \
+    edit        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cat         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    dir         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    work        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cd          [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    url         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    file        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    logfile     [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    gohome      [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    \
+    fetch       [list action_target         [ACTION_ARGS_PORTS]] \
+    checksum    [list action_target         [ACTION_ARGS_PORTS]] \
+    extract     [list action_target         [ACTION_ARGS_PORTS]] \
+    patch       [list action_target         [ACTION_ARGS_PORTS]] \
+    configure   [list action_target         [ACTION_ARGS_PORTS]] \
+    build       [list action_target         [ACTION_ARGS_PORTS]] \
+    destroot    [list action_target         [ACTION_ARGS_PORTS]] \
+    install     [list action_target         [ACTION_ARGS_PORTS]] \
+    clean       [list action_target         [ACTION_ARGS_PORTS]] \
+    test        [list action_target         [ACTION_ARGS_PORTS]] \
+    lint        [list action_target         [ACTION_ARGS_PORTS]] \
+    livecheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    distcheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    mirror      [list action_target         [ACTION_ARGS_PORTS]] \
+    load        [list action_target         [ACTION_ARGS_PORTS]] \
+    unload      [list action_target         [ACTION_ARGS_PORTS]] \
+    distfiles   [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    archivefetch [list action_target         [ACTION_ARGS_PORTS]] \
+    archive     [list action_target         [ACTION_ARGS_PORTS]] \
+    unarchive   [list action_target         [ACTION_ARGS_PORTS]] \
+    dmg         [list action_target         [ACTION_ARGS_PORTS]] \
+    mdmg        [list action_target         [ACTION_ARGS_PORTS]] \
+    dpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    mpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    pkg         [list action_target         [ACTION_ARGS_PORTS]] \
+    portpkg     [list action_target         [ACTION_ARGS_PORTS]] \
+    rpm         [list action_target         [ACTION_ARGS_PORTS]] \
+    srpm        [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    quit        [list action_exit           [ACTION_ARGS_NONE]] \
+    exit        [list action_exit           [ACTION_ARGS_NONE]] \
+]
+
+# Expand "action".
+# Returns an action proc, or a list of matching action procs, or the action passed in
+proc find_action { action } {
+    global action_array
+    
+    if { ! [info exists action_array($action)] } {
+        set guess [guess_action $action]
+        if { [info exists action_array($guess)] } {
+            return $guess
+        }
+        return $guess
+    }
+    
+    return $action
+}
+
+# Expand action
+# If there's more than one match, return the next possibility
+proc find_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    } else {
+        set action [complete_action $action]
+        if { [info exists action_array($action)] } {
+            set action_proc [lindex $action_array($action) 0]
+        }
+    }
+    
+    return $action_proc
+}
+
+proc get_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    }
+    
+    return $action_proc
+}
+
+# Returns whether an action expects text arguments at all,
+# expects text arguments or wants an expanded list of ports
+# Return values are constants:
+#   [ACTION_ARGS_NONE]     Does not expect any text argument
+#   [ACTION_ARGS_STRINGS]  Expects some strings as text argument
+#   [ACTION_ARGS_PORTS]    Wants an expanded list of ports as text argument
+proc action_needs_portlist { action } {
+    global action_array
+
+    set ret 0
+    if {[info exists action_array($action)]} {
+        set ret [lindex $action_array($action) 1]
+    }
+
+    return $ret
+}
+
+# cmd_opts_array specifies which arguments the commands accept
+# Commands not listed here do not accept any arguments
+# Syntax if {option argn}
+# Where option is the name of the option and argn specifies how many arguments
+# this argument takes
+global cmd_opts_array
+array set cmd_opts_array {
+    edit        {{editor 1}}
+    info        {category categories depends_fetch depends_extract
+                 depends_build depends_lib depends_run
+                 depends description epoch fullname heading homepage index license
+                 line long_description
+                 maintainer maintainers name platform platforms portdir pretty
+                 replaced_by revision subports variant variants version}
+    contents    {size {units 1}}
+    deps        {index no-build}
+    rdeps       {index no-build full}
+    rdependents {full}
+    search      {case-sensitive category categories depends_fetch
+                 depends_extract depends_build depends_lib depends_run
+                 depends description epoch exact glob homepage line
+                 long_description maintainer maintainers name platform
+                 platforms portdir regex revision variant variants version}
+    selfupdate  {nosync}
+    space       {{units 1} total}
+    activate    {no-exec}
+    deactivate  {no-exec}
+    install     {no-rev-upgrade unrequested}
+    uninstall   {follow-dependents follow-dependencies no-exec}
+    variants    {index}
+    clean       {all archive dist work logs}
+    mirror      {new}
+    lint        {nitpick}
+    select      {list set show summary}
+    log         {{phase 1} {level 1}}
+    upgrade     {force enforce-variants no-replace no-rev-upgrade}
+    rev-upgrade {id-loadcmd-check}
+    doctor      {quiet}
+}
+
+##
+# Checks whether the given option is valid
+#
+# @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} {
+    global cmd_opts_array
+
+    # This could be so easy with lsearch -index,
+    # but that's only available as of Tcl 8.5
+
+    if {![info exists cmd_opts_array($action)]} {
+        return {}
+    }
+
+    set result {}
+
+    foreach item $cmd_opts_array($action) {
+        if {[llength $item] == 1} {
+            set name $item
+            set argc 0
+        } else {
+            set name [lindex $item 0]
+            set argc [lindex $item 1]
+        }
+
+        if {$name == $option} {
+            set result [list [list $name $argc]]
+            break
+        } elseif {[string first $option $name] == 0} {
+            lappend result [list $name $argc]
+        }
+    }
+
+    return $result
+}
+
+# Parse global options
+#
+# Note that this is called several times:
+#   (1) Initially, to parse options that will be constant across all commands
+#       (options that come prior to any command, frozen into global_options_base)
+#   (2) Following each command (to parse options that will be unique to that command
+#       (the global_options array is reset to global_options_base prior to each command)
+#
+proc parse_options { action ui_options_name global_options_name } {
+    upvar $ui_options_name ui_options
+    upvar $global_options_name global_options
+    global cmdname cmd_opts_array
+    
+    while {[moreargs]} {
+        set arg [lookahead]
+        
+        if {[string index $arg 0] ne "-"} {
+            break
+        } elseif {[string index $arg 1] eq "-"} {
+            # Process long arguments
+            switch -- $arg {
+                -- { # This is the options terminator; do no further option processing
+                    advance; break
+                }
+                default {
+                    set key [string range $arg 2 end]
+                    set kopts [cmd_option_matches $action $key]
+                    if {[llength $kopts] == 0} {
+                        return -code error "${action} does not accept --${key}"
+                    } elseif {[llength $kopts] > 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst "--[lindex $e 0]"
+                        }
+                        return -code error "\"port ${action} --${key}\" is ambiguous: \n  port ${action} [join $errlst "\n  port ${action} "]"
+                    }
+                    set key   [lindex $kopts 0 0]
+                    set kargc [lindex $kopts 0 1]
+                    if {$kargc == 0} {
+                        set global_options(ports_${action}_${key}) yes
+                    } else {
+                        set args {}
+                        while {[moreargs] && $kargc > 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc > 0} {
+                            return -code error "--${key} expects [expr {$kargc + [llength $args]}] parameters!"
+                        }
+                        set global_options(ports_${action}_${key}) $args
+                    }
+                }
+            }
+        } else {
+            # Process short arg(s)
+            set opts [string range $arg 1 end]
+            foreach c [split $opts {}] {
+                switch -- $c {
+                    v {
+                        set ui_options(ports_verbose) yes
+                    }
+                    d {
+                        set ui_options(ports_debug) yes
+                        # debug implies verbose
+                        set ui_options(ports_verbose) yes
+                    }
+                    q {
+                        set ui_options(ports_quiet) yes
+                    }
+                    p {
+                        # Ignore errors while processing within a command
+                        set ui_options(ports_processall) yes
+                    }
+                    f {
+                        set global_options(ports_force) yes
+                    }
+                    o {
+                        set global_options(ports_ignore_different) yes
+                    }
+                    n {
+                        set global_options(ports_nodeps) yes
+                    }
+                    u {
+                        set global_options(port_uninstall_old) yes
+                    }
+                    R {
+                        set global_options(ports_do_dependents) yes
+                    }
+                    s {
+                        set global_options(ports_source_only) yes
+                    }
+                    b {
+                        set global_options(ports_binary_only) yes
+                    }
+                    c {
+                        set global_options(ports_autoclean) yes
+                    }
+                    k {
+                        set global_options(ports_autoclean) no
+                    }
+                    t {
+                        set global_options(ports_trace) yes
+                    }
+                    y {
+                        set global_options(ports_dryrun) yes
+                    }
+                    F {
+                        # Name a command file to process
+                        advance
+                        if {[moreargs]} {
+                            lappend ui_options(ports_commandfiles) [lookahead]
+                        }
+                    }
+                    D {
+                        advance
+                        if {[moreargs]} {
+                            cd [lookahead]
+                        }
+                        break
+                    }
+                    default {
+                        print_usage; exit 1
+                    }
+                }
+            }
+        }
+
+        advance
+    }
+}
+
+# acquire exclusive registry lock for actions that need it
+# returns 1 if locked, 0 otherwise
+proc lock_reg_if_needed {action} {
+    switch -- $action {
+        activate -
+        deactivate -
+        setrequested -
+        unsetrequested -
+        upgrade -
+        uninstall -
+        install {
+            registry::exclusive_lock
+            return 1
+        }
+    }
+    return 0
+}
+
+proc process_cmd { argv } {
+    global cmd_argc cmd_argv cmd_argn \
+           global_options global_options_base private_options ui_options \
+           current_portdir
+    set cmd_argv $argv
+    set cmd_argc [llength $argv]
+    set cmd_argn 0
+
+    set action_status 0
+
+    # Process an action if there is one
+    while {($action_status == 0 || [macports::ui_isset ports_processall]) && [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == ";" } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == "#" } {
+            while { [moreargs] } { advance }
+            break
+        }
+
+        set locked [lock_reg_if_needed $action]
+        # Always start out processing an action in current_portdir
+        cd $current_portdir
+        
+        # Reset global_options from base before each action, as we munge it just below...
+        array unset global_options
+        array set global_options $global_options_base
+        
+        # Find an action to execute
+        set actions [find_action $action]
+        if {[llength $actions] == 1} {
+            set action [lindex $actions 0]
+            set action_proc [get_action_proc $action]
+        } else {
+            if {[llength $actions] > 1} {
+                ui_error "\"port ${action}\" is ambiguous: \n  port [join $actions "\n  port "]"
+            } else {
+                ui_error "Unrecognized action \"port $action\""
+            }
+            set action_status 1
+            break
+        }
+
+        # Parse options that will be unique to this action
+        # (to avoid abiguity with -variants and a default port, either -- must be
+        # used to terminate option processing, or the pseudo-port current must be specified).
+        if {[catch {parse_options $action ui_options global_options} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            ui_error $result
+            set action_status 1
+            break
+        }
+
+        # What kind of arguments does the command expect?
+        set expand [action_needs_portlist $action]
+
+        # Parse action arguments, setting a special flag if there were none
+        # We otherwise can't tell the difference between arguments that evaluate
+        # to the empty set, and the empty set itself.
+        set portlist {}
+        switch -- [lookahead] {
+            ;       -
+            _EOF_ {
+                set private_options(ports_no_args) yes
+            }
+            default {
+                if {[ACTION_ARGS_NONE] == $expand} {
+                    ui_error "$action does not accept string arguments"
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] && ![match ";"] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error "Improper expression syntax while processing parameters"
+                        set action_status 1
+                        break
+                    }
+                }
+            }
+        }
+        
+        # execute the action
+        set action_status [$action_proc $action $portlist [array get global_options]]
+
+        # unlock if needed
+        if {$locked} {
+            registry::exclusive_unlock
+        }
+
+        # Print notifications of just-activated ports.
+        portclient::notifications::display
+
+        # semaphore to exit
+        if {$action_status == -999} break
+    }
+    
+    return $action_status
+}
+
+
+proc complete_portname { text state } { 
+    global complete_choices complete_position
+    
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices {}
+
+        # Build a list of ports with text as their prefix
+        if {[catch {set res [mportsearch "${text}*" false glob]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "search for portname $pattern failed: $result"
+        }
+        foreach {name info} $res {
+            lappend complete_choices $name
+        }
+    }
+    
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+    
+    return $word
+}
+
+
+# return text action beginning with $text
+proc complete_action { text state } {   
+    global action_array complete_choices complete_position
+
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices [array names action_array "[string tolower $text]*"]
+    }
+
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+
+    return $word
+}
+
+# return all actions beginning with $text
+proc guess_action { text } {   
+    global action_array
+
+    return [array names action_array "[string tolower $text]*"]
+
+    if { [llength $complete_choices ] == 1 } {
+        return [lindex $complete_choices 0]
+    }
+
+    return {}
+}
+
+proc attempt_completion { text word start end } {
+    # If the word starts with '~', or contains '.' or '/', then use the build-in
+    # completion to complete the word
+    if { [regexp {^~|[/.]} $word] } {
+        return ""
+    }
+
+    # Decide how to do completion based on where we are in the string
+    set prefix [string range $text 0 [expr {$start - 1}]]
+    
+    # If only whitespace characters preceed us, or if the
+    # previous non-whitespace character was a ;, then we're
+    # an action (the first word of a command)
+    if { [regexp {(^\s*$)|(;\s*$)} $prefix] } {
+        return complete_action
+    }
+    
+    # Otherwise, do completion on portname
+    return complete_portname
+}
+
+
+proc get_next_cmdline { in out use_readline prompt linename } {
+    upvar $linename line
+    
+    set line ""
+    while { $line eq "" } {
+
+        if {$use_readline} {
+            set len [readline read -attempted_completion attempt_completion line $prompt]
+        } else {
+            puts -nonewline $out $prompt
+            flush $out
+            set len [gets $in line]
+        }
+
+        if { $len < 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline && $line ne "" } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in "stdin"]
+    set name "port"
+    set use_readline [expr {$isstdin && [readline init $name]}]
+    set history_file [file normalize "${macports::macports_user_dir}/history"]
+
+    # Read readline history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin && ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts "MacPorts [macports::version]"
+        puts "Entering interactive mode... (\"help\" for help, \"quit\" to quit)"
+    }
+
+    # Main command loop
+    set exit_status 0
+    while { $exit_status == 0 || $isstdin || [macports::ui_isset ports_processall] } {
+
+        # Calculate our prompt
+        if { $noisy } {
+            set shortdir [eval file join [lrange [file split $current_portdir] end-1 end]]
+            set prompt "\[$shortdir\] > "
+        } else {
+            set prompt ""
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] <= 0  } {
+            puts ""
+            break
+        }
+
+        # Process the command
+        set exit_status [process_cmd $line]
+        
+        # Check for semaphore to exit
+        if {$exit_status == -999} {
+            set exit_status 0
+            break
+        }
+    }
+
+    # Create macports user directory if it does not exist yet
+    if {$use_readline && ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts "Goodbye"
+    }
+
+    return $exit_status
+}
+
+
+proc process_command_files { filelist } {
+    set exit_status 0
+
+    # For each file in the command list, process commands
+    # in the file
+    foreach file $filelist {
+        if {$file eq "-"} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal "Failed to open command file; $result"
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne "stdin"} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 && ![macports::ui_isset ports_processall]} {
+            return $exit_status
+        }
+    }
+
+    return $exit_status
+}
+
+namespace eval portclient::progress {
+    ##
+    # Maximum width of the progress bar or indicator when displaying it.
+    variable maxWidth 50
+
+    ##
+    # The start time of the last progress callback as returned by [clock time].
+    # Since only one progress indicator is active at a time, this variable is
+    # shared between the different variants of progress functions.
+    variable startTime
+
+    ##
+    # Delay in milliseconds after the start of the operation before deciding
+    # that showing a progress bar makes sense.
+    variable showTimeThreshold 500
+
+    ##
+    # Percentage value between 0 and 1 that must not have been reached yet when
+    # $showTimeThreshold has passed for a progress bar to be shown. If the
+    # operation has proceeded above e.g. 75% after 500ms we won't bother
+    # displaying a progress indicator anymore -- the operation will be finished
+    # in well below a second anyway.
+    variable showPercentageThreshold 0.75
+
+    ##
+    # Boolean indication whether the progress indicator should be shown or is
+    # still hidden because the current operation didn't need enough time for
+    # a progress indicator to make sense, yet.
+    variable show no
+
+    ##
+    # Initialize the progress bar display delay; call this from the start
+    # action of the progress functions.
+    proc initDelay {} {
+        variable show
+        variable startTime
+
+        set startTime [clock milliseconds]
+        set show no
+    }
+
+    ##
+    # Determine whether a progress bar should be shown for the current
+    # operation in its current state. You must have called initDelay for the
+    # current operation before calling this method.
+    #
+    # @param cur
+    #        Current progress in abstract units.
+    # @param total
+    #        Total number of abstract units to be processed, if known. Pass
+    #        0 if unknown.
+    # @return
+    #        "yes", if the progress indicator should be shown, "no" otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq "yes"} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] > $showTimeThreshold &&
+                ($total == 0 || [expr {double($cur) / double($total)}] < $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of "start", "update", "intermission" or "finish", where start
+    #        will be called before any number of update calls, interrupted by
+    #        any number of intermission calls (called because other output is
+    #        being produced), followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        "intermission" and "finish", the args are empty and unused. For
+    #        "update", args contains $cur and $total, where $cur is the current
+    #        number of units processed and $total is the total number of units
+    #        to be processed. If the total is not known, it is 0.
+    proc generic {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {now total} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            progressbar $now $total [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        } else {
+                            unprogressbar [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        }
+                    }
+                }
+            }
+            intermission -
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of "start", "update" or "finish", where start will be called
+    #        before any number of update calls, followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        contains a single argument "ul" or "dl" indicating whether this is
+    #        an up- or download. For "update", contains the arguments
+    #        ("ul"|"dl") $total $now $speed where ul/dl are as for start, and
+    #        total, now and speed are doubles indicating the total transfer
+    #        size, currently transferred amount and average speed per second in
+    #        bytes. Unused for "finish".
+    proc download {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {type total now speed} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format "        speed: %-13s" "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format " %-10s     speed: %-13s" [bytesize $now {} "%6.1f"] "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            unprogressbar $barLen $barPrefix $barSuffix
+                        }
+                    }
+                }
+            }
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Draw a progress bar using unicode block drawing characters
+    #
+    # @param current
+    #        The current progress value.
+    # @param total
+    #        The progress value representing 100%.
+    # @param width
+    #        The width in characters of the progress bar. This includes percentage
+    #        output, which takes up 8 characters.
+    # @param prefix
+    #        Prefix to be printed in front of the progress bar.
+    # @param suffix
+    #        Suffix to be printed after the progress bar.
+    proc progressbar {current total width {prefix ""} {suffix ""}} {
+        # Subtract the width of the percentage output, also subtract the two
+        # characters [ and ] bounding the progress bar.
+        set percentageWidth 8
+        set barWidth      [expr {entier($width) - $percentageWidth - 2}]
+
+        # Map the range (0, $total) to (0, 4 * $width) where $width is the maximum
+        # numebr of characters to be printed for the progress bar. Multiply the
+        # upper bound with 8 because we have 8 sub-states per character.
+        set barProgress   [expr {entier(round(($current * $barWidth * 8) / $total))}]
+
+        set barInteger    [expr {$barProgress / 8}]
+        #set barRemainder  [expr {$barProgress % 8}]
+
+        # Finally, also provide a percentage value to print behind the progress bar
+        set percentage [expr {double($current) * 100 / double($total)}]
+
+        # clear the current line, enable reverse video
+        set progressbar "\033\[7m"
+        for {set i 0} {$i < $barInteger} {incr i} {
+            # U+2588 FULL BLOCK doesn't match the other blocks in some fonts :/
+            # Two half blocks work better in some fonts, but not in others (because
+            # they leave ugly spaces). So, one or the other choice isn't better or
+            # worse and even just using full blocks looks ugly in a few fonts.
+
+            # Use pure ASCII until somebody fixes most of the default terminal fonts :/
+            append progressbar " "
+        }
+        # back to normal output
+        append progressbar "\033\[0m"
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger < $barWidth} {
+        #            append progressbar " "
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar "\u258f"
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar "\u258e"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar "\u258c"
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar "\u258b"
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar "\u258a"
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar "\u2589"
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i < $barWidth} {incr i} {
+            append progressbar " "
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format " %[expr {$percentageWidth - 3}].1f %%" $percentage]
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}"
+        flush stdout
+    }
+
+
+    ##
+    # Internal state of the progress indicator; unless you're hacking the
+    # unprogressbar code you should never touch this.
+    variable unprogressState 0
+
+    ##
+    # Draw a progress indicator
+    #
+    # @param width
+    #        The width in characters of the progress indicator.
+    # @param prefix
+    #        Prefix to be printed in front of the progress indicator.
+    # @param suffix
+    #        Suffix to be printed after the progress indicator.
+    proc unprogressbar {width {prefix ""} {suffix ""}} {
+        variable unprogressState
+
+        # Subtract the two characters [ and ] bounding the progress indicator
+        # from the width.
+        set barWidth [expr {int($width) - 2}]
+
+        # Number of states of the progress bar, or rather: the number of
+        # characters before the sequence repeats.
+        set numStates 4
+
+        set unprogressState [expr {($unprogressState + 1) % $numStates}]
+
+        set progressbar ""
+        for {set i 0} {$i < $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar "\u2022"
+            } else {
+                append progressbar " "
+            }
+        }
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${suffix}"
+        flush stdout
+    }
+}
+
+namespace eval portclient::notifications {
+    ##
+    # Ports whose notifications to display; these were either installed
+    # or requested to be installed.
+    variable notificationsToPrint
+    array set notificationsToPrint {}
+
+    ##
+    # Add a port to the list for printing notifications.
+    #
+    # @param name
+    #        The name of the port.
+    # @param note
+    #        A list of notes to be stored for the given port.
+    proc append {name notes} {
+        variable notificationsToPrint
+
+        set notificationsToPrint($name) $notes
+    }
+
+    ##
+    # Print port notifications.
+    #
+    proc display {} {
+        global env
+        variable notificationsToPrint
+
+        # Display notes at the end of the activation phase.
+        if {[array size notificationsToPrint] > 0} {
+            ui_notice "--->  Some of the ports you installed have notes:"
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice "  $name has the following notes:"
+
+                # If env(COLUMNS) exists, limit each line's width to this width.
+                if {[info exists env(COLUMNS)]} {
+                    set maxlen $env(COLUMNS)
+
+                    foreach note $notes {
+                        foreach line [split $note "\n"] {
+                            set joiner ""
+                            set lines ""
+                            set newline "    "
+
+                            foreach word [split $line " "] {
+                                if {[string length $newline] + [string length $word] >= $maxlen} {
+                                    lappend lines $newline
+                                    set newline "    "
+                                    set joiner ""
+                                }
+                                ::append newline $joiner $word
+                                set joiner " "
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines "\n"]
+                        }
+                    }
+                } else {
+                    foreach note $notes {
+                        ui_notice $note
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+##########################################
+# Main
+##########################################
+
+# Global arrays passed to the macports1.0 layer
+array set ui_options        {}
+array set global_options    {}
+array set global_variations {}
+
+# Global options private to this script
+array set private_options {}
+
+# Make sure we get the size of the terminal
+# We do this here to save it in the boot_env, in case we determined it manually
+term_init_size
+
+global env boot_env argv0 cmdname argc argv cmd_argc cmd_argv cmd_argn \
+       current_portdir global_options_base exit_status
+
+# Save off a copy of the environment before mportinit monkeys with it
+array set boot_env [array get env]
+
+set cmdname [file tail $argv0]
+
+# Setp cmd_argv to match argv
+set cmd_argv $argv
+set cmd_argc $argc
+set cmd_argn 0
+
+# make sure we're using a sane umask
+umask 022
+
+# If we've been invoked as portf, then the first argument is assumed
+# to be the name of a command file (i.e., there is an implicit -F
+# before any arguments).
+if {[moreargs] && $cmdname eq "portf"} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options "global" ui_options global_options} result]} {
+    puts "Error: $result"
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    && $portclient::progress::hasTermAnsiSend eq "yes"
+    && (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne "yes")} {
+    set ui_options(progress_download) portclient::progress::download
+    set ui_options(progress_generic)  portclient::progress::generic
+}
+
+set ui_options(notifications_append) portclient::notifications::append
+
+# Get arguments remaining after option processing
+set remaining_args [lrange $cmd_argv $cmd_argn end]
+
+# If we have no arguments remaining after option processing then force
+# interactive mode
+if { [llength $remaining_args] == 0 && ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq "selfupdate" || [lookahead] eq "sync"} {
+    # tell mportinit not to tell the user they should selfupdate
+    set ui_options(ports_no_old_index_warning) 1
+}
+
+# Initialize mport
+# This must be done following parse of global options, as some options are
+# evaluated by mportinit.
+if {[catch {mportinit ui_options global_options global_variations} result]} {
+    global errorInfo
+    puts "$errorInfo"
+    fatal "Failed to initialize MacPorts, $result"
+}
+
+# Set up some global state for our code
+set current_portdir [pwd]
+
+# Freeze global_options into global_options_base; global_options
+# will be reset to global_options_base prior to processing each command.
+set global_options_base [array get global_options]
+
+# First process any remaining args as action(s)
+set exit_status 0
+if { [llength $remaining_args] > 0 } {
+
+    # If there are remaining arguments, process those as a command
+    set exit_status [process_cmd $remaining_args]
+}
+
+# Process any prescribed command files, including standard input
+if { ($exit_status == 0 || [macports::ui_isset ports_processall]) && [info exists ui_options(ports_commandfiles)] } {
+    set exit_status [process_command_files $ui_options(ports_commandfiles)]
+}
+if {$exit_status == -999} {
+    set exit_status 0
+}
+
+# shut down macports1.0
+mportshutdown
+
+# Return with exit_status
+exit $exit_status

Added: branches/gsoc14-cleanup/src/port/port.orig
===================================================================
--- branches/gsoc14-cleanup/src/port/port.orig	                        (rev 0)
+++ branches/gsoc14-cleanup/src/port/port.orig	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,5362 @@
+#!/opt/local/libexec/macports/bin/tclsh8.5
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
+# $Id: port.tcl 119177 2014-04-18 22:35:29Z cal at macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw <rshaw at opendarwin.org>
+# Copyright (c) 2002-2003 Apple Inc.
+# 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.
+# 3. Neither the name of Apple Inc. nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+# Create a namespace for some local variables
+namespace eval portclient::progress {
+    ##
+    # Indicate whether the term::ansi::send tcllib package is available and was
+    # imported. "yes", if the package is available, "no" otherwise.
+    variable hasTermAnsiSend no
+}
+
+if {![catch {package require term::ansi::send}]} {
+    set portclient::progress::hasTermAnsiSend yes
+}
+
+package require macports
+package require Pextlib 1.0
+
+# Standard procedures
+proc print_usage {{verbose 1}} {
+    global cmdname
+    set syntax {
+        [-bcdfknopqRstuvy] [-D portdir] [-F cmdfile] action [privopts] [actionflags]
+        [[portname|pseudo-portname|port-url] [@version] [+-variant]... [option=value]...]...
+    }
+
+    if {$verbose} {
+        puts stderr "Usage: $cmdname$syntax"
+        puts stderr "\"$cmdname help\" or \"man 1 port\" for more information."
+    } else {
+        puts stderr "$cmdname$syntax"
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds ""
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen > 65} {
+            set cmds "$cmds,\n"
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new "$cmd"
+        } else {
+            set new ", $cmd"
+        }
+        incr lineLen [string length $new]
+        set cmds "$cmds$new"
+    }
+
+    set cmdText "Supported actions
+------------------
+$cmds
+"
+
+    set text {
+Pseudo-portnames
+----------------
+Pseudo-portnames are words that may be used in place of a portname, and
+which expand to some set of ports. The common pseudo-portnames are:
+all, current, active, inactive, actinact, installed, uninstalled, outdated,
+obsolete, requested, unrequested and leaves.
+These pseudo-portnames expand to the set of ports named.
+
+Pseudo-portnames starting with variants:, variant:, description:, depends:,
+depends_lib:, depends_run:, depends_build:, depends_fetch:, depends_extract:,
+portdir:, homepage:, epoch:, platforms:, platform:, name:, long_description:,
+maintainers:, maintainer:, categories:, category:, version:, revision:, and
+license: each select a set of ports based on a regex search of metadata
+about the ports. In all such cases, a standard regex pattern following
+the colon will be used to select the set of ports to which the
+pseudo-portname expands.
+
+Pseudo-portnames starting with depof:, rdepof:, dependentof:, and rdependentof:
+select ports that are direct or recursive dependencies or dependents of the
+following portname, respectively.
+
+Portnames that contain standard glob characters will be expanded to the
+set of ports matching the glob pattern.
+    
+Port expressions
+----------------
+Portnames, port glob patterns, and pseudo-portnames may be logically
+combined using expressions consisting of and, or, not, !, (, and ).
+    
+For more information
+--------------------
+See man pages: port(1), macports.conf(5), portfile(7), portgroup(7),
+porthier(7), portstyle(7). Also, see http://www.macports.org.
+    }
+
+    puts "$cmdText$text"
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error "$argv0: $s"
+    exit 1
+}
+
+##
+# Helper function to define constants
+#
+# Constants defined with const can simply be accessed in the same way as
+# calling a proc.
+#
+# Example:
+# const FOO 42
+# puts [FOO]
+#
+# @param name variable name
+# @param value constant variable value
+proc const {name args} {
+    proc $name {} [list return [expr $args]]
+}
+
+# Format an integer representing bytes using given units
+proc bytesize {siz {unit {}} {format {%.3f}}} {
+    if {$unit == {}} {
+        if {$siz > 0x40000000} {
+            set unit "GiB"
+        } elseif {$siz > 0x100000} {
+            set unit "MiB"
+        } elseif {$siz > 0x400} {
+            set unit "KiB"
+        } else {
+            set unit "B"
+        }
+    }
+    switch -- $unit {
+        KiB {
+            set siz [expr {$siz / 1024.0}]
+        }
+        kB {
+            set siz [expr {$siz / 1000.0}]
+        }
+        MiB {
+            set siz [expr {$siz / 1048576.0}]
+        }
+        MB {
+            set siz [expr {$siz / 1000000.0}]
+        }
+        GiB {
+            set siz [expr {$siz / 1073741824.0}]
+        }
+        GB {
+            set siz [expr {$siz / 1000000000.0}]
+        }
+        B { }
+        default {
+            ui_warn "Unknown file size unit '$unit' specified"
+            set unit "B"
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return "$siz $unit"
+}
+
+proc filesize {fil {unit {}}} {
+    set siz {@}
+    catch {
+        set siz [bytesize [file size $fil] $unit]
+    }
+    return $siz
+}
+
+# Produce an error message, and exit, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc fatal_softcontinue s {
+    if {[macports::global_option_isset ports_force]} {
+        ui_error $s
+        return -code continue
+    } else {
+        fatal $s
+    }
+}
+
+
+# Produce an error message, and break, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc break_softcontinue { msg status name_status } {
+    upvar $name_status status_var 
+    ui_error $msg
+    if {[macports::ui_isset ports_processall]} {
+        set status_var 0
+        return -code continue
+    } else {
+        set status_var $status
+        return -code break
+    }
+}
+
+# show the URL for the ticket reporting instructions
+proc print_tickets_url {args} {
+    if {${macports::prefix} ne "/usr/local" && ${macports::prefix} ne "/usr"} {
+        ui_error "Follow http://guide.macports.org/#project.tickets to report a bug."
+    }
+}
+
+# Form a composite version as is sometimes used for registry functions
+# This function sorts the variants and presents them in a canonical representation
+proc composite_version {version variations {emptyVersionOkay 0}} {
+    # Form a composite version out of the version and variations
+    
+    # Select the variations into positive and negative
+    set pos {}
+    set neg {}
+    foreach { key val } $variations {
+        if {$val eq "+"} {
+            lappend pos $key
+        } elseif {$val eq "-"} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version ""
+    if {$version ne "" || $emptyVersionOkay} {
+        set pos_str ""
+        set neg_str ""
+
+        if {[llength $pos]} {
+            set pos_str "+[join [lsort -ascii $pos] "+"]"
+        }
+        if {[llength $neg]} {
+            set neg_str "-[join [lsort -ascii $neg] "-"]"
+        }
+
+        set composite_version "$version$pos_str$neg_str"
+    }
+
+    return $composite_version
+}
+
+
+proc split_variants {variants} {
+    set result {}
+    set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
+    foreach { match sign variant } $l {
+        lappend result $variant $sign
+    }
+    return $result
+}
+
+
+##
+# Maps friendly field names to their real name
+# Names which do not need mapping are not changed.
+#
+# @param field friendly name
+# @return real name
+proc map_friendly_field_names { field } {
+    switch -- $field {
+        variant -
+        platform -
+        maintainer -
+        subport {
+            set field "${field}s"
+        }
+        category {
+            set field "categories"
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion ""}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] > 1 } {
+        # set portname again since the one we were passed may not have had the correct case
+        set portname [lindex $ilist 0 0]
+        ui_notice "The following versions of $portname are currently installed:"
+        foreach i [portlist_sortint $ilist] { 
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants} (active)"
+            }
+        }
+        return -code error "Registry error: Please specify the full version as recorded in the port registry."
+    } else {
+        return [lindex $ilist 0]
+    }
+}
+
+
+proc entry_for_portlist {portentry} {
+    global global_options global_variations
+
+    # Each portlist entry currently has the following elements in it:
+    #   url             if any
+    #   name
+    #   version         (version_revision)
+    #   variants array  (variant=>+-)
+    #   requested_variants array  (variant=>+-)
+    #   options array   (key=>value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) "" }
+    if {![info exists port(name)]}      { set port(name) "" }
+    if {![info exists port(version)]}   { set port(version) "" }
+    if {![info exists port(variants)]}  { set port(variants) "" }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) "" }
+    if {![info exists port(options)]}   { set port(options) [array get global_options] }
+
+    # If neither portname nor url is specified, then default to the current port
+    if { $port(url) eq "" && $port(name) eq "" } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq ""} {
+            ui_error "A default port name could not be supplied."
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) "$port(name)/[composite_version $port(version) $port(variants)]"
+    
+    return [array get port]
+}
+
+
+proc add_to_portlist {listname portentry} {
+    upvar $listname portlist
+    
+    # Form portlist entry and add to portlist
+    lappend portlist [entry_for_portlist $portentry]
+}
+
+
+proc add_ports_to_portlist {listname ports {overridelist ""}} {
+    upvar $listname portlist
+
+    array set overrides $overridelist
+
+    # Add each entry to the named portlist, overriding any values
+    # specified as overrides
+    foreach portentry $ports {
+        array set port $portentry
+        if ([info exists overrides(version)])   { set port(version) $overrides(version) }
+        if ([info exists overrides(variants)])  { set port(variants) $overrides(variants) }
+        if ([info exists overrides(requested_variants)])  { set port(requested_variants) $overrides(requested_variants) }
+        if ([info exists overrides(options)])   { set port(options) $overrides(options) }
+        add_to_portlist portlist [array get port]
+    }
+}
+
+
+proc url_to_portname { url {quiet 0} } {
+    # Save directory and restore the directory, since mportopen changes it
+    set savedir [pwd]
+    set portname ""
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg "Can't map the URL '$url' to a port description file (\"${result}\")."
+            ui_msg "Please verify that the directory and portfile syntax are correct."
+        }
+    } else {
+        array set portinfo [mportinfo $ctx]
+        set portname $portinfo(name)
+        mportclose $ctx
+    }
+    cd $savedir
+    return $portname
+}
+
+
+# Supply a default porturl/portname if the portlist is empty
+proc require_portlist { nameportlist {is_upgrade "no"} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 && (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        if {${is_upgrade} == "yes"} {
+            # $> port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # "upgrade", let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg "Nothing to upgrade."
+            return 1
+        }
+        ui_error "No ports matched the given expression"
+        return 1
+    }
+
+    if {[llength $portlist] == 0} {
+        set portlist [get_current_port]
+
+        if {[llength $portlist] == 0} {
+            # there was no port in current directory
+            return 1
+        }
+    }
+
+    return 0
+}
+
+
+# Execute the enclosed block once for every element in the portlist
+# When the block is entered, the following variables will have been set:
+#   portspec, porturl, portname, portversion, options, variations, requested_variations
+proc foreachport {portlist block} {
+    set savedir [pwd]
+    foreach portspec $portlist {
+    
+        # Set the variables for the block
+        uplevel 1 "array unset portspec; array set portspec { $portspec }"
+        uplevel 1 {
+            set porturl $portspec(url)
+            set portname $portspec(name)
+            set portversion $portspec(version)
+            array unset variations
+            array set variations $portspec(variants)
+            array unset requested_variations
+            array set requested_variations $portspec(requested_variants)
+            array unset options
+            array set options $portspec(options)
+        }
+        
+        # Invoke block
+        uplevel 1 $block
+        
+        # Restore cwd after each port, since mportopen changes it, and otherwise relative
+        # urls would break on subsequent passes
+        if {[file exists $savedir]} {
+            cd $savedir
+        } else {
+            cd ~
+        }
+    }
+}
+
+
+proc portlist_compare { a b } {
+    array set a_ $a
+    array set b_ $b
+    set namecmp [string equal -nocase $a_(name) $b_(name)]
+    if {$namecmp != 1} {
+        if {$a_(name) eq [lindex [lsort -dictionary [list $a_(name) $b_(name)]] 0]} {
+            return -1
+        }
+        return 1
+    }
+    set avr_ [split $a_(version) "_"]
+    set bvr_ [split $b_(version) "_"]
+    set versioncmp [vercmp [lindex $avr_ 0] [lindex $bvr_ 0]]
+    if {$versioncmp != 0} {
+        return $versioncmp
+    }
+    set ar_ [lindex $avr_ 1]
+    set br_ [lindex $bvr_ 1]
+    if {$ar_ < $br_} {
+        return -1
+    } elseif {$ar_ > $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name at version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list "name" [lindex $a 0] "version" "[lindex $a 1]_[lindex $a 2]"]
+    array set b_ [list "name" [lindex $b 0] "version" "[lindex $b 1]_[lindex $b 2]"]
+    return [portlist_compare [array get a_] [array get b_]]
+}
+
+# Same as portlist_sort, but with numeric indexes {name version revision}
+proc portlist_sortint { list } {
+    return [lsort -command portlist_compareint $list]
+}
+
+# sort portlist so dependents come before their dependencies
+proc portlist_sortdependents { portlist } {
+    foreach p $portlist {
+        array set pvals $p
+        lappend entries($pvals(name)) $p
+        if {![info exists dependents($pvals(name))]} {
+            set dependents($pvals(name)) {}
+            foreach result [registry::list_dependents $pvals(name)] {
+                lappend dependents($pvals(name)) [lindex $result 2]
+            }
+        }
+        array unset pvals
+    }
+    set ret {}
+    foreach p $portlist {
+        portlist_sortdependents_helper $p entries dependents seen ret
+    }
+    return $ret
+}
+
+proc portlist_sortdependents_helper {p up_entries up_dependents up_seen up_retlist} {
+    upvar $up_seen seen
+    if {![info exists seen($p)]} {
+        set seen($p) 1
+        upvar $up_entries entries $up_dependents dependents $up_retlist retlist
+        array set pvals $p
+        foreach dependent $dependents($pvals(name)) {
+            if {[info exists entries($dependent)]} {
+                foreach entry $entries($dependent) {
+                    portlist_sortdependents_helper $entry entries dependents seen retlist
+                }
+            }
+        }
+        lappend retlist $p
+    }
+}
+
+proc regex_pat_sanitize { s } {
+    set sanitized [regsub -all {[\\(){}+$.^]} $s {\\&}]
+    return $sanitized
+}
+
+##
+# Makes sure we get the current terminal size
+proc term_init_size {} {
+    global env
+
+    if {![info exists env(COLUMNS)] || ![info exists env(LINES)]} {
+        if {[isatty stdout]} {
+            set size [term_get_size stdout]
+
+            if {![info exists env(LINES)] && [lindex $size 0] > 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] && [lindex $size 1] > 0} {
+                set env(COLUMNS) [lindex $size 1]
+            }
+        }
+    }
+}
+
+##
+# Wraps a multi-line string at specified textwidth
+#
+# @see wrapline
+#
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrap {string maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set splitstring {}
+    set indentline $indentfirstline
+    foreach line [split $string "\n"] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring "\n"]
+}
+
+##
+# Wraps a line at specified textwidth
+#
+# @see wrap
+#
+# @param line input line
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrapline {line maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set string [split $line " "]
+    if {$indentfirstline == 0} {
+        set newline ""
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner " "
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] >= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner ""
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 && $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner " "
+    }
+    lappend lines $newline
+    return [join $lines "\n"]
+}
+
+##
+# Wraps a line at a specified width with a label in front
+#
+# @see wrap
+#
+# @param label label for output
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @return wrapped string
+proc wraplabel {label string maxlen {indent ""}} {
+    append label ": [string repeat " " [expr {[string length $indent] - [string length "$label: "]}]]"
+    return "$label[wrap $string $maxlen $indent 0]"
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first "@" $m] < 0} {
+            if {[string first ":" $m] >= 0} {
+                set m [regsub -- "(.*):(.*)" $m "\\2@\\1"] 
+            } else {
+                set m "$m at macports.org"
+            }
+        }
+        lappend result $m
+    }
+    return $result
+}
+
+
+##########################################
+# Port selection
+##########################################
+proc unique_results_to_portlist {infos} {
+    set result {}
+    array unset unique
+    foreach {name info} $infos {
+        array unset portinfo
+        array set portinfo $info
+        
+        set portentry [entry_for_portlist [list url $portinfo(porturl) name $name]]
+        
+        array unset entry
+        array set entry $portentry
+        
+        if {[info exists unique($entry(fullname))]} continue
+        set unique($entry(fullname)) 1
+        
+        lappend result $portentry
+    }
+    return $result
+}
+
+
+proc get_matching_ports {pattern {casesensitive no} {matchstyle glob} {field name}} {
+    if {[catch {set res [mportsearch $pattern $casesensitive $matchstyle $field]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        fatal "search for portname $pattern failed: $result"
+    }
+    set results [unique_results_to_portlist $res]
+    
+    # Return the list of all ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_all_ports {} {
+    global all_ports_cache
+
+    if {![info exists all_ports_cache]} {
+         if {[catch {set res [mportlistall]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "listing all ports failed: $result"
+        }
+        set results [unique_results_to_portlist $res]
+        set all_ports_cache [portlist_sort $results]
+    }
+    return $all_ports_cache
+}
+
+
+proc get_current_ports {} {
+    # This is just a synonym for get_current_port that
+    # works with the regex in element
+    return [get_current_port]
+}
+
+
+proc get_current_port {} {
+    set url file://.
+    set portname [url_to_portname $url]
+    if {$portname eq ""} {
+        ui_msg "To use the current port, you must be in a port's directory."
+        return [list]
+    }
+
+    set results {}
+    add_to_portlist results [list url $url name $portname]
+    return $results
+}
+
+
+proc get_installed_ports { {ignore_active yes} {active yes} } {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [split_variants [lindex $i 3]]
+        set iactive [lindex $i 4]
+
+        if { ${ignore_active} == "yes" || (${active} == "yes") == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants $ivariants]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_uninstalled_ports {} {
+    # Return all - installed
+    set all [get_all_ports]
+    set installed [get_installed_ports]
+    return [opComplement $all $installed]
+}
+
+
+proc get_active_ports {} {
+    return [get_installed_ports no yes]
+}
+
+
+proc get_inactive_ports {} {
+    return [get_installed_ports no no]
+}
+
+proc get_actinact_ports {} {
+    set inactive_ports [get_inactive_ports]
+    set active_ports [get_active_ports]
+    set results {}
+
+    foreach port $inactive_ports {
+        array set portspec $port
+        set portname $portspec(name)
+        lappend inact($portname) $port
+    }
+
+    foreach port $active_ports {
+        array set portspec $port
+        set portname $portspec(name)
+
+        if {[info exists inact($portname)]} {
+            if {![info exists added_inact($portname)]} {
+                foreach inact_spec $inact($portname) {
+                    lappend results $inact_spec
+                }
+                set added_inact($portname) 1
+            }
+            lappend results $port
+        }
+    }
+    return $results
+}
+
+
+proc get_outdated_ports {} {
+    # Get the list of installed ports
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] > 0 } {
+        foreach i $ilist {
+
+            # Get information about the installed port
+            set portname            [lindex $i 0]
+            set installed_version   [lindex $i 1]
+            set installed_revision  [lindex $i 2]
+            set installed_compound  "${installed_version}_${installed_revision}"
+            set installed_variants  [lindex $i 3]
+
+            set is_active           [lindex $i 4]
+            if {$is_active == 0} continue
+
+            set installed_epoch     [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                fatal "lookup of portname $portname failed: $result"
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+
+            # Get information about latest available version and revision
+            set latest_version $portinfo(version)
+            set latest_revision     0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     "${latest_version}_${latest_revision}"
+            set latest_epoch        0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch    $portinfo(epoch)
+            }
+
+            # Compare versions, first checking epoch, then version, then revision
+            set comp_result 0
+            if {$installed_version != $latest_version} {
+                set comp_result [expr {$installed_epoch - $latest_epoch}]
+                if { $comp_result == 0 } {
+                    set comp_result [vercmp $installed_version $latest_version]
+                }
+            }
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            if {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision $installed_variants $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                }
+            }
+
+            # Add outdated ports to our results list
+            if { $comp_result < 0 } {
+                add_to_portlist results [list name $portname version $installed_compound variants [split_variants $installed_variants]]
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_obsolete_ports {} {
+    set ilist [get_installed_ports]
+    set results {}
+
+    foreach i $ilist {
+        array set port $i
+
+        if {[catch {mportlookup $port(name)} result]} {
+            ui_debug "$::errorInfo"
+            break_softcontinue "lookup of portname $portname failed: $result" 1 status
+        }
+
+        if {[llength $result] < 2} {
+            lappend results $i
+        }
+    }
+
+    # Return the list of ports, already sorted
+    return [portlist_sort $results]
+}
+
+# return ports that have registry property $propname set to $propval
+proc get_ports_with_prop {propname propval} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [lindex $i 3]
+        set iepoch [lindex $i 5]
+        set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
+        if {[registry::property_retrieve $regref $propname] == $propval} {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants [split_variants $ivariants]]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+proc get_requested_ports {} {
+    return [get_ports_with_prop requested 1]
+}
+
+proc get_unrequested_ports {} {
+    return [get_ports_with_prop requested 0]
+}
+
+proc get_leaves_ports {} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq ""} {
+            add_to_portlist results [list name $iname version "[lindex $i 1]_[lindex $i 2]" variants [split_variants [lindex $i 3]]]
+        }
+    }
+    return [portlist_sort [opIntersection $results [get_unrequested_ports]]]
+}
+
+proc get_dependent_ports {portname recursive} {
+    registry::open_dep_map
+    set deplist [registry::list_dependents $portname]
+    # could return specific versions here using registry2.0 features
+    set results {}
+    foreach dep $deplist {
+        add_to_portlist results [list name [lindex $dep 2]]
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex $dep 2]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    set rdeplist [registry::list_dependents $depname]
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex $rdep 2]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_dep_ports {portname recursive} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its deps
+    set results {}
+    set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+
+    set deplist {}
+    foreach type $deptypes {
+        if {[info exists portinfo($type)]} {
+            foreach dep $portinfo($type) {
+                add_to_portlist results [list name [lindex [split $dep :] end]]
+                lappend deplist $dep
+            }
+        }
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        return -code error "lookup of portname $depname failed: $result"
+                    }
+                    if {[llength $result] < 2} {
+                        ui_error "Port $depname not found"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                
+                    # open its portfile
+                    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+                        ui_debug "$::errorInfo"
+                        ui_error "Unable to open port: $result"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [mportinfo $mport]
+                    mportclose $mport
+
+                    # collect its deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                add_to_portlist results [list name [lindex [split $rdep :] end]]
+                                lappend rdeplist $rdep
+                            }
+                        }
+                    }
+
+                    # add them to the lists
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex [split $rdep :] end]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+proc get_subports {portname} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its subports
+    set results {}
+
+    if {[info exists portinfo(subports)]} {
+        foreach subport $portinfo(subports) {
+            add_to_portlist results [list name $subport]
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+##########################################
+# Port expressions
+##########################################
+proc portExpr { resname } {
+    upvar $resname reslist
+    set result [seqExpr reslist]
+    return $result
+}
+
+
+proc seqExpr { resname } {
+    upvar $resname reslist
+    
+    # Evaluate a sequence of expressions a b c...
+    # These act the same as a or b or c
+
+    set result 1
+    while {$result} {
+        switch -- [lookahead] {
+            ;       -
+            )       -
+            _EOF_   { break }
+        }
+
+        set blist {}
+        set result [orExpr blist]
+        if {$result} {
+            # Calculate the union of result and b
+            set reslist [opUnion $reslist $blist]
+        }
+    }
+    
+    return $result
+}
+
+
+proc orExpr { resname } {
+    upvar $resname reslist
+    
+    set a [andExpr reslist]
+    while ($a) {
+        switch -- [lookahead] {
+            or {
+                    advance
+                    set blist {}
+                    if {![andExpr blist]} {
+                        return 0
+                    }
+                        
+                    # Calculate a union b
+                    set reslist [opUnion $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc andExpr { resname } {
+    upvar $resname reslist
+    
+    set a [unaryExpr reslist]
+    while {$a} {
+        switch -- [lookahead] {
+            and {
+                    advance
+                    
+                    set blist {}
+                    set b [unaryExpr blist]
+                    if {!$b} {
+                        return 0
+                    }
+                    
+                    # Calculate a intersect b
+                    set reslist [opIntersection $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc unaryExpr { resname } {
+    upvar $resname reslist
+    set result 0
+
+    switch -- [lookahead] {
+        !   -
+        not {
+                advance
+                set blist {}
+                set result [unaryExpr blist]
+                if {$result} {
+                    set all [get_all_ports]
+                    set reslist [opComplement $all $blist]
+                }
+            }
+        default {
+                set result [element reslist]
+            }
+    }
+    
+    return $result
+}
+
+
+proc element { resname } {
+    upvar $resname reslist
+    set el 0
+    
+    set url ""
+    set name ""
+    set version ""
+    array unset requested_variants
+    array unset options
+    
+    set token [lookahead]
+    switch -regex -- $token {
+        ^\\)$               -
+        ^\;                 -
+        ^_EOF_$             { # End of expression/cmd/file
+        }
+
+        ^\\($               { # Parenthesized Expression
+            advance
+            set el [portExpr reslist]
+            if {!$el || ![match ")"]} {
+                set el 0
+            }
+        }
+
+        ^all(@.*)?$         -
+        ^installed(@.*)?$   -
+        ^uninstalled(@.*)?$ -
+        ^active(@.*)?$      -
+        ^inactive(@.*)?$    -
+        ^actinact(@.*)?$    -
+        ^leaves(@.*)?$      -
+        ^outdated(@.*)?$    -
+        ^obsolete(@.*)?$    -
+        ^requested(@.*)?$   -
+        ^unrequested(@.*)?$ -
+        ^current(@.*)?$     {
+            # A simple pseudo-port name
+            advance
+
+            # Break off the version component, if there is one
+            regexp {^(\w+)(@.*)?} $token matchvar name remainder
+
+            add_multiple_ports reslist [get_${name}_ports] $remainder
+
+            set el 1
+        }
+
+        ^variants:          -
+        ^variant:           -
+        ^description:       -
+        ^portdir:           -
+        ^homepage:          -
+        ^epoch:             -
+        ^platforms:         -
+        ^platform:          -
+        ^name:              -
+        ^long_description:  -
+        ^maintainers:       -
+        ^maintainer:        -
+        ^categories:        -
+        ^category:          -
+        ^version:           -
+        ^depends_lib:       -
+        ^depends_build:     -
+        ^depends_run:       -
+        ^depends_extract:   -
+        ^depends_fetch:     -
+        ^replaced_by:       -
+        ^revision:          -
+        ^subport:           -
+        ^subports:          -
+        ^license:           { # Handle special port selectors
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            # Remap friendly names to actual names
+            set field [map_friendly_field_names $field]
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp $field]
+            set el 1
+        }
+
+        ^depends:           { # A port selector shorthand for depends_{lib,build,run,fetch,extract}
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_lib"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_build"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_run"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_extract"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_fetch"]
+
+            set el 1
+        }
+
+        ^dependentof:       -
+        ^rdependentof:      {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdependentof"]
+            add_multiple_ports reslist [get_dependent_ports $portname $recursive]
+            
+            set el 1
+        }
+        
+        ^depof:             -
+        ^rdepof:            {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdepof"]
+            add_multiple_ports reslist [get_dep_ports $portname $recursive]
+            
+            set el 1
+        }
+
+        ^subportof:         {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            add_multiple_ports reslist [get_subports $portname]
+
+            set el 1
+        }
+
+        [][?*]              { # Handle portname glob patterns
+            advance; add_multiple_ports reslist [get_matching_ports $token no glob]
+            set el 1
+        }
+
+        ^\\w+:.+            { # Handle a url by trying to open it as a port and mapping the name
+            advance
+            set name [url_to_portname $token]
+            if {$name ne ""} {
+                parsePortSpec version requested_variants options
+                add_to_portlist reslist [list url $token \
+                  name $name \
+                  version $version \
+                  requested_variants [array get requested_variants] \
+                  variants [array get requested_variants] \
+                  options [array get options]]
+                set el 1
+            } else {
+                ui_error "Can't open URL '$token' as a port"
+                set el 0
+            }
+        }
+
+        default             { # Treat anything else as a portspec (portname, version, variants, options
+            # or some combination thereof).
+            parseFullPortSpec url name version requested_variants options
+            add_to_portlist reslist [list url $url \
+              name $name \
+              version $version \
+              requested_variants [array get requested_variants] \
+              variants [array get requested_variants] \
+              options [array get options]]
+            set el 1
+        }
+    }
+
+    return $el
+}
+
+
+proc add_multiple_ports { resname ports {remainder ""} } {
+    upvar $resname reslist
+    
+    set version ""
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne ""} { set overrides(version) $version }
+    if {[array size variants]} {
+        # we always record the requested variants separately,
+        # but requested ones always override existing ones
+        set overrides(requested_variants) [array get variants]
+        set overrides(variants) [array get variants]
+    }
+    if {[array size options]} { set overrides(options) [array get options] }
+
+    add_ports_to_portlist reslist $ports [array get overrides]
+}
+
+
+proc unique_entries { entries } {
+    # Form the list of all the unique elements in the list a,
+    # considering only the port fullname, and taking the first
+    # found element first
+    set result {}
+    array unset unique
+    foreach item $entries {
+        array set port $item
+        if {[info exists unique($port(fullname))]} continue
+        set unique($port(fullname)) 1
+        lappend result $item
+    }
+    return $result
+}
+
+
+proc opUnion { a b } {
+    # Return the unique elements in the combined two lists
+    return [unique_entries [concat $a $b]]
+}
+
+
+proc opIntersection { a b } {
+    set result {}
+    
+    # Rules we follow in performing the intersection of two port lists:
+    #
+    #   a/, a/          ==> a/
+    #   a/, b/          ==>
+    #   a/, a/1.0       ==> a/1.0
+    #   a/1.0, a/       ==> a/1.0
+    #   a/1.0, a/2.0    ==>
+    #
+    #   If there's an exact match, we take it.
+    #   If there's a match between simple and discriminated, we take the later.
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem [unique_entries $b] {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, matching against b
+    foreach aitem [unique_entries $a] {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+        foreach match $matches {
+            if {$simpleform} {
+                set i $bfull($match)
+                lappend result [lindex $b $i]
+            } else {
+                lappend result $aitem
+            }
+        }
+    }
+    
+    return $result
+}
+
+
+proc opComplement { a b } {
+    set result {}
+    
+    # Return all elements of a not matching elements in b
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem $b {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, taking all those items that don't match b
+    foreach aitem $a {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+
+        # We copy this element to result only if it didn't match against b
+        if {![llength $matches]} {
+            lappend result $aitem
+        }
+    }
+    
+    return $result
+}
+
+
+proc parseFullPortSpec { urlname namename vername varname optname } {
+    upvar $urlname porturl
+    upvar $namename portname
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    set portname ""
+    set portversion ""
+    array unset portvariants
+    array unset portoptions
+    
+    if { [moreargs] } {
+        # Look first for a potential portname
+        #
+        # We need to allow a wide variety of tokens here, because of actions like "provides"
+        # so we take a rather lenient view of what a "portname" is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder ""
+        if {![regexp {^(@|[-+]([[:alpha:]_]+[\w\.]*)|[[:alpha:]_]+[\w\.]*=)} $token match]} {
+            advance
+            regexp {^([^@]+)(@.*)?} $token match portname remainder
+            
+            # If the portname contains a /, then try to use it as a URL
+            if {[string match "*/*" $portname]} {
+                set url "file://$portname"
+                set name [url_to_portname $url 1]
+                if { $name ne "" } {
+                    # We mapped the url to valid port
+                    set porturl $url
+                    set portname $name
+                    # Continue to parse rest of portspec....
+                } else {
+                    # We didn't map the url to a port; treat it
+                    # as a raw string for something like port contents
+                    # or cd
+                    set porturl ""
+                    # Since this isn't a port, we don't try to parse
+                    # any remaining portspec....
+                    return
+                }
+            }
+        }
+        
+        # Now parse the rest of the spec
+        parsePortSpec portversion portvariants portoptions $remainder
+    }
+}
+
+# check if the install prefix is writable
+# should be called by actions that will modify it
+proc prefix_unwritable {} {
+    global macports::portdbpath
+    if {[file writable $portdbpath]} {
+        return 0
+    } else {
+        ui_error "Insufficient privileges to write to MacPorts install prefix."
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder ""} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion ""
+    array unset portoptions
+    array set portoptions [array get global_options]
+    array unset portvariants
+    
+    # Parse port version/variants/options
+    set opt $remainder
+    set adv 0
+    set consumed 0
+    for {set firstTime 1} {$opt ne "" || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq ""} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime && [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first "/" $opt]
+            if {$sepPos >= 0} {
+                # Version terminated by "/" to disambiguate -variant from part of version
+                set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                set opt [string range $opt [expr {$sepPos + 1}] end]
+            } else {
+                # Version terminated by "+", or else is complete
+                set sepPos [string first "+" $opt]
+                if {$sepPos >= 0} {
+                    # Version terminated by "+"
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt ""
+                }
+            }
+            set consumed 1
+        } else {
+            # Parse all other options
+            
+            # Look first for a variable setting: VARNAME=VALUE
+            if {[regexp {^([[:alpha:]_]+[\w\.]*)=(.*)} $opt match key val] == 1} {
+                # It's a variable setting
+                set portoptions($key) "\"$val\""
+                set opt ""
+                set consumed 1
+            } elseif {[regexp {^([-+])([[:alpha:]_]+[\w\.]*)} $opt match sign variant] == 1} {
+                # It's a variant
+                set portvariants($variant) $sign
+                set opt [string range $opt [expr {[string length $variant] + 1}] end]
+                set consumed 1
+            } else {
+                # Not an option we recognize, so break from port option processing
+                if { $consumed && $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds ""
+        if {[info exists cmd_opts_array($action)]} {
+            foreach opt $cmd_opts_array($action) {
+                if {[llength $opt] == 1} {
+                    set name $opt
+                    set optc 0
+                } else {
+                    set name [lindex $opt 0]
+                    set optc [lindex $opt 1]
+                }
+
+                append cmds " --$name"
+
+                for {set i 1} {$i <= $optc} {incr i} {
+                    append cmds " <arg$i>"
+                }
+            }
+        }
+        set args ""
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <arguments>"
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <portlist>"
+        }
+
+        set ret "Usage: "
+        set len [string length $action]
+        append ret [wrap "$action$cmds$args" 0 [string repeat " " [expr {8 + $len}]] 0]
+        append ret "\n"
+
+        return $ret
+    }
+
+    return -1
+}
+
+proc action_usage { action portlist opts } {
+    if {[llength $portlist] == 0} {
+        print_usage
+        return 0
+    }
+
+    foreach topic $portlist {
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile "$macports::prefix/var/macports/port-help.tcl"
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr "Error reading helpfile $helpfile: $err"
+            return 1
+        }
+    } else {
+        puts stderr "Unable to open help file $helpfile"
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr "No help for topic $topic"
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+
+        puts stderr $porthelp($topic)
+    }
+
+    return 0
+}
+
+
+proc action_log { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array unset portinfo
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+            set portname $portinfo(name)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            array unset portinfo
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] "main.log"]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue "Could not open file $logfile: $result" 1 status
+            }
+            set data [read $fp]
+            set data [split $data "\n"]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase "\[a-z\]*"
+            }
+
+            if {[info exists global_options(ports_log_level)]} {
+                set index [lsearch -exact ${macports::ui_priorities} $global_options(ports_log_level)]
+                if {$index == -1} {
+                    set prefix ""
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] "|"]
+                }
+            } else {
+                set prefix "\[a-z\]*"
+            }
+            foreach line $data {
+                set exp "^:($prefix|any):($phase|any) (.*)$"
+                if {[regexp $exp $line -> lpriority lphase lmsg] == 1} {
+                    puts "[macports::ui_prefix_default $lpriority]$lmsg"
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue "Log file for port $portname not found" 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator ""
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] && $options(ports_info_index)} {
+            set index_only 1
+        }
+        puts -nonewline $separator
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq "" || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!$index_only} {
+            # Add any global_variations to the variations
+            # specified for the port (so we get e.g. dependencies right)
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+ 
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            unset options(subport)
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "no PortIndex entry found for $portname"
+            continue
+        }
+        array unset options ports_info_index
+
+        # Understand which info items are actually lists
+        # (this could be overloaded to provide a generic formatting code to
+        # allow us to, say, split off the prefix on libs)
+        array set list_map "
+            categories      1
+            depends_fetch   1
+            depends_extract 1
+            depends_build   1
+            depends_lib     1
+            depends_run     1
+            maintainers     1
+            platforms       1
+            variants        1
+            conflicts       1
+            subports        1
+        "
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     ""
+            variants    Variants
+            depends_fetch "Fetch Dependencies"
+            depends_extract "Extract Dependencies"
+            depends_build "Build Dependencies"
+            depends_run "Runtime Dependencies"
+            depends_lib "Library Dependencies"
+            description "Brief Description"
+            long_description "Description"
+            fullname    "Full Name: "
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   "Conflicts with"
+            replaced_by "Replaced by"
+            subports    "Sub-ports"
+        }
+
+        # Wrap-length map for pretty printing
+        array set pretty_wrap {
+            heading 0
+            replaced_by 22
+            variants 22
+            depends_fetch 22
+            depends_extract 22
+            depends_build 22
+            depends_run 22
+            depends_lib 22
+            description 22
+            long_description 22
+            homepage 22
+            platforms 22
+            license 22
+            conflicts 22
+            maintainers 22
+            subports 22
+        }
+
+        # Interpret a convenient field abbreviation
+        if {[info exists options(ports_info_depends)] && $options(ports_info_depends) eq "yes"} {
+            array unset options ports_info_depends
+            set options(ports_info_depends_fetch) yes
+            set options(ports_info_depends_extract) yes
+            set options(ports_info_depends_build) yes
+            set options(ports_info_depends_lib) yes
+            set options(ports_info_depends_run) yes
+        }
+                
+        # Set up our field separators
+        set show_label 1
+        set field_sep "\n"
+        set subfield_sep ", "
+        set pretty_print 0
+        
+        # For human-readable summary, which is the default with no options
+        if {[llength [array get options ports_info_*]] == 0} {
+            set pretty_print 1
+        } elseif {[info exists options(ports_info_pretty)]} {
+            set pretty_print 1
+            array unset options ports_info_pretty
+        }
+
+        # Tune for sort(1)
+        if {[info exists options(ports_info_line)]} {
+            array unset options ports_info_line
+            set noseparator 1
+            set show_label 0
+            set field_sep "\t"
+            set subfield_sep ","
+        }
+        
+        # Figure out whether to show field name
+        set quiet [macports::ui_isset ports_quiet]
+        if {$quiet} {
+            set show_label 0
+        }
+        # In pretty-print mode we also suppress messages, even though we show
+        # most of the labels:
+        if {$pretty_print} {
+            set quiet 1
+        }
+
+        # Spin through action options, emitting information for any found
+        set fields {}
+        set opts_todo [array names options ports_info_*]
+        set fields_tried {}
+        if {![llength $opts_todo]} {
+            set opts_todo {ports_info_heading
+                ports_info_replaced_by
+                ports_info_subports
+                ports_info_variants 
+                ports_info_skip_line
+                ports_info_long_description ports_info_homepage 
+                ports_info_skip_line ports_info_depends_fetch
+                ports_info_depends_extract ports_info_depends_build
+                ports_info_depends_lib ports_info_depends_run
+                ports_info_conflicts
+                ports_info_platforms ports_info_license
+                ports_info_maintainers
+            }
+        }
+        foreach { option } $opts_todo {
+            set opt [string range $option 11 end]
+            # Artificial field name for formatting
+            if {$pretty_print && $opt eq "skip_line"} {
+                lappend fields ""
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq "heading"} {
+                set inf "$portinfo(name) @$portinfo(version)"
+                set ropt "heading"
+                if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                    append inf "_$portinfo(revision)"
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf " ([join $portinfo(categories) ", "])"
+                }
+            } elseif {$opt eq "fullname"} {
+                set inf "$portinfo(name) @"
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt "fullname"
+            } else {
+                # Map from friendly name
+                set ropt [map_friendly_field_names $opt]
+                
+                # If there's no such info, move on
+                if {![info exists portinfo($ropt)]} {
+                    set inf ""
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label ""
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label "$opt: "
+            }
+            
+            # Format the data
+            if { $ropt eq "maintainers" } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq "variants"} {
+                    # Use the new format for variants iff it exists in
+                    # PortInfo. This key currently does not exist outside of
+                    # trunk (1.8.0).
+                    array unset vinfo
+                    if {[info exists portinfo(vinfo)]} {
+                        array set vinfo $portinfo(vinfo)
+                    }
+
+                    set pi_vars $inf
+                    set inf {}
+                    foreach v [lsort $pi_vars] {
+                        set varmodifier ""
+                        if {[info exists variations($v)]} {
+                            # selected by command line, prefixed with +/-
+                            set varmodifier $variations($v)
+                        } elseif {[info exists global_variations($v)]} {
+                            # selected by variants.conf, prefixed with (+)/(-)
+                            set varmodifier "($global_variations($v))"
+                            # Retrieve additional information from the new key.
+                        } elseif {[info exists vinfo]} {
+                            array unset variant
+                            array set variant $vinfo($v)
+                            if {[info exists variant(is_default)]} {
+                                set varmodifier "\[$variant(is_default)]"
+                            }
+                        }
+                        lappend inf "$varmodifier$v"
+                    }
+                } elseif {[string match "depend*" $ropt] 
+                          && ![macports::ui_isset ports_verbose]} {
+                    set pi_deps $inf
+                    set inf {}
+                    foreach d $pi_deps {
+                        lappend inf [lindex [split $d :] end]
+                    }
+                }
+            } 
+            #End of special pretty-print formatting for certain fields
+            if {[info exists list_map($ropt)]} {
+                set field [join $inf $subfield_sep]
+            } else {
+                set field $inf
+            }
+            
+            # Assemble the entry
+            if {$pretty_print} {
+                # The two special fields are considered headings and are
+                # emitted immediately, rather than waiting. Also they are not
+                # recorded on the list of fields tried
+                if {$ropt eq "heading" || $ropt eq "fullname"} {
+                    puts "$label$field"
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq ""} {
+                    continue
+                }
+                if {$label eq ""} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat " " $wrap_len]]
+                } else {
+                    set wrap_len [string length $label]
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wraplabel $label $field 0 [string repeat " " $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields "$label$field"
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print && [llength $fields_tried]} {
+                puts -nonewline "$portinfo(name) has no "
+                puts [join $fields_tried ", "]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator "--\n"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_location { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        if { [catch {set ilist [registry_installed $portname [composite_version $portversion [array get variations]]]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port location failed: $result" 1 status
+        } else {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0]
+            set version [lindex $ilist 1]
+            set revision [lindex $ilist 2]
+            set variants [lindex $ilist 3]
+            set epoch [lindex $ilist 5]
+        }
+
+        set ref [registry::open_entry $portname $version $revision $variants $epoch]
+        set imagedir [registry::property_retrieve $ref location]
+        ui_notice "Port $portname ${version}_${revision}${variants} is installed as an image in:"
+        puts $imagedir
+    }
+    
+    return $status
+}
+
+
+proc action_notes { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set status 0
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue "The lookup of '$portname' failed: $result" \
+                                1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "The port '$portname' was not found" 1 status
+            }
+
+            # Retrieve the port's URL.
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        }
+        
+        # Add any global_variations to the variations
+        # specified for the port
+        array unset merged_variations
+        array set merged_variations [array get variations]
+        foreach { variation value } [array get global_variations] { 
+            if { ![info exists merged_variations($variation)] } { 
+                set merged_variations($variation) $value 
+            } 
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+
+        # Open the Portfile associated with this port.
+        if {[catch {set mport [mportopen $porturl [array get options] \
+                                         [array get merged_variations]]} \
+                   result]} {
+            ui_debug $::errorInfo
+            break_softcontinue [concat "The URL '$porturl' could not be" \
+                                       "opened: $result"] 1 status
+        }
+        array unset portinfo
+        array set portinfo [mportinfo $mport]
+        mportclose $mport
+
+        # Return the notes associated with this Portfile.
+        if {[info exists portinfo(notes)]} {
+            set portnotes $portinfo(notes)
+        } else {
+            set portnotes {}
+        }
+
+        # Retrieve the port's name once more to ensure it has the proper case.
+        set portname $portinfo(name)
+
+        # Display the notes.
+        if {$portnotes ne {}} {
+            ui_notice "$portname has the following notes:"
+            foreach note $portnotes {
+                puts [wrap $note 0 "  " 1]
+            }
+        } else {
+            puts "$portname has no notes."
+        }
+    }
+    return $status
+}
+
+
+proc action_provides { action portlist opts } {
+    # In this case, portname is going to be used for the filename... since
+    # that is the first argument we expect... perhaps there is a better way
+    # to do this?
+    if { ![llength $portlist] } {
+        ui_error "Please specify a filename to check which port provides that file."
+        return 1
+    }
+    foreach filename $portlist {
+        set file [file normalize $filename]
+        if {[file exists $file] || ![catch {file type $file}]} {
+            if {![file isdirectory $file] || [file type $file] eq "link"} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts "$file is provided by: $port"
+                } else {
+                    puts "$file is not provided by a MacPorts port."
+                }
+            } else {
+                puts "$file is a directory."
+            }
+        } else {
+            puts "$file does not exist."
+        }
+    }
+    registry::close_file_map
+    
+    return 0
+}
+
+
+proc action_activate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_activate_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[$regref installtype] eq "image" && [registry::run_target $regref activate [array get options]]} {
+                continue
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::activate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port activate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping activate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_deactivate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    set portlist [portlist_sortdependents $portlist]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_deactivate_no-exec)]
+            && ![catch {set ilist [registry::active $portname]}]} {
+
+            set i [lindex $ilist 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            if {$composite_version eq "" || $composite_version == "${iversion}_${irevision}${ivariants}"} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq "image" && [registry::run_target $regref deactivate [array get options]]} {
+                    continue
+                }
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::deactivate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port deactivate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping deactivate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug "action_select \[$portlist] \[$opts]..."
+
+    array set opts_array $opts
+    set commands [array names opts_array ports_select_*]
+    array unset opts_array
+
+    # Error out if no group is specified or command is not --summary.
+    if {[llength $portlist] < 1 && [string map {ports_select_ ""} [lindex $commands 0]] != "summary"} {
+        ui_error "port select \[--list|--set|--show|--summary] \<group> \[<version>]"
+        return 1
+    }
+
+    set group [lindex $portlist 0]
+    
+    # If no command (--set, --show, --list, --summary) is specified *but*
+    #  more than one argument is specified, default to the set command.
+    if {[llength $commands] < 1 && [llength $portlist] > 1} {
+        set command set
+        ui_debug [concat "Although no command was specified, more than " \
+                         "one argument was specified.  Defaulting to the " \
+                         "'set' command..."]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] < 1} {
+        set command list
+        ui_debug [concat "No command was specified. Defaulting to the " \
+                         "'list' command..."]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] > 1} {
+        ui_error [concat "Multiple commands were specified. Only one " \
+                         "command may be specified at a time."]
+        return 1
+    } else {
+        set command [string map {ports_select_ ""} [lindex $commands 0]]
+        ui_debug "The '$command' command was specified."
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'list' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn "Unable to get active selected version: $selected_version"
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error "The 'list' command failed: $versions"
+                return 1
+            }
+
+            ui_notice "Available versions for $group:"
+            foreach v $versions {
+                ui_notice -nonewline "\t"
+                if {$selected_version == $v} {
+                    ui_msg "$v (active)"
+                } else {
+                    ui_msg "$v"
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] < 2} {
+                ui_error [concat "The 'set' command expects two " \
+                                 "arguments: <group>, <version>"]
+                return 1
+            } elseif {[llength $portlist] > 2} {
+                ui_warn [concat "The 'set' command only expects two " \
+                                "arguments. Extra arguments will be " \
+                                "ignored."]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline "Selecting '$version' for '$group' "
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg "failed: $result"
+                return 1
+            }
+            ui_msg "succeeded. '$version' is now active."
+            return 0
+        }
+        show {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'show' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error "The 'show' command failed: $selected_version"
+                return 1
+            }
+            puts [concat "The currently selected version for '$group' is " \
+                         "'$selected_version'."]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] > 0} {
+                ui_warn [concat "The 'summary' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error "The 'summary' command failed: $portgroups"
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr "%-*s  %-*s  %s"
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn "The list of options for the select group $pg could not be obtained: $versions"
+                    continue
+                }
+                # remove "none", sort the list, append none at the end
+                set noneidx [lsearch -exact $versions "none"]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions "none"
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn "The currently selected option for the select group $pg could not be obtained: $selected_version"
+                    continue
+                }
+                set groupdesc(selected) $selected_version
+
+                set w1 [expr {max($w1, [string length $pg])}]
+                set w2 [expr {max($w2, [string length $selected_version])}]
+
+                lappend groups [array get groupdesc]
+                array unset groupdesc
+            }
+            puts [format $formatStr $w1 "Name" $w2 "Selected" "Options"]
+            puts [format $formatStr $w1 "====" $w2 "========" "======="]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) " "]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error "An unknown command '$command' was specified."
+            return 1
+        }
+    }
+}
+
+
+proc action_selfupdate { action portlist opts } {
+    global global_options
+    if { [catch {macports::selfupdate [array get global_options] base_updated} result ] } {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_error "$result"
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg "Please run `port -v selfupdate' for details."
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal "port selfupdate failed: $result"
+    }
+    
+    if {$base_updated} {
+        # exit immediately if in batch/interactive mode
+        return -999
+    } else {
+        return 0
+    }
+}
+
+
+proc action_setrequested { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    # set or unset?
+    set val [string equal $action "setrequested"]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info "Setting requested flag for $portname to $val"
+            foreach i $ilist {
+                set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+                registry::property_store $regref requested $val
+            }
+        } else {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist "yes"] || ([prefix_unwritable] && ![macports::global_option_isset ports_dryrun])} {
+        return 1
+    }
+
+    # shared depscache for all ports in the list
+    array set depscache {}
+    set status 0
+    foreachport $portlist {
+        if {![info exists depscache(port:$portname)]} {
+            set status [macports::upgrade $portname "port:$portname" [array get requested_variations] [array get options] depscache]
+            # status 2 means the port was not found in the index,
+            # status 3 means the port is not installed
+            if {$status != 0 && $status != 2 && $status != 3 && ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 && $status != 2 && $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] && ${macports::revupgrade_autorun} && ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+<<<<<<< HEAD
+    macports::doctor_main
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::doctor_main $opts
+>>>>>>> svn
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+<<<<<<< HEAD
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+>>>>>>> svn
+    macports::reclaim_main  
+    return 0
+}
+
+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 } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Version: "
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Platform: "
+    }
+    puts "${macports::os_platform} ${macports::os_major} ${macports::os_arch}"
+    return 0
+}
+
+
+proc action_dependents { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set ilist {}
+
+    registry::open_dep_map
+
+    set status 0
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if { [catch {set ilist [registry::installed $portname $composite_version]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        } else {
+            # choose the active version if there is one
+            set index 0
+            foreach i $ilist {
+                if {[lindex $i 4]} {
+                    set found 1
+                    break
+                }
+                incr index
+            }
+            if {![info exists found]} {
+                set index 0
+            }
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist $index 0]
+            set iversion [lindex $ilist $index 1]
+            set irevision [lindex $ilist $index 2]
+            set ivariants [lindex $ilist $index 3]
+        }
+        
+        set deplist [registry::list_dependents $portname $iversion $irevision $ivariants]
+        if { [llength $deplist] > 0 } {
+            if {$action eq "rdependents"} {
+                set toplist $deplist
+                while 1 {
+                    set newlist {}
+                    foreach dep $deplist {
+                        set depname [lindex $dep 2]
+                        if {![info exists seen($depname)]} {
+                            set seen($depname) 1
+                            set rdeplist [registry::list_dependents $depname]
+                            foreach rdep $rdeplist {
+                                lappend newlist $rdep
+                            }
+                            set dependentsof($depname) $rdeplist
+                        }
+                    }
+                    if {[llength $newlist] > 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice "The following ports are dependent on ${portname}:"
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos >= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] <= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] && [string is true -strict $options(ports_rdependents_full)])} {
+                        puts "${spaces}${cur_portname}"
+                        set seen($cur_portname) 1
+                        incr cur_pos
+                        set pos_stack [lreplace $pos_stack end end $cur_pos]
+                        if {[info exists dependentsof($cur_portname)]} {
+                            lappend portstack $dependentsof($cur_portname)
+                            lappend pos_stack 0
+                        }
+                        continue
+                    }
+                    incr cur_pos
+                    set pos_stack [lreplace $pos_stack end end $cur_pos]
+                }
+            } else {
+                foreach dep $deplist {
+                    set depport [lindex $dep 2]
+                    if {[macports::ui_isset ports_quiet]} {
+                        ui_msg "$depport"
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg "$depport depends on $portname"
+                    } else {
+                        ui_msg "$depport depends on $portname (by [lindex $dep 1]:)"
+                    }
+                }
+            }
+        } else {
+            ui_notice "$portname has no dependents."
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator ""
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] && [string is true -strict $options(ports_${action}_no-build)]} {
+            set deptypes {depends_lib depends_run}
+        } else {
+            set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+        }
+
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+            # Add any global_variations to the variations
+            # specified for the port, so we get dependencies right
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn "port ${action} --index does not work with the 'current' pseudo-port"
+            continue
+        }
+        set portname $portinfo(name)
+
+        set deplist {}
+        set deps_output {}
+        set ndeps 0
+        array set labeldict {depends_fetch Fetch depends_extract Extract depends_build Build depends_lib Library depends_run Runtime}
+        # get list of direct deps
+        foreach type $deptypes {
+            if {[info exists portinfo($type)]} {
+                if {$action eq "rdeps" || [macports::ui_isset ports_verbose]} {
+                    foreach dep $portinfo($type) {
+                        lappend deplist $dep
+                    }
+                } else {
+                    foreach dep $portinfo($type) {
+                        lappend deplist [lindex [split $dep :] end]
+                    }
+                }
+                if {$action eq "deps"} {
+                    set label "$labeldict($type) Dependencies"
+                    lappend deps_output [wraplabel $label [join $deplist ", "] 0 [string repeat " " 22]]
+                    incr ndeps [llength $deplist]
+                    set deplist {}
+                }
+            }
+        }
+
+        set version $portinfo(version)
+        set revision $portinfo(revision)
+        if {[info exists portinfo(canonical_active_variants)]} {
+            set variants $portinfo(canonical_active_variants)
+        } else {
+            set variants {}
+        }
+
+        puts -nonewline $separator
+        if {$action eq "deps"} {
+            if {$ndeps == 0} {
+                ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+            } else {
+                ui_notice "Full Name: $portname @${version}_${revision}${variants}"
+                puts [join $deps_output "\n"]
+            }
+            set separator "--\n"
+            continue
+        }
+
+        set toplist $deplist
+        # gather all the deps
+        while 1 {
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        break_softcontinue "lookup of portname $depname failed: $result" 1 status
+                    }
+                    if {[llength $result] < 2} {
+                        break_softcontinue "Port $depname not found" 1 status
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                    set options(subport) $portinfo(name)
+                    
+                    # open the portfile if requested
+                    if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug "$::errorInfo"
+                            break_softcontinue "Unable to open port: $result" 1 status
+                        }
+                        array unset portinfo
+                        array set portinfo [mportinfo $mport]
+                        mportclose $mport
+                    }
+                    
+                    # get list of the dep's deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                lappend rdeplist $rdep
+                                lappend newlist $rdep
+                            }
+                        }
+                    }
+                    set depsof($depname) $rdeplist
+                }
+            }
+            if {[llength $newlist] > 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] > 0} {
+            ui_notice "The following ports are dependencies of $portname @${version}_${revision}${variants}:"
+        } else {
+            ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos >= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] <= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] && [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts "${spaces}${cur_port}"
+                } else {
+                    puts "${spaces}${cur_portname}"
+                }
+                set seen($cur_portname) 1
+                incr cur_pos
+                set pos_stack [lreplace $pos_stack end end $cur_pos]
+                if {[info exists depsof($cur_portname)]} {
+                    lappend portstack $depsof($cur_portname)
+                    lappend pos_stack 0
+                }
+                continue
+            }
+            incr cur_pos
+            set pos_stack [lreplace $pos_stack end end $cur_pos]
+        }
+        set separator "--\n"
+    }
+    return $status
+}
+
+
+proc action_uninstall { action portlist opts } {
+    set status 0
+    if {[macports::global_option_isset port_uninstall_old]} {
+        # if -u then uninstall all inactive ports
+        # (union these to any other ports user has in the port list)
+        set portlist [opUnion $portlist [get_inactive_ports]]
+    } else {
+        # Otherwise the user hopefully supplied a portlist, or we'll default to the existing directory
+        if {[require_portlist portlist]} {
+            return 1
+        }
+    }
+    if {[prefix_unwritable]} {
+        return 1
+    }
+
+    set portlist [portlist_sortdependents $portlist]
+
+    foreachport $portlist {
+        if {![registry::entry_exists_for_name $portname]} {
+            # if the code path arrives here the port either isn't installed, or
+            # it doesn't exist at all. We can't be sure, but we can check the
+            # portindex whether a port by that name exists (in which case not
+            # uninstalling it is probably no problem). If there is no port by
+            # that name, alert the user in case of typos.
+            ui_info "$portname is not installed"
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn "no such port: $portname, skipping uninstall"
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set iactive [lindex $i 4]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[registry::run_target $regref uninstall [array get options]]} {
+                continue
+            }
+        }
+
+        if { [catch {registry_uninstall::uninstall_composite $portname $composite_version [array get options]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port uninstall failed: $result" 1 status
+        }
+    }
+
+    return $status
+}
+
+
+proc action_installed { action portlist opts } {
+    global private_options
+    set status 0
+    set restrictedList 0
+    set ilist {}
+    
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreachport $portlist {
+            set composite_version [composite_version $portversion [array get variations]]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port installed failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] > 0 } {
+        ui_notice "The following ports are currently installed:"
+        foreach i [portlist_sortint $ilist] {
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            set extra ""
+            set nvariants ""
+            if {[macports::ui_isset ports_verbose]} {
+                set regref [registry::open_entry $iname $iversion $irevision $ivariants [lindex $i 5]]
+                set nvariants [registry::property_retrieve $regref negated_variants]
+                if {$nvariants == 0} {
+                    set nvariants ""
+                }
+                set os_platform [registry::property_retrieve $regref os_platform]
+                set os_major [registry::property_retrieve $regref os_major]
+                set archs [registry::property_retrieve $regref archs]
+                if {$os_platform != 0 && $os_platform ne "" && $os_major != 0 && $os_major ne ""} {
+                    append extra " platform='$os_platform $os_major'"
+                }
+                if {$archs != 0 && $archs ne ""} {
+                    append extra " archs='$archs'"
+                }
+            }
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}"
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are installed."
+    } else {
+        ui_notice "No ports are installed."
+    }
+
+    return $status
+}
+
+
+proc action_outdated { action portlist opts } {
+    global private_options
+    set status 0
+
+    # If port names were supplied, limit ourselves to those ports, else check all installed ports
+    set ilist {}
+    set restrictedList 0
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreach portspec $portlist {
+            array set port $portspec
+            set portname $port(name)
+            set composite_version [composite_version $port(version) $port(variants)]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port outdated failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] > 0 } {
+        foreach i [portlist_sortint $ilist] {
+        
+            # Get information about the installed port
+            set portname [lindex $i 0]
+            set installed_version [lindex $i 1]
+            set installed_revision [lindex $i 2]
+            set installed_compound "${installed_version}_${installed_revision}"
+
+            set is_active [lindex $i 4]
+            if {$is_active == 0} {
+                continue
+            }
+            set installed_epoch [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+            
+            # Get information about latest available version and revision
+            if {![info exists portinfo(version)]} {
+                ui_warn "$portname has no version field"
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound "${latest_version}_${latest_revision}"
+            set latest_epoch 0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch $portinfo(epoch)
+            }
+            
+            # Compare versions, first checking epoch, then version, then revision
+            set epoch_comp_result [expr {$installed_epoch - $latest_epoch}]
+            set comp_result [vercmp $installed_version $latest_version]
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            set reason ""
+            if {$epoch_comp_result != 0 && $installed_version != $latest_version} {
+                if {($comp_result >= 0 && $epoch_comp_result < 0) || ($comp_result <= 0 && $epoch_comp_result > 0)} {
+                    set reason { (epoch $installed_epoch $relation $latest_epoch)}
+                }
+                set comp_result $epoch_comp_result
+            } elseif {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision [lindex $i 3] $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                    set reason { (platform $os_platform_installed $os_major_installed != ${macports::os_platform} ${macports::os_major})}
+                }
+            }
+            
+            # Report outdated (or, for verbose, predated) versions
+            if { $comp_result != 0 } {
+                            
+                # Form a relation between the versions
+                set flag ""
+                if { $comp_result > 0 } {
+                    set relation ">"
+                    set flag "!"
+                } else {
+                    set relation "<"
+                }
+                
+                # Emit information
+                if {$comp_result < 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice "The following installed ports are outdated:"
+                    }
+                    incr num_outdated
+
+                    puts [format "%-30s %-24s %1s" $portname "$installed_compound $relation $latest_compound [subst $reason]" $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice "No installed ports are outdated."
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are outdated."
+    } else {
+        ui_notice "No ports are installed."
+    }
+    
+    return $status
+}
+
+
+proc action_contents { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {[info exists global_options(ports_contents_size)]} {
+        set units {}
+        if {[info exists global_options(ports_contents_units)]} {
+            set units [complete_size_units $global_options(ports_contents_units)]
+        }
+        set outstring {[format "%12s $file" [filesize $file $units]]}
+    } else {
+        set outstring {  $file}
+    }
+
+    foreachport $portlist {
+        if { ![catch {set ilist [registry::installed $portname]} result] } {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0 0]
+        }
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                ui_notice "Port $portname contains:"
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice "Port $portname does not contain any files or is not active."
+            }
+        } else {
+            ui_notice "Port $portname is not installed."
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq "K" || $units eq "Ki"} {
+        return "KiB"
+    } elseif {$units eq "k"} {
+        return "kB"
+    } elseif {$units eq "Mi"} {
+        return "MiB"
+    } elseif {$units eq "M"} {
+        return "MB"
+    } elseif {$units eq "Gi"} {
+        return "GiB"
+    } elseif {$units eq "G"} {
+        return "GB"
+    } else {
+        return $units
+    }
+}
+
+# Show space used by the given ports' files
+proc action_space {action portlist opts} {
+    global global_options
+    require_portlist portlist
+
+    set units {}
+    if {[info exists global_options(ports_space_units)]} {
+        set units [complete_size_units $global_options(ports_space_units)]
+    }
+    set spaceall 0.0
+    foreachport $portlist {
+        set space 0.0
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne "yes"} {
+                    set msg "[bytesize $space $units] $portname"
+                    if { $portversion != {} } {
+                        append msg " @$portversion"
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr "Port $portname does not contain any file or is not active."
+            }
+        } else {
+            puts stderr "Port $portname is not installed."
+        }
+    }
+    if {[llength $portlist] > 1 || ([info exists options(ports_space_total)] && $options(ports_space_total) eq "yes")} {
+        puts "[bytesize $spaceall $units] total"
+    }
+    return 0
+}
+
+proc action_variants { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] && $options(ports_variants_index) eq "yes")} {
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "port variants --index does not work with 'current' pseudo-port"
+            continue
+        }
+
+        # set portname again since the one we were passed may not have had the correct case
+        set portname $portinfo(name)
+
+        # if this fails the port doesn't have any variants
+        if {![info exists portinfo(variants)]} {
+            ui_notice "$portname has no variants"
+        } else {
+            array unset vinfo
+            # Use the new format if it exists.
+            if {[info exists portinfo(vinfo)]} {
+                array set vinfo $portinfo(vinfo)
+            # Otherwise fall back to the old format.
+            } elseif {[info exists portinfo(variant_desc)]} {
+                array set vdescriptions $portinfo(variant_desc)
+            }
+
+            # print out all the variants
+            ui_notice "$portname has the variants:"
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier "   "
+                # Retrieve variants' information from the new format.
+                if {[info exists vinfo]} {
+                    array unset variant
+                    array set variant $vinfo($v)
+
+                    # Retrieve conflicts, description, is_default, and
+                    # vrequires.
+                    if {[info exists variant(conflicts)]} {
+                        set vconflicts $variant(conflicts)
+                    }
+                    if {[info exists variant(description)]} {
+                        set vdescription $variant(description)
+                    }
+
+                    # XXX Keep these varmodifiers in sync with action_info, or create a wrapper for it
+                    if {[info exists variations($v)]} {
+                        set varmodifier "  $variations($v)"
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier "($global_variations($v))"
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier "\[$variant(is_default)\]"
+                    }
+                    if {[info exists variant(requires)]} {
+                        set vrequires $variant(requires)
+                    }
+                # Retrieve variants' information from the old format,
+                # which only consists of the description.
+                } elseif {[info exists vdescriptions($v)]} {
+                    set vdescription $vdescriptions($v)
+                }
+
+                if {[info exists vdescription]} {
+                    puts [wraplabel "$varmodifier$v" [string trim $vdescription] 0 [string repeat " " [expr 5 + [string length $v]]]]
+                } else {
+                    puts "$varmodifier$v"
+                }
+                if {[info exists vconflicts]} {
+                    puts "     * conflicts with [string trim $vconflicts]"
+                }
+                if {[info exists vrequires]} {
+                    puts "     * requires [string trim $vrequires]"
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        ui_error "You must specify a search pattern"
+        return 1
+    }
+
+    # Copy global options as we are going to modify the array
+    array set options [array get global_options]
+
+    if {[info exists options(ports_search_depends)] && $options(ports_search_depends) eq "yes"} {
+        array unset options ports_search_depends
+        set options(ports_search_depends_fetch) yes
+        set options(ports_search_depends_extract) yes
+        set options(ports_search_depends_build) yes
+        set options(ports_search_depends_lib) yes
+        set options(ports_search_depends_run) yes
+    }
+
+    # Array to hold given filters
+    array set filters {}
+    # Default matchstyle
+    set filter_matchstyle "none"
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne "yes" } {
+            continue
+        }
+        switch -- $opt {
+            exact -
+            glob {
+                set filter_matchstyle $opt
+                continue
+            }
+            regex {
+                set filter_matchstyle regexp
+                continue
+            }
+            case-sensitive {
+                set filter_case yes
+                continue
+            }
+            line {
+                continue
+            }
+        }
+
+        set filters($opt) "yes"
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) "yes"
+        set filters(description) "yes"
+    }
+
+    set separator ""
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq "none"} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first "*" $portname] == -1 && [string first "?" $portname] == -1} {
+                set searchstring "*$portname*"
+            }
+            set matchstyle glob
+        }
+
+        set res {}
+        set portfound 0
+        foreach { opt } [array get filters] {
+            # Map from friendly name
+            set opt [map_friendly_field_names $opt]
+
+            if {[catch {eval set matches \[mportsearch \$searchstring $filter_case \$matchstyle $opt\]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for name $portname failed: $result" 1 status
+            }
+
+            set tmp {}
+            foreach {name info} $matches {
+                add_to_portlist tmp [concat [list name $name] $info]
+            }
+            set res [opUnion $res $tmp]
+        }
+        set res [portlist_sort $res]
+
+        set joiner ""
+        foreach info $res {
+            array unset portinfo
+            array set portinfo $info
+
+            # XXX is this the right place to verify an entry?
+            if {![info exists portinfo(name)]} {
+                puts stderr "Invalid port entry, missing portname"
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing description"
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing version"
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        && $options(ports_search_line) eq "yes"} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts "$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)"
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts "$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)"
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline "$portinfo(name) @$portinfo(version)"
+                    if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                        puts -nonewline "_$portinfo(revision)"
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline " ([join $portinfo(categories) ", "])"
+                    }
+                    puts ""
+                    puts [wrap [join $portinfo(description)] 0 [string repeat " " 4]]
+                }
+            }
+
+            set joiner "\n"
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice "No match for $portname found"
+        } elseif {[llength $res] > 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne "yes")} {
+                ui_notice "\nFound [llength $res] ports."
+            }
+        }
+
+        set separator "--\n"
+    }
+
+    array unset options
+    array unset filters
+
+    return $status
+}
+
+
+proc action_list { action portlist opts } {
+    global private_options
+    set status 0
+    
+    # Default to list all ports if no portnames are supplied
+    if { ![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        add_to_portlist portlist [list name "-all-"]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq "-all-"} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "listing all ports failed: $result" 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $search_string failed: $result" 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir ""
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format "%-30s @%-14s %s" $portinfo(name) $portinfo(version) $outdir]
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_echo { action portlist opts } {
+    global global_options
+
+    # Simply echo back the port specs given to this command
+    foreachport $portlist {
+        if {![macports::ui_isset ports_quiet]} {
+            set opts {}
+            foreach { key value } [array get options] {
+                if {![info exists global_options($key)]} {
+                    lappend opts "$key=$value"
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne "" } {
+                set ver_field "@$composite_version"
+            } else {
+                set ver_field ""
+            }
+            puts [format "%-30s %s %s" $portname $ver_field  [join $opts " "]]
+        } else {
+            puts "$portname"
+        }
+    }
+
+    return 0
+}
+
+
+proc action_portcmds { action portlist opts } {
+    # Operations on the port's directory and Portfile
+    global env boot_env current_portdir
+
+    array set local_options $opts
+    
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific, otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+            set portname $portinfo(name)
+        }
+        
+        
+        # Calculate portdir, porturl, and portfile from initial porturl
+        set portdir [file normalize [macports::getportdir $porturl]]
+        set porturl "file://${portdir}";    # Rebuild url so it's fully qualified
+        set portfile "${portdir}/Portfile"
+        
+        # Now execute the specific action
+        if {[file readable $portfile]} {
+            switch -- $action {
+                cat {
+                    # Copy the portfile to standard output
+                    set f [open $portfile RDONLY]
+                    while { ![eof $f] } {
+                        puts -nonewline [read $f 4096]
+                    }
+                    close $f
+                }
+                
+                edit {
+                    # Edit the port's portfile with the user's editor
+                    
+                    # Restore our entire environment from start time.
+                    # We need it to evaluate the editor, and the editor
+                    # may want stuff from it as well, like TERM.
+                    array unset env_save; array set env_save [array get env]
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor ""
+                    set editor_var "ports_${action}_editor"
+                    if {[info exists local_options($editor_var)]} {
+                        set editor [join $local_options($editor_var)]
+                    } else {
+                        foreach ed { MP_EDITOR VISUAL EDITOR } {
+                            if {[info exists env($ed)]} {
+                                set editor $env($ed)
+                                break
+                            }
+                        }
+                    }
+                    
+                    # Use a reasonable canned default if no editor specified or set in env
+                    if { $editor eq "" } { set editor "/usr/bin/vi" }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec >@stdout <@stdin 2>@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug "$errorInfo"
+                        break_softcontinue "unable to invoke editor $editor: $result" 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get env_save]
+                }
+
+                dir {
+                    # output the path to the port's directory
+                    puts $portdir
+                }
+
+                work {
+                    # output the path to the port's work directory
+                    set workpath [macports::getportworkpath_from_portdir $portdir $portname]
+                    if {[file exists $workpath]} {
+                        puts $workpath
+                    }
+                }
+
+                cd {
+                    # Change to the port's directory, making it the default
+                    # port for any future commands
+                    set current_portdir $portdir
+                }
+
+                url {
+                    # output the url of the port's directory, suitable to feed back in later as a port descriptor
+                    puts $porturl
+                }
+
+                file {
+                    # output the path to the port's portfile
+                    puts $portfile
+                }
+
+                logfile {
+                    set logfile [file join [macports::getportlogpath $portdir $portname] "main.log"]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error "Log file not found for port in $portdir"
+                    }
+                }
+
+                gohome {
+                    set homepage ""
+
+                    # Get the homepage as read from PortIndex
+                    if {[info exists portinfo(homepage)]} {
+                        set homepage $portinfo(homepage)
+                    }
+
+                    # If not available, get the homepage for the port by opening the Portfile
+                    if {$homepage eq "" && ![catch {set ctx [mportopen $porturl]} result]} {
+                        array set portinfo [mportinfo $ctx]
+                        if {[info exists portinfo(homepage)]} {
+                            set homepage $portinfo(homepage)
+                        }
+                        mportclose $ctx
+                    }
+
+                    # Try to open a browser to the homepage for the given port
+                    if { $homepage ne "" } {
+                        if {[catch {system "${macports::autoconf::open_path} '$homepage'"} result]} {
+                            global errorInfo
+                            ui_debug "$errorInfo"
+                            break_softcontinue "unable to invoke browser using ${macports::autoconf::open_path}: $result" 1 status
+                        }
+                    } else {
+                        ui_error [format "No homepage for %s" $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue "Could not read $portfile" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_sync { action portlist opts } {
+    global global_options
+
+    set status 0
+    if {[catch {mportsync [array get global_options]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_msg "port sync failed: $result"
+        set status 1
+    }
+    
+    return $status
+}
+
+
+proc action_target { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {($action eq "install" || $action eq "archive") && [prefix_unwritable] && ![macports::global_option_isset ports_dryrun]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn "Skipping $portname (not in the ports tree)"
+                    continue
+                } else {
+                    break_softcontinue "Port $portname not found" 1 status
+                }
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+        }
+
+        # use existing variants iff none were explicitly requested
+        if {[array get requested_variations] eq "" && [array get variations] ne ""} {
+            array unset requested_variations
+            array set requested_variations [array get variations]
+        }
+
+        # Add any global_variations to the variations
+        # specified for the port
+        foreach { variation value } [array get global_variations] {
+            if { ![info exists requested_variations($variation)] } {
+                set requested_variations($variation) $value
+            }
+        }
+
+        # If version was specified, save it as a version glob for use
+        # in port actions (e.g. clean).
+        if {[string length $portversion]} {
+            set options(ports_version_glob) $portversion
+        }
+        # if installing, mark the port as explicitly requested
+        if {$action eq "install"} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq "archive"} {
+            set target install
+        } else {
+            set target $action
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+        if {[catch {set workername [mportopen $porturl [array get options] [array get requested_variations]]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to open port: $result" 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to execute port: $result" 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue "Processing of port $portname failed" 1 status
+        }
+    }
+    
+    if {$status == 0 && $action eq "install" && ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] && ![info exists options(ports_install_no-rev-upgrade)] && ${macports::revupgrade_autorun}} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+
+proc action_exit { action portlist opts } {
+    # Return a semaphore telling the main loop to quit
+    return -999
+}
+
+
+##########################################
+# Command Parsing
+##########################################
+proc moreargs {} {
+    global cmd_argn cmd_argc
+    return [expr {$cmd_argn < $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn < $cmd_argc} {
+        return [lindex $cmd_argv $cmd_argn]
+    } else {
+        return _EOF_
+    }
+}
+
+
+proc advance {} {
+    global cmd_argn
+    incr cmd_argn
+}
+
+
+proc match s {
+    if {[lookahead] == $s} {
+        advance
+        return 1
+    }
+    return 0
+}
+
+# action_array specifies which action to run on the given command
+# and if the action wants an expanded portlist.
+# The value is a list of the form {action expand},
+# where action is a string and expand a value:
+#   0 none        Does not expect any text argument
+#   1 strings     Expects some strings as text argument
+#   2 ports       Wants an expanded list of ports as text argument
+global action_array
+
+# Define global constants
+const ACTION_ARGS_NONE 0
+const ACTION_ARGS_STRINGS 1
+const ACTION_ARGS_PORTS 2
+
+array set action_array [list \
+    usage       [list action_usage          [ACTION_ARGS_STRINGS]] \
+    help        [list action_help           [ACTION_ARGS_STRINGS]] \
+    \
+    echo        [list action_echo           [ACTION_ARGS_PORTS]] \
+    \
+    info        [list action_info           [ACTION_ARGS_PORTS]] \
+    location    [list action_location       [ACTION_ARGS_PORTS]] \
+    notes       [list action_notes          [ACTION_ARGS_PORTS]] \
+    provides    [list action_provides       [ACTION_ARGS_STRINGS]] \
+    log         [list action_log            [ACTION_ARGS_PORTS]] \
+    \
+    activate    [list action_activate       [ACTION_ARGS_PORTS]] \
+    deactivate  [list action_deactivate     [ACTION_ARGS_PORTS]] \
+    \
+    select      [list action_select         [ACTION_ARGS_STRINGS]] \
+    \
+    sync        [list action_sync           [ACTION_ARGS_NONE]] \
+    selfupdate  [list action_selfupdate     [ACTION_ARGS_NONE]] \
+    \
+    setrequested   [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    unsetrequested [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    \
+    upgrade     [list action_upgrade        [ACTION_ARGS_PORTS]] \
+    rev-upgrade [list action_revupgrade     [ACTION_ARGS_NONE]] \
+    reclaim     [list action_reclaim        [ACTION_ARGS_NONE]] \
+    doctor      [list action_doctor         [ACTION_ARGS_NONE]] \
+    \
+    version     [list action_version        [ACTION_ARGS_NONE]] \
+    platform    [list action_platform       [ACTION_ARGS_NONE]] \
+    \
+    uninstall   [list action_uninstall      [ACTION_ARGS_PORTS]] \
+    \
+    installed   [list action_installed      [ACTION_ARGS_PORTS]] \
+    outdated    [list action_outdated       [ACTION_ARGS_PORTS]] \
+    contents    [list action_contents       [ACTION_ARGS_PORTS]] \
+    space       [list action_space          [ACTION_ARGS_PORTS]] \
+    dependents  [list action_dependents     [ACTION_ARGS_PORTS]] \
+    rdependents [list action_dependents     [ACTION_ARGS_PORTS]] \
+    deps        [list action_deps           [ACTION_ARGS_PORTS]] \
+    rdeps       [list action_deps           [ACTION_ARGS_PORTS]] \
+    variants    [list action_variants       [ACTION_ARGS_PORTS]] \
+    \
+    search      [list action_search         [ACTION_ARGS_STRINGS]] \
+    list        [list action_list           [ACTION_ARGS_PORTS]] \
+    \
+    edit        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cat         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    dir         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    work        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cd          [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    url         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    file        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    logfile     [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    gohome      [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    \
+    fetch       [list action_target         [ACTION_ARGS_PORTS]] \
+    checksum    [list action_target         [ACTION_ARGS_PORTS]] \
+    extract     [list action_target         [ACTION_ARGS_PORTS]] \
+    patch       [list action_target         [ACTION_ARGS_PORTS]] \
+    configure   [list action_target         [ACTION_ARGS_PORTS]] \
+    build       [list action_target         [ACTION_ARGS_PORTS]] \
+    destroot    [list action_target         [ACTION_ARGS_PORTS]] \
+    install     [list action_target         [ACTION_ARGS_PORTS]] \
+    clean       [list action_target         [ACTION_ARGS_PORTS]] \
+    test        [list action_target         [ACTION_ARGS_PORTS]] \
+    lint        [list action_target         [ACTION_ARGS_PORTS]] \
+    livecheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    distcheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    mirror      [list action_target         [ACTION_ARGS_PORTS]] \
+    load        [list action_target         [ACTION_ARGS_PORTS]] \
+    unload      [list action_target         [ACTION_ARGS_PORTS]] \
+    distfiles   [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    archivefetch [list action_target         [ACTION_ARGS_PORTS]] \
+    archive     [list action_target         [ACTION_ARGS_PORTS]] \
+    unarchive   [list action_target         [ACTION_ARGS_PORTS]] \
+    dmg         [list action_target         [ACTION_ARGS_PORTS]] \
+    mdmg        [list action_target         [ACTION_ARGS_PORTS]] \
+    dpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    mpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    pkg         [list action_target         [ACTION_ARGS_PORTS]] \
+    portpkg     [list action_target         [ACTION_ARGS_PORTS]] \
+    rpm         [list action_target         [ACTION_ARGS_PORTS]] \
+    srpm        [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    quit        [list action_exit           [ACTION_ARGS_NONE]] \
+    exit        [list action_exit           [ACTION_ARGS_NONE]] \
+]
+
+# Expand "action".
+# Returns an action proc, or a list of matching action procs, or the action passed in
+proc find_action { action } {
+    global action_array
+    
+    if { ! [info exists action_array($action)] } {
+        set guess [guess_action $action]
+        if { [info exists action_array($guess)] } {
+            return $guess
+        }
+        return $guess
+    }
+    
+    return $action
+}
+
+# Expand action
+# If there's more than one match, return the next possibility
+proc find_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    } else {
+        set action [complete_action $action]
+        if { [info exists action_array($action)] } {
+            set action_proc [lindex $action_array($action) 0]
+        }
+    }
+    
+    return $action_proc
+}
+
+proc get_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    }
+    
+    return $action_proc
+}
+
+# Returns whether an action expects text arguments at all,
+# expects text arguments or wants an expanded list of ports
+# Return values are constants:
+#   [ACTION_ARGS_NONE]     Does not expect any text argument
+#   [ACTION_ARGS_STRINGS]  Expects some strings as text argument
+#   [ACTION_ARGS_PORTS]    Wants an expanded list of ports as text argument
+proc action_needs_portlist { action } {
+    global action_array
+
+    set ret 0
+    if {[info exists action_array($action)]} {
+        set ret [lindex $action_array($action) 1]
+    }
+
+    return $ret
+}
+
+# cmd_opts_array specifies which arguments the commands accept
+# Commands not listed here do not accept any arguments
+# Syntax if {option argn}
+# Where option is the name of the option and argn specifies how many arguments
+# this argument takes
+global cmd_opts_array
+array set cmd_opts_array {
+    edit        {{editor 1}}
+    info        {category categories depends_fetch depends_extract
+                 depends_build depends_lib depends_run
+                 depends description epoch fullname heading homepage index license
+                 line long_description
+                 maintainer maintainers name platform platforms portdir pretty
+                 replaced_by revision subports variant variants version}
+    contents    {size {units 1}}
+    deps        {index no-build}
+    rdeps       {index no-build full}
+    rdependents {full}
+    search      {case-sensitive category categories depends_fetch
+                 depends_extract depends_build depends_lib depends_run
+                 depends description epoch exact glob homepage line
+                 long_description maintainer maintainers name platform
+                 platforms portdir regex revision variant variants version}
+    selfupdate  {nosync}
+    space       {{units 1} total}
+    activate    {no-exec}
+    deactivate  {no-exec}
+    install     {no-rev-upgrade unrequested}
+    uninstall   {follow-dependents follow-dependencies no-exec}
+    variants    {index}
+    clean       {all archive dist work logs}
+    mirror      {new}
+    lint        {nitpick}
+    select      {list set show summary}
+    log         {{phase 1} {level 1}}
+    upgrade     {force enforce-variants no-replace no-rev-upgrade}
+    rev-upgrade {id-loadcmd-check}
+    doctor      {quiet}
+}
+
+##
+# Checks whether the given option is valid
+#
+# @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} {
+    global cmd_opts_array
+
+    # This could be so easy with lsearch -index,
+    # but that's only available as of Tcl 8.5
+
+    if {![info exists cmd_opts_array($action)]} {
+        return {}
+    }
+
+    set result {}
+
+    foreach item $cmd_opts_array($action) {
+        if {[llength $item] == 1} {
+            set name $item
+            set argc 0
+        } else {
+            set name [lindex $item 0]
+            set argc [lindex $item 1]
+        }
+
+        if {$name == $option} {
+            set result [list [list $name $argc]]
+            break
+        } elseif {[string first $option $name] == 0} {
+            lappend result [list $name $argc]
+        }
+    }
+
+    return $result
+}
+
+# Parse global options
+#
+# Note that this is called several times:
+#   (1) Initially, to parse options that will be constant across all commands
+#       (options that come prior to any command, frozen into global_options_base)
+#   (2) Following each command (to parse options that will be unique to that command
+#       (the global_options array is reset to global_options_base prior to each command)
+#
+proc parse_options { action ui_options_name global_options_name } {
+    upvar $ui_options_name ui_options
+    upvar $global_options_name global_options
+    global cmdname cmd_opts_array
+    
+    while {[moreargs]} {
+        set arg [lookahead]
+        
+        if {[string index $arg 0] ne "-"} {
+            break
+        } elseif {[string index $arg 1] eq "-"} {
+            # Process long arguments
+            switch -- $arg {
+                -- { # This is the options terminator; do no further option processing
+                    advance; break
+                }
+                default {
+                    set key [string range $arg 2 end]
+                    set kopts [cmd_option_matches $action $key]
+                    if {[llength $kopts] == 0} {
+                        return -code error "${action} does not accept --${key}"
+                    } elseif {[llength $kopts] > 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst "--[lindex $e 0]"
+                        }
+                        return -code error "\"port ${action} --${key}\" is ambiguous: \n  port ${action} [join $errlst "\n  port ${action} "]"
+                    }
+                    set key   [lindex $kopts 0 0]
+                    set kargc [lindex $kopts 0 1]
+                    if {$kargc == 0} {
+                        set global_options(ports_${action}_${key}) yes
+                    } else {
+                        set args {}
+                        while {[moreargs] && $kargc > 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc > 0} {
+                            return -code error "--${key} expects [expr {$kargc + [llength $args]}] parameters!"
+                        }
+                        set global_options(ports_${action}_${key}) $args
+                    }
+                }
+            }
+        } else {
+            # Process short arg(s)
+            set opts [string range $arg 1 end]
+            foreach c [split $opts {}] {
+                switch -- $c {
+                    v {
+                        set ui_options(ports_verbose) yes
+                    }
+                    d {
+                        set ui_options(ports_debug) yes
+                        # debug implies verbose
+                        set ui_options(ports_verbose) yes
+                    }
+                    q {
+                        set ui_options(ports_quiet) yes
+                    }
+                    p {
+                        # Ignore errors while processing within a command
+                        set ui_options(ports_processall) yes
+                    }
+                    f {
+                        set global_options(ports_force) yes
+                    }
+                    o {
+                        set global_options(ports_ignore_different) yes
+                    }
+                    n {
+                        set global_options(ports_nodeps) yes
+                    }
+                    u {
+                        set global_options(port_uninstall_old) yes
+                    }
+                    R {
+                        set global_options(ports_do_dependents) yes
+                    }
+                    s {
+                        set global_options(ports_source_only) yes
+                    }
+                    b {
+                        set global_options(ports_binary_only) yes
+                    }
+                    c {
+                        set global_options(ports_autoclean) yes
+                    }
+                    k {
+                        set global_options(ports_autoclean) no
+                    }
+                    t {
+                        set global_options(ports_trace) yes
+                    }
+                    y {
+                        set global_options(ports_dryrun) yes
+                    }
+                    F {
+                        # Name a command file to process
+                        advance
+                        if {[moreargs]} {
+                            lappend ui_options(ports_commandfiles) [lookahead]
+                        }
+                    }
+                    D {
+                        advance
+                        if {[moreargs]} {
+                            cd [lookahead]
+                        }
+                        break
+                    }
+                    default {
+                        print_usage; exit 1
+                    }
+                }
+            }
+        }
+
+        advance
+    }
+}
+
+# acquire exclusive registry lock for actions that need it
+# returns 1 if locked, 0 otherwise
+proc lock_reg_if_needed {action} {
+    switch -- $action {
+        activate -
+        deactivate -
+        setrequested -
+        unsetrequested -
+        upgrade -
+        uninstall -
+        install {
+            registry::exclusive_lock
+            return 1
+        }
+    }
+    return 0
+}
+
+proc process_cmd { argv } {
+    global cmd_argc cmd_argv cmd_argn \
+           global_options global_options_base private_options ui_options \
+           current_portdir
+    set cmd_argv $argv
+    set cmd_argc [llength $argv]
+    set cmd_argn 0
+
+    set action_status 0
+
+    # Process an action if there is one
+    while {($action_status == 0 || [macports::ui_isset ports_processall]) && [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == ";" } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == "#" } {
+            while { [moreargs] } { advance }
+            break
+        }
+
+        set locked [lock_reg_if_needed $action]
+        # Always start out processing an action in current_portdir
+        cd $current_portdir
+        
+        # Reset global_options from base before each action, as we munge it just below...
+        array unset global_options
+        array set global_options $global_options_base
+        
+        # Find an action to execute
+        set actions [find_action $action]
+        if {[llength $actions] == 1} {
+            set action [lindex $actions 0]
+            set action_proc [get_action_proc $action]
+        } else {
+            if {[llength $actions] > 1} {
+                ui_error "\"port ${action}\" is ambiguous: \n  port [join $actions "\n  port "]"
+            } else {
+                ui_error "Unrecognized action \"port $action\""
+            }
+            set action_status 1
+            break
+        }
+
+        # Parse options that will be unique to this action
+        # (to avoid abiguity with -variants and a default port, either -- must be
+        # used to terminate option processing, or the pseudo-port current must be specified).
+        if {[catch {parse_options $action ui_options global_options} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            ui_error $result
+            set action_status 1
+            break
+        }
+
+        # What kind of arguments does the command expect?
+        set expand [action_needs_portlist $action]
+
+        # Parse action arguments, setting a special flag if there were none
+        # We otherwise can't tell the difference between arguments that evaluate
+        # to the empty set, and the empty set itself.
+        set portlist {}
+        switch -- [lookahead] {
+            ;       -
+            _EOF_ {
+                set private_options(ports_no_args) yes
+            }
+            default {
+                if {[ACTION_ARGS_NONE] == $expand} {
+                    ui_error "$action does not accept string arguments"
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] && ![match ";"] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error "Improper expression syntax while processing parameters"
+                        set action_status 1
+                        break
+                    }
+                }
+            }
+        }
+        
+        # execute the action
+        set action_status [$action_proc $action $portlist [array get global_options]]
+
+        # unlock if needed
+        if {$locked} {
+            registry::exclusive_unlock
+        }
+
+        # Print notifications of just-activated ports.
+        portclient::notifications::display
+
+        # semaphore to exit
+        if {$action_status == -999} break
+    }
+    
+    return $action_status
+}
+
+
+proc complete_portname { text state } { 
+    global complete_choices complete_position
+    
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices {}
+
+        # Build a list of ports with text as their prefix
+        if {[catch {set res [mportsearch "${text}*" false glob]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "search for portname $pattern failed: $result"
+        }
+        foreach {name info} $res {
+            lappend complete_choices $name
+        }
+    }
+    
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+    
+    return $word
+}
+
+
+# return text action beginning with $text
+proc complete_action { text state } {   
+    global action_array complete_choices complete_position
+
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices [array names action_array "[string tolower $text]*"]
+    }
+
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+
+    return $word
+}
+
+# return all actions beginning with $text
+proc guess_action { text } {   
+    global action_array
+
+    return [array names action_array "[string tolower $text]*"]
+
+    if { [llength $complete_choices ] == 1 } {
+        return [lindex $complete_choices 0]
+    }
+
+    return {}
+}
+
+proc attempt_completion { text word start end } {
+    # If the word starts with '~', or contains '.' or '/', then use the build-in
+    # completion to complete the word
+    if { [regexp {^~|[/.]} $word] } {
+        return ""
+    }
+
+    # Decide how to do completion based on where we are in the string
+    set prefix [string range $text 0 [expr {$start - 1}]]
+    
+    # If only whitespace characters preceed us, or if the
+    # previous non-whitespace character was a ;, then we're
+    # an action (the first word of a command)
+    if { [regexp {(^\s*$)|(;\s*$)} $prefix] } {
+        return complete_action
+    }
+    
+    # Otherwise, do completion on portname
+    return complete_portname
+}
+
+
+proc get_next_cmdline { in out use_readline prompt linename } {
+    upvar $linename line
+    
+    set line ""
+    while { $line eq "" } {
+
+        if {$use_readline} {
+            set len [readline read -attempted_completion attempt_completion line $prompt]
+        } else {
+            puts -nonewline $out $prompt
+            flush $out
+            set len [gets $in line]
+        }
+
+        if { $len < 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline && $line ne "" } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in "stdin"]
+    set name "port"
+    set use_readline [expr {$isstdin && [readline init $name]}]
+    set history_file [file normalize "${macports::macports_user_dir}/history"]
+
+    # Read readline history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin && ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts "MacPorts [macports::version]"
+        puts "Entering interactive mode... (\"help\" for help, \"quit\" to quit)"
+    }
+
+    # Main command loop
+    set exit_status 0
+    while { $exit_status == 0 || $isstdin || [macports::ui_isset ports_processall] } {
+
+        # Calculate our prompt
+        if { $noisy } {
+            set shortdir [eval file join [lrange [file split $current_portdir] end-1 end]]
+            set prompt "\[$shortdir\] > "
+        } else {
+            set prompt ""
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] <= 0  } {
+            puts ""
+            break
+        }
+
+        # Process the command
+        set exit_status [process_cmd $line]
+        
+        # Check for semaphore to exit
+        if {$exit_status == -999} {
+            set exit_status 0
+            break
+        }
+    }
+
+    # Create macports user directory if it does not exist yet
+    if {$use_readline && ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts "Goodbye"
+    }
+
+    return $exit_status
+}
+
+
+proc process_command_files { filelist } {
+    set exit_status 0
+
+    # For each file in the command list, process commands
+    # in the file
+    foreach file $filelist {
+        if {$file eq "-"} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal "Failed to open command file; $result"
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne "stdin"} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 && ![macports::ui_isset ports_processall]} {
+            return $exit_status
+        }
+    }
+
+    return $exit_status
+}
+
+namespace eval portclient::progress {
+    ##
+    # Maximum width of the progress bar or indicator when displaying it.
+    variable maxWidth 50
+
+    ##
+    # The start time of the last progress callback as returned by [clock time].
+    # Since only one progress indicator is active at a time, this variable is
+    # shared between the different variants of progress functions.
+    variable startTime
+
+    ##
+    # Delay in milliseconds after the start of the operation before deciding
+    # that showing a progress bar makes sense.
+    variable showTimeThreshold 500
+
+    ##
+    # Percentage value between 0 and 1 that must not have been reached yet when
+    # $showTimeThreshold has passed for a progress bar to be shown. If the
+    # operation has proceeded above e.g. 75% after 500ms we won't bother
+    # displaying a progress indicator anymore -- the operation will be finished
+    # in well below a second anyway.
+    variable showPercentageThreshold 0.75
+
+    ##
+    # Boolean indication whether the progress indicator should be shown or is
+    # still hidden because the current operation didn't need enough time for
+    # a progress indicator to make sense, yet.
+    variable show no
+
+    ##
+    # Initialize the progress bar display delay; call this from the start
+    # action of the progress functions.
+    proc initDelay {} {
+        variable show
+        variable startTime
+
+        set startTime [clock milliseconds]
+        set show no
+    }
+
+    ##
+    # Determine whether a progress bar should be shown for the current
+    # operation in its current state. You must have called initDelay for the
+    # current operation before calling this method.
+    #
+    # @param cur
+    #        Current progress in abstract units.
+    # @param total
+    #        Total number of abstract units to be processed, if known. Pass
+    #        0 if unknown.
+    # @return
+    #        "yes", if the progress indicator should be shown, "no" otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq "yes"} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] > $showTimeThreshold &&
+                ($total == 0 || [expr {double($cur) / double($total)}] < $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of "start", "update", "intermission" or "finish", where start
+    #        will be called before any number of update calls, interrupted by
+    #        any number of intermission calls (called because other output is
+    #        being produced), followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        "intermission" and "finish", the args are empty and unused. For
+    #        "update", args contains $cur and $total, where $cur is the current
+    #        number of units processed and $total is the total number of units
+    #        to be processed. If the total is not known, it is 0.
+    proc generic {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {now total} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            progressbar $now $total [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        } else {
+                            unprogressbar [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        }
+                    }
+                }
+            }
+            intermission -
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of "start", "update" or "finish", where start will be called
+    #        before any number of update calls, followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        contains a single argument "ul" or "dl" indicating whether this is
+    #        an up- or download. For "update", contains the arguments
+    #        ("ul"|"dl") $total $now $speed where ul/dl are as for start, and
+    #        total, now and speed are doubles indicating the total transfer
+    #        size, currently transferred amount and average speed per second in
+    #        bytes. Unused for "finish".
+    proc download {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {type total now speed} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format "        speed: %-13s" "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format " %-10s     speed: %-13s" [bytesize $now {} "%6.1f"] "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            unprogressbar $barLen $barPrefix $barSuffix
+                        }
+                    }
+                }
+            }
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Draw a progress bar using unicode block drawing characters
+    #
+    # @param current
+    #        The current progress value.
+    # @param total
+    #        The progress value representing 100%.
+    # @param width
+    #        The width in characters of the progress bar. This includes percentage
+    #        output, which takes up 8 characters.
+    # @param prefix
+    #        Prefix to be printed in front of the progress bar.
+    # @param suffix
+    #        Suffix to be printed after the progress bar.
+    proc progressbar {current total width {prefix ""} {suffix ""}} {
+        # Subtract the width of the percentage output, also subtract the two
+        # characters [ and ] bounding the progress bar.
+        set percentageWidth 8
+        set barWidth      [expr {entier($width) - $percentageWidth - 2}]
+
+        # Map the range (0, $total) to (0, 4 * $width) where $width is the maximum
+        # numebr of characters to be printed for the progress bar. Multiply the
+        # upper bound with 8 because we have 8 sub-states per character.
+        set barProgress   [expr {entier(round(($current * $barWidth * 8) / $total))}]
+
+        set barInteger    [expr {$barProgress / 8}]
+        #set barRemainder  [expr {$barProgress % 8}]
+
+        # Finally, also provide a percentage value to print behind the progress bar
+        set percentage [expr {double($current) * 100 / double($total)}]
+
+        # clear the current line, enable reverse video
+        set progressbar "\033\[7m"
+        for {set i 0} {$i < $barInteger} {incr i} {
+            # U+2588 FULL BLOCK doesn't match the other blocks in some fonts :/
+            # Two half blocks work better in some fonts, but not in others (because
+            # they leave ugly spaces). So, one or the other choice isn't better or
+            # worse and even just using full blocks looks ugly in a few fonts.
+
+            # Use pure ASCII until somebody fixes most of the default terminal fonts :/
+            append progressbar " "
+        }
+        # back to normal output
+        append progressbar "\033\[0m"
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger < $barWidth} {
+        #            append progressbar " "
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar "\u258f"
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar "\u258e"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar "\u258c"
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar "\u258b"
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar "\u258a"
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar "\u2589"
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i < $barWidth} {incr i} {
+            append progressbar " "
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format " %[expr {$percentageWidth - 3}].1f %%" $percentage]
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}"
+        flush stdout
+    }
+
+
+    ##
+    # Internal state of the progress indicator; unless you're hacking the
+    # unprogressbar code you should never touch this.
+    variable unprogressState 0
+
+    ##
+    # Draw a progress indicator
+    #
+    # @param width
+    #        The width in characters of the progress indicator.
+    # @param prefix
+    #        Prefix to be printed in front of the progress indicator.
+    # @param suffix
+    #        Suffix to be printed after the progress indicator.
+    proc unprogressbar {width {prefix ""} {suffix ""}} {
+        variable unprogressState
+
+        # Subtract the two characters [ and ] bounding the progress indicator
+        # from the width.
+        set barWidth [expr {int($width) - 2}]
+
+        # Number of states of the progress bar, or rather: the number of
+        # characters before the sequence repeats.
+        set numStates 4
+
+        set unprogressState [expr {($unprogressState + 1) % $numStates}]
+
+        set progressbar ""
+        for {set i 0} {$i < $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar "\u2022"
+            } else {
+                append progressbar " "
+            }
+        }
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${suffix}"
+        flush stdout
+    }
+}
+
+namespace eval portclient::notifications {
+    ##
+    # Ports whose notifications to display; these were either installed
+    # or requested to be installed.
+    variable notificationsToPrint
+    array set notificationsToPrint {}
+
+    ##
+    # Add a port to the list for printing notifications.
+    #
+    # @param name
+    #        The name of the port.
+    # @param note
+    #        A list of notes to be stored for the given port.
+    proc append {name notes} {
+        variable notificationsToPrint
+
+        set notificationsToPrint($name) $notes
+    }
+
+    ##
+    # Print port notifications.
+    #
+    proc display {} {
+        global env
+        variable notificationsToPrint
+
+        # Display notes at the end of the activation phase.
+        if {[array size notificationsToPrint] > 0} {
+            ui_notice "--->  Some of the ports you installed have notes:"
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice "  $name has the following notes:"
+
+                # If env(COLUMNS) exists, limit each line's width to this width.
+                if {[info exists env(COLUMNS)]} {
+                    set maxlen $env(COLUMNS)
+
+                    foreach note $notes {
+                        foreach line [split $note "\n"] {
+                            set joiner ""
+                            set lines ""
+                            set newline "    "
+
+                            foreach word [split $line " "] {
+                                if {[string length $newline] + [string length $word] >= $maxlen} {
+                                    lappend lines $newline
+                                    set newline "    "
+                                    set joiner ""
+                                }
+                                ::append newline $joiner $word
+                                set joiner " "
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines "\n"]
+                        }
+                    }
+                } else {
+                    foreach note $notes {
+                        ui_notice $note
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+##########################################
+# Main
+##########################################
+
+# Global arrays passed to the macports1.0 layer
+array set ui_options        {}
+array set global_options    {}
+array set global_variations {}
+
+# Global options private to this script
+array set private_options {}
+
+# Make sure we get the size of the terminal
+# We do this here to save it in the boot_env, in case we determined it manually
+term_init_size
+
+global env boot_env argv0 cmdname argc argv cmd_argc cmd_argv cmd_argn \
+       current_portdir global_options_base exit_status
+
+# Save off a copy of the environment before mportinit monkeys with it
+array set boot_env [array get env]
+
+set cmdname [file tail $argv0]
+
+# Setp cmd_argv to match argv
+set cmd_argv $argv
+set cmd_argc $argc
+set cmd_argn 0
+
+# make sure we're using a sane umask
+umask 022
+
+# If we've been invoked as portf, then the first argument is assumed
+# to be the name of a command file (i.e., there is an implicit -F
+# before any arguments).
+if {[moreargs] && $cmdname eq "portf"} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options "global" ui_options global_options} result]} {
+    puts "Error: $result"
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    && $portclient::progress::hasTermAnsiSend eq "yes"
+    && (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne "yes")} {
+    set ui_options(progress_download) portclient::progress::download
+    set ui_options(progress_generic)  portclient::progress::generic
+}
+
+set ui_options(notifications_append) portclient::notifications::append
+
+# Get arguments remaining after option processing
+set remaining_args [lrange $cmd_argv $cmd_argn end]
+
+# If we have no arguments remaining after option processing then force
+# interactive mode
+if { [llength $remaining_args] == 0 && ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq "selfupdate" || [lookahead] eq "sync"} {
+    # tell mportinit not to tell the user they should selfupdate
+    set ui_options(ports_no_old_index_warning) 1
+}
+
+# Initialize mport
+# This must be done following parse of global options, as some options are
+# evaluated by mportinit.
+if {[catch {mportinit ui_options global_options global_variations} result]} {
+    global errorInfo
+    puts "$errorInfo"
+    fatal "Failed to initialize MacPorts, $result"
+}
+
+# Set up some global state for our code
+set current_portdir [pwd]
+
+# Freeze global_options into global_options_base; global_options
+# will be reset to global_options_base prior to processing each command.
+set global_options_base [array get global_options]
+
+# First process any remaining args as action(s)
+set exit_status 0
+if { [llength $remaining_args] > 0 } {
+
+    # If there are remaining arguments, process those as a command
+    set exit_status [process_cmd $remaining_args]
+}
+
+# Process any prescribed command files, including standard input
+if { ($exit_status == 0 || [macports::ui_isset ports_processall]) && [info exists ui_options(ports_commandfiles)] } {
+    set exit_status [process_command_files $ui_options(ports_commandfiles)]
+}
+if {$exit_status == -999} {
+    set exit_status 0
+}
+
+# shut down macports1.0
+mportshutdown
+
+# Return with exit_status
+exit $exit_status

Added: branches/gsoc14-cleanup/src/port/port.tcl.orig
===================================================================
--- branches/gsoc14-cleanup/src/port/port.tcl.orig	                        (rev 0)
+++ branches/gsoc14-cleanup/src/port/port.tcl.orig	2014-08-13 22:14:51 UTC (rev 123747)
@@ -0,0 +1,5361 @@
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=tcl:et:sw=4:ts=4:sts=4
+# $Id: port.tcl 119177 2014-04-18 22:35:29Z cal at macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw <rshaw at opendarwin.org>
+# Copyright (c) 2002-2003 Apple Inc.
+# 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.
+# 3. Neither the name of Apple Inc. nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+# Create a namespace for some local variables
+namespace eval portclient::progress {
+    ##
+    # Indicate whether the term::ansi::send tcllib package is available and was
+    # imported. "yes", if the package is available, "no" otherwise.
+    variable hasTermAnsiSend no
+}
+
+if {![catch {package require term::ansi::send}]} {
+    set portclient::progress::hasTermAnsiSend yes
+}
+
+package require macports
+package require Pextlib 1.0
+
+# Standard procedures
+proc print_usage {{verbose 1}} {
+    global cmdname
+    set syntax {
+        [-bcdfknopqRstuvy] [-D portdir] [-F cmdfile] action [privopts] [actionflags]
+        [[portname|pseudo-portname|port-url] [@version] [+-variant]... [option=value]...]...
+    }
+
+    if {$verbose} {
+        puts stderr "Usage: $cmdname$syntax"
+        puts stderr "\"$cmdname help\" or \"man 1 port\" for more information."
+    } else {
+        puts stderr "$cmdname$syntax"
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds ""
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen > 65} {
+            set cmds "$cmds,\n"
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new "$cmd"
+        } else {
+            set new ", $cmd"
+        }
+        incr lineLen [string length $new]
+        set cmds "$cmds$new"
+    }
+
+    set cmdText "Supported actions
+------------------
+$cmds
+"
+
+    set text {
+Pseudo-portnames
+----------------
+Pseudo-portnames are words that may be used in place of a portname, and
+which expand to some set of ports. The common pseudo-portnames are:
+all, current, active, inactive, actinact, installed, uninstalled, outdated,
+obsolete, requested, unrequested and leaves.
+These pseudo-portnames expand to the set of ports named.
+
+Pseudo-portnames starting with variants:, variant:, description:, depends:,
+depends_lib:, depends_run:, depends_build:, depends_fetch:, depends_extract:,
+portdir:, homepage:, epoch:, platforms:, platform:, name:, long_description:,
+maintainers:, maintainer:, categories:, category:, version:, revision:, and
+license: each select a set of ports based on a regex search of metadata
+about the ports. In all such cases, a standard regex pattern following
+the colon will be used to select the set of ports to which the
+pseudo-portname expands.
+
+Pseudo-portnames starting with depof:, rdepof:, dependentof:, and rdependentof:
+select ports that are direct or recursive dependencies or dependents of the
+following portname, respectively.
+
+Portnames that contain standard glob characters will be expanded to the
+set of ports matching the glob pattern.
+    
+Port expressions
+----------------
+Portnames, port glob patterns, and pseudo-portnames may be logically
+combined using expressions consisting of and, or, not, !, (, and ).
+    
+For more information
+--------------------
+See man pages: port(1), macports.conf(5), portfile(7), portgroup(7),
+porthier(7), portstyle(7). Also, see http://www.macports.org.
+    }
+
+    puts "$cmdText$text"
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error "$argv0: $s"
+    exit 1
+}
+
+##
+# Helper function to define constants
+#
+# Constants defined with const can simply be accessed in the same way as
+# calling a proc.
+#
+# Example:
+# const FOO 42
+# puts [FOO]
+#
+# @param name variable name
+# @param value constant variable value
+proc const {name args} {
+    proc $name {} [list return [expr $args]]
+}
+
+# Format an integer representing bytes using given units
+proc bytesize {siz {unit {}} {format {%.3f}}} {
+    if {$unit == {}} {
+        if {$siz > 0x40000000} {
+            set unit "GiB"
+        } elseif {$siz > 0x100000} {
+            set unit "MiB"
+        } elseif {$siz > 0x400} {
+            set unit "KiB"
+        } else {
+            set unit "B"
+        }
+    }
+    switch -- $unit {
+        KiB {
+            set siz [expr {$siz / 1024.0}]
+        }
+        kB {
+            set siz [expr {$siz / 1000.0}]
+        }
+        MiB {
+            set siz [expr {$siz / 1048576.0}]
+        }
+        MB {
+            set siz [expr {$siz / 1000000.0}]
+        }
+        GiB {
+            set siz [expr {$siz / 1073741824.0}]
+        }
+        GB {
+            set siz [expr {$siz / 1000000000.0}]
+        }
+        B { }
+        default {
+            ui_warn "Unknown file size unit '$unit' specified"
+            set unit "B"
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return "$siz $unit"
+}
+
+proc filesize {fil {unit {}}} {
+    set siz {@}
+    catch {
+        set siz [bytesize [file size $fil] $unit]
+    }
+    return $siz
+}
+
+# Produce an error message, and exit, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc fatal_softcontinue s {
+    if {[macports::global_option_isset ports_force]} {
+        ui_error $s
+        return -code continue
+    } else {
+        fatal $s
+    }
+}
+
+
+# Produce an error message, and break, unless
+# we're handling errors in a soft fashion, in which
+# case we continue
+proc break_softcontinue { msg status name_status } {
+    upvar $name_status status_var 
+    ui_error $msg
+    if {[macports::ui_isset ports_processall]} {
+        set status_var 0
+        return -code continue
+    } else {
+        set status_var $status
+        return -code break
+    }
+}
+
+# show the URL for the ticket reporting instructions
+proc print_tickets_url {args} {
+    if {${macports::prefix} ne "/usr/local" && ${macports::prefix} ne "/usr"} {
+        ui_error "Follow http://guide.macports.org/#project.tickets to report a bug."
+    }
+}
+
+# Form a composite version as is sometimes used for registry functions
+# This function sorts the variants and presents them in a canonical representation
+proc composite_version {version variations {emptyVersionOkay 0}} {
+    # Form a composite version out of the version and variations
+    
+    # Select the variations into positive and negative
+    set pos {}
+    set neg {}
+    foreach { key val } $variations {
+        if {$val eq "+"} {
+            lappend pos $key
+        } elseif {$val eq "-"} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version ""
+    if {$version ne "" || $emptyVersionOkay} {
+        set pos_str ""
+        set neg_str ""
+
+        if {[llength $pos]} {
+            set pos_str "+[join [lsort -ascii $pos] "+"]"
+        }
+        if {[llength $neg]} {
+            set neg_str "-[join [lsort -ascii $neg] "-"]"
+        }
+
+        set composite_version "$version$pos_str$neg_str"
+    }
+
+    return $composite_version
+}
+
+
+proc split_variants {variants} {
+    set result {}
+    set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
+    foreach { match sign variant } $l {
+        lappend result $variant $sign
+    }
+    return $result
+}
+
+
+##
+# Maps friendly field names to their real name
+# Names which do not need mapping are not changed.
+#
+# @param field friendly name
+# @return real name
+proc map_friendly_field_names { field } {
+    switch -- $field {
+        variant -
+        platform -
+        maintainer -
+        subport {
+            set field "${field}s"
+        }
+        category {
+            set field "categories"
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion ""}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] > 1 } {
+        # set portname again since the one we were passed may not have had the correct case
+        set portname [lindex $ilist 0 0]
+        ui_notice "The following versions of $portname are currently installed:"
+        foreach i [portlist_sortint $ilist] { 
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants} (active)"
+            }
+        }
+        return -code error "Registry error: Please specify the full version as recorded in the port registry."
+    } else {
+        return [lindex $ilist 0]
+    }
+}
+
+
+proc entry_for_portlist {portentry} {
+    global global_options global_variations
+
+    # Each portlist entry currently has the following elements in it:
+    #   url             if any
+    #   name
+    #   version         (version_revision)
+    #   variants array  (variant=>+-)
+    #   requested_variants array  (variant=>+-)
+    #   options array   (key=>value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) "" }
+    if {![info exists port(name)]}      { set port(name) "" }
+    if {![info exists port(version)]}   { set port(version) "" }
+    if {![info exists port(variants)]}  { set port(variants) "" }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) "" }
+    if {![info exists port(options)]}   { set port(options) [array get global_options] }
+
+    # If neither portname nor url is specified, then default to the current port
+    if { $port(url) eq "" && $port(name) eq "" } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq ""} {
+            ui_error "A default port name could not be supplied."
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) "$port(name)/[composite_version $port(version) $port(variants)]"
+    
+    return [array get port]
+}
+
+
+proc add_to_portlist {listname portentry} {
+    upvar $listname portlist
+    
+    # Form portlist entry and add to portlist
+    lappend portlist [entry_for_portlist $portentry]
+}
+
+
+proc add_ports_to_portlist {listname ports {overridelist ""}} {
+    upvar $listname portlist
+
+    array set overrides $overridelist
+
+    # Add each entry to the named portlist, overriding any values
+    # specified as overrides
+    foreach portentry $ports {
+        array set port $portentry
+        if ([info exists overrides(version)])   { set port(version) $overrides(version) }
+        if ([info exists overrides(variants)])  { set port(variants) $overrides(variants) }
+        if ([info exists overrides(requested_variants)])  { set port(requested_variants) $overrides(requested_variants) }
+        if ([info exists overrides(options)])   { set port(options) $overrides(options) }
+        add_to_portlist portlist [array get port]
+    }
+}
+
+
+proc url_to_portname { url {quiet 0} } {
+    # Save directory and restore the directory, since mportopen changes it
+    set savedir [pwd]
+    set portname ""
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg "Can't map the URL '$url' to a port description file (\"${result}\")."
+            ui_msg "Please verify that the directory and portfile syntax are correct."
+        }
+    } else {
+        array set portinfo [mportinfo $ctx]
+        set portname $portinfo(name)
+        mportclose $ctx
+    }
+    cd $savedir
+    return $portname
+}
+
+
+# Supply a default porturl/portname if the portlist is empty
+proc require_portlist { nameportlist {is_upgrade "no"} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 && (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        if {${is_upgrade} == "yes"} {
+            # $> port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # "upgrade", let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg "Nothing to upgrade."
+            return 1
+        }
+        ui_error "No ports matched the given expression"
+        return 1
+    }
+
+    if {[llength $portlist] == 0} {
+        set portlist [get_current_port]
+
+        if {[llength $portlist] == 0} {
+            # there was no port in current directory
+            return 1
+        }
+    }
+
+    return 0
+}
+
+
+# Execute the enclosed block once for every element in the portlist
+# When the block is entered, the following variables will have been set:
+#   portspec, porturl, portname, portversion, options, variations, requested_variations
+proc foreachport {portlist block} {
+    set savedir [pwd]
+    foreach portspec $portlist {
+    
+        # Set the variables for the block
+        uplevel 1 "array unset portspec; array set portspec { $portspec }"
+        uplevel 1 {
+            set porturl $portspec(url)
+            set portname $portspec(name)
+            set portversion $portspec(version)
+            array unset variations
+            array set variations $portspec(variants)
+            array unset requested_variations
+            array set requested_variations $portspec(requested_variants)
+            array unset options
+            array set options $portspec(options)
+        }
+        
+        # Invoke block
+        uplevel 1 $block
+        
+        # Restore cwd after each port, since mportopen changes it, and otherwise relative
+        # urls would break on subsequent passes
+        if {[file exists $savedir]} {
+            cd $savedir
+        } else {
+            cd ~
+        }
+    }
+}
+
+
+proc portlist_compare { a b } {
+    array set a_ $a
+    array set b_ $b
+    set namecmp [string equal -nocase $a_(name) $b_(name)]
+    if {$namecmp != 1} {
+        if {$a_(name) eq [lindex [lsort -dictionary [list $a_(name) $b_(name)]] 0]} {
+            return -1
+        }
+        return 1
+    }
+    set avr_ [split $a_(version) "_"]
+    set bvr_ [split $b_(version) "_"]
+    set versioncmp [vercmp [lindex $avr_ 0] [lindex $bvr_ 0]]
+    if {$versioncmp != 0} {
+        return $versioncmp
+    }
+    set ar_ [lindex $avr_ 1]
+    set br_ [lindex $bvr_ 1]
+    if {$ar_ < $br_} {
+        return -1
+    } elseif {$ar_ > $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name at version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list "name" [lindex $a 0] "version" "[lindex $a 1]_[lindex $a 2]"]
+    array set b_ [list "name" [lindex $b 0] "version" "[lindex $b 1]_[lindex $b 2]"]
+    return [portlist_compare [array get a_] [array get b_]]
+}
+
+# Same as portlist_sort, but with numeric indexes {name version revision}
+proc portlist_sortint { list } {
+    return [lsort -command portlist_compareint $list]
+}
+
+# sort portlist so dependents come before their dependencies
+proc portlist_sortdependents { portlist } {
+    foreach p $portlist {
+        array set pvals $p
+        lappend entries($pvals(name)) $p
+        if {![info exists dependents($pvals(name))]} {
+            set dependents($pvals(name)) {}
+            foreach result [registry::list_dependents $pvals(name)] {
+                lappend dependents($pvals(name)) [lindex $result 2]
+            }
+        }
+        array unset pvals
+    }
+    set ret {}
+    foreach p $portlist {
+        portlist_sortdependents_helper $p entries dependents seen ret
+    }
+    return $ret
+}
+
+proc portlist_sortdependents_helper {p up_entries up_dependents up_seen up_retlist} {
+    upvar $up_seen seen
+    if {![info exists seen($p)]} {
+        set seen($p) 1
+        upvar $up_entries entries $up_dependents dependents $up_retlist retlist
+        array set pvals $p
+        foreach dependent $dependents($pvals(name)) {
+            if {[info exists entries($dependent)]} {
+                foreach entry $entries($dependent) {
+                    portlist_sortdependents_helper $entry entries dependents seen retlist
+                }
+            }
+        }
+        lappend retlist $p
+    }
+}
+
+proc regex_pat_sanitize { s } {
+    set sanitized [regsub -all {[\\(){}+$.^]} $s {\\&}]
+    return $sanitized
+}
+
+##
+# Makes sure we get the current terminal size
+proc term_init_size {} {
+    global env
+
+    if {![info exists env(COLUMNS)] || ![info exists env(LINES)]} {
+        if {[isatty stdout]} {
+            set size [term_get_size stdout]
+
+            if {![info exists env(LINES)] && [lindex $size 0] > 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] && [lindex $size 1] > 0} {
+                set env(COLUMNS) [lindex $size 1]
+            }
+        }
+    }
+}
+
+##
+# Wraps a multi-line string at specified textwidth
+#
+# @see wrapline
+#
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrap {string maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set splitstring {}
+    set indentline $indentfirstline
+    foreach line [split $string "\n"] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring "\n"]
+}
+
+##
+# Wraps a line at specified textwidth
+#
+# @see wrap
+#
+# @param line input line
+# @param maxlen text width (0 defaults to current terminal width)
+# @param indent prepend to every line
+# @return wrapped string
+proc wrapline {line maxlen {indent ""} {indentfirstline 1}} {
+    global env
+
+    if {$maxlen == 0} {
+        if {![info exists env(COLUMNS)]} {
+            # no width for wrapping
+            return $string
+        }
+        set maxlen $env(COLUMNS)
+    }
+
+    set string [split $line " "]
+    if {$indentfirstline == 0} {
+        set newline ""
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner " "
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] >= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner ""
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 && $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner " "
+    }
+    lappend lines $newline
+    return [join $lines "\n"]
+}
+
+##
+# Wraps a line at a specified width with a label in front
+#
+# @see wrap
+#
+# @param label label for output
+# @param string input string
+# @param maxlen text width (0 defaults to current terminal width)
+# @return wrapped string
+proc wraplabel {label string maxlen {indent ""}} {
+    append label ": [string repeat " " [expr {[string length $indent] - [string length "$label: "]}]]"
+    return "$label[wrap $string $maxlen $indent 0]"
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first "@" $m] < 0} {
+            if {[string first ":" $m] >= 0} {
+                set m [regsub -- "(.*):(.*)" $m "\\2@\\1"] 
+            } else {
+                set m "$m at macports.org"
+            }
+        }
+        lappend result $m
+    }
+    return $result
+}
+
+
+##########################################
+# Port selection
+##########################################
+proc unique_results_to_portlist {infos} {
+    set result {}
+    array unset unique
+    foreach {name info} $infos {
+        array unset portinfo
+        array set portinfo $info
+        
+        set portentry [entry_for_portlist [list url $portinfo(porturl) name $name]]
+        
+        array unset entry
+        array set entry $portentry
+        
+        if {[info exists unique($entry(fullname))]} continue
+        set unique($entry(fullname)) 1
+        
+        lappend result $portentry
+    }
+    return $result
+}
+
+
+proc get_matching_ports {pattern {casesensitive no} {matchstyle glob} {field name}} {
+    if {[catch {set res [mportsearch $pattern $casesensitive $matchstyle $field]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        fatal "search for portname $pattern failed: $result"
+    }
+    set results [unique_results_to_portlist $res]
+    
+    # Return the list of all ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_all_ports {} {
+    global all_ports_cache
+
+    if {![info exists all_ports_cache]} {
+         if {[catch {set res [mportlistall]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "listing all ports failed: $result"
+        }
+        set results [unique_results_to_portlist $res]
+        set all_ports_cache [portlist_sort $results]
+    }
+    return $all_ports_cache
+}
+
+
+proc get_current_ports {} {
+    # This is just a synonym for get_current_port that
+    # works with the regex in element
+    return [get_current_port]
+}
+
+
+proc get_current_port {} {
+    set url file://.
+    set portname [url_to_portname $url]
+    if {$portname eq ""} {
+        ui_msg "To use the current port, you must be in a port's directory."
+        return [list]
+    }
+
+    set results {}
+    add_to_portlist results [list url $url name $portname]
+    return $results
+}
+
+
+proc get_installed_ports { {ignore_active yes} {active yes} } {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [split_variants [lindex $i 3]]
+        set iactive [lindex $i 4]
+
+        if { ${ignore_active} == "yes" || (${active} == "yes") == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants $ivariants]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+
+proc get_uninstalled_ports {} {
+    # Return all - installed
+    set all [get_all_ports]
+    set installed [get_installed_ports]
+    return [opComplement $all $installed]
+}
+
+
+proc get_active_ports {} {
+    return [get_installed_ports no yes]
+}
+
+
+proc get_inactive_ports {} {
+    return [get_installed_ports no no]
+}
+
+proc get_actinact_ports {} {
+    set inactive_ports [get_inactive_ports]
+    set active_ports [get_active_ports]
+    set results {}
+
+    foreach port $inactive_ports {
+        array set portspec $port
+        set portname $portspec(name)
+        lappend inact($portname) $port
+    }
+
+    foreach port $active_ports {
+        array set portspec $port
+        set portname $portspec(name)
+
+        if {[info exists inact($portname)]} {
+            if {![info exists added_inact($portname)]} {
+                foreach inact_spec $inact($portname) {
+                    lappend results $inact_spec
+                }
+                set added_inact($portname) 1
+            }
+            lappend results $port
+        }
+    }
+    return $results
+}
+
+
+proc get_outdated_ports {} {
+    # Get the list of installed ports
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] > 0 } {
+        foreach i $ilist {
+
+            # Get information about the installed port
+            set portname            [lindex $i 0]
+            set installed_version   [lindex $i 1]
+            set installed_revision  [lindex $i 2]
+            set installed_compound  "${installed_version}_${installed_revision}"
+            set installed_variants  [lindex $i 3]
+
+            set is_active           [lindex $i 4]
+            if {$is_active == 0} continue
+
+            set installed_epoch     [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                fatal "lookup of portname $portname failed: $result"
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+
+            # Get information about latest available version and revision
+            set latest_version $portinfo(version)
+            set latest_revision     0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     "${latest_version}_${latest_revision}"
+            set latest_epoch        0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch    $portinfo(epoch)
+            }
+
+            # Compare versions, first checking epoch, then version, then revision
+            set comp_result 0
+            if {$installed_version != $latest_version} {
+                set comp_result [expr {$installed_epoch - $latest_epoch}]
+                if { $comp_result == 0 } {
+                    set comp_result [vercmp $installed_version $latest_version]
+                }
+            }
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            if {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision $installed_variants $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                }
+            }
+
+            # Add outdated ports to our results list
+            if { $comp_result < 0 } {
+                add_to_portlist results [list name $portname version $installed_compound variants [split_variants $installed_variants]]
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_obsolete_ports {} {
+    set ilist [get_installed_ports]
+    set results {}
+
+    foreach i $ilist {
+        array set port $i
+
+        if {[catch {mportlookup $port(name)} result]} {
+            ui_debug "$::errorInfo"
+            break_softcontinue "lookup of portname $portname failed: $result" 1 status
+        }
+
+        if {[llength $result] < 2} {
+            lappend results $i
+        }
+    }
+
+    # Return the list of ports, already sorted
+    return [portlist_sort $results]
+}
+
+# return ports that have registry property $propname set to $propval
+proc get_ports_with_prop {propname propval} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        set iversion [lindex $i 1]
+        set irevision [lindex $i 2]
+        set ivariants [lindex $i 3]
+        set iepoch [lindex $i 5]
+        set regref [registry::open_entry $iname $iversion $irevision $ivariants $iepoch]
+        if {[registry::property_retrieve $regref $propname] == $propval} {
+            add_to_portlist results [list name $iname version "${iversion}_${irevision}" variants [split_variants $ivariants]]
+        }
+    }
+
+    # Return the list of ports, sorted
+    return [portlist_sort $results]
+}
+
+proc get_requested_ports {} {
+    return [get_ports_with_prop requested 1]
+}
+
+proc get_unrequested_ports {} {
+    return [get_ports_with_prop requested 0]
+}
+
+proc get_leaves_ports {} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result ne "Registry error: No ports registered as installed."} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "port installed failed: $result"
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq ""} {
+            add_to_portlist results [list name $iname version "[lindex $i 1]_[lindex $i 2]" variants [split_variants [lindex $i 3]]]
+        }
+    }
+    return [portlist_sort [opIntersection $results [get_unrequested_ports]]]
+}
+
+proc get_dependent_ports {portname recursive} {
+    registry::open_dep_map
+    set deplist [registry::list_dependents $portname]
+    # could return specific versions here using registry2.0 features
+    set results {}
+    foreach dep $deplist {
+        add_to_portlist results [list name [lindex $dep 2]]
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex $dep 2]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    set rdeplist [registry::list_dependents $depname]
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex $rdep 2]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+proc get_dep_ports {portname recursive} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its deps
+    set results {}
+    set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+
+    set deplist {}
+    foreach type $deptypes {
+        if {[info exists portinfo($type)]} {
+            foreach dep $portinfo($type) {
+                add_to_portlist results [list name [lindex [split $dep :] end]]
+                lappend deplist $dep
+            }
+        }
+    }
+
+    # actually do this iteratively to avoid hitting Tcl's recursion limit
+    if {$recursive} {
+        while 1 {
+            set rportlist {}
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        return -code error "lookup of portname $depname failed: $result"
+                    }
+                    if {[llength $result] < 2} {
+                        ui_error "Port $depname not found"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                
+                    # open its portfile
+                    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+                        ui_debug "$::errorInfo"
+                        ui_error "Unable to open port: $result"
+                        continue
+                    }
+                    array unset portinfo
+                    array set portinfo [mportinfo $mport]
+                    mportclose $mport
+
+                    # collect its deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                add_to_portlist results [list name [lindex [split $rdep :] end]]
+                                lappend rdeplist $rdep
+                            }
+                        }
+                    }
+
+                    # add them to the lists
+                    foreach rdep $rdeplist {
+                        lappend newlist $rdep
+                        add_to_portlist rportlist [list name [lindex [split $rdep :] end]]
+                    }
+                }
+            }
+            if {[llength $rportlist] > 0} {
+                set results [opUnion $results $rportlist]
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+proc get_subports {portname} {
+    global global_variations
+
+    # look up portname
+    if {[catch {mportlookup $portname} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "lookup of portname $portname failed: $result"
+    }
+    if {[llength $result] < 2} {
+        return -code error "Port $portname not found"
+    }
+    array unset portinfo
+    array set portinfo [lindex $result 1]
+    set porturl $portinfo(porturl)
+
+    # open portfile
+    if {[catch {set mport [mportopen $porturl [list subport $portinfo(name)] [array get global_variations]]} result]} {
+        ui_debug "$::errorInfo"
+        return -code error "Unable to open port: $result"
+    }
+    array unset portinfo
+    array set portinfo [mportinfo $mport]
+    mportclose $mport
+
+    # gather its subports
+    set results {}
+
+    if {[info exists portinfo(subports)]} {
+        foreach subport $portinfo(subports) {
+            add_to_portlist results [list name $subport]
+        }
+    }
+
+    return [portlist_sort $results]
+}
+
+
+##########################################
+# Port expressions
+##########################################
+proc portExpr { resname } {
+    upvar $resname reslist
+    set result [seqExpr reslist]
+    return $result
+}
+
+
+proc seqExpr { resname } {
+    upvar $resname reslist
+    
+    # Evaluate a sequence of expressions a b c...
+    # These act the same as a or b or c
+
+    set result 1
+    while {$result} {
+        switch -- [lookahead] {
+            ;       -
+            )       -
+            _EOF_   { break }
+        }
+
+        set blist {}
+        set result [orExpr blist]
+        if {$result} {
+            # Calculate the union of result and b
+            set reslist [opUnion $reslist $blist]
+        }
+    }
+    
+    return $result
+}
+
+
+proc orExpr { resname } {
+    upvar $resname reslist
+    
+    set a [andExpr reslist]
+    while ($a) {
+        switch -- [lookahead] {
+            or {
+                    advance
+                    set blist {}
+                    if {![andExpr blist]} {
+                        return 0
+                    }
+                        
+                    # Calculate a union b
+                    set reslist [opUnion $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc andExpr { resname } {
+    upvar $resname reslist
+    
+    set a [unaryExpr reslist]
+    while {$a} {
+        switch -- [lookahead] {
+            and {
+                    advance
+                    
+                    set blist {}
+                    set b [unaryExpr blist]
+                    if {!$b} {
+                        return 0
+                    }
+                    
+                    # Calculate a intersect b
+                    set reslist [opIntersection $reslist $blist]
+                }
+            default {
+                    return $a
+                }
+        }
+    }
+    
+    return $a
+}
+
+
+proc unaryExpr { resname } {
+    upvar $resname reslist
+    set result 0
+
+    switch -- [lookahead] {
+        !   -
+        not {
+                advance
+                set blist {}
+                set result [unaryExpr blist]
+                if {$result} {
+                    set all [get_all_ports]
+                    set reslist [opComplement $all $blist]
+                }
+            }
+        default {
+                set result [element reslist]
+            }
+    }
+    
+    return $result
+}
+
+
+proc element { resname } {
+    upvar $resname reslist
+    set el 0
+    
+    set url ""
+    set name ""
+    set version ""
+    array unset requested_variants
+    array unset options
+    
+    set token [lookahead]
+    switch -regex -- $token {
+        ^\\)$               -
+        ^\;                 -
+        ^_EOF_$             { # End of expression/cmd/file
+        }
+
+        ^\\($               { # Parenthesized Expression
+            advance
+            set el [portExpr reslist]
+            if {!$el || ![match ")"]} {
+                set el 0
+            }
+        }
+
+        ^all(@.*)?$         -
+        ^installed(@.*)?$   -
+        ^uninstalled(@.*)?$ -
+        ^active(@.*)?$      -
+        ^inactive(@.*)?$    -
+        ^actinact(@.*)?$    -
+        ^leaves(@.*)?$      -
+        ^outdated(@.*)?$    -
+        ^obsolete(@.*)?$    -
+        ^requested(@.*)?$   -
+        ^unrequested(@.*)?$ -
+        ^current(@.*)?$     {
+            # A simple pseudo-port name
+            advance
+
+            # Break off the version component, if there is one
+            regexp {^(\w+)(@.*)?} $token matchvar name remainder
+
+            add_multiple_ports reslist [get_${name}_ports] $remainder
+
+            set el 1
+        }
+
+        ^variants:          -
+        ^variant:           -
+        ^description:       -
+        ^portdir:           -
+        ^homepage:          -
+        ^epoch:             -
+        ^platforms:         -
+        ^platform:          -
+        ^name:              -
+        ^long_description:  -
+        ^maintainers:       -
+        ^maintainer:        -
+        ^categories:        -
+        ^category:          -
+        ^version:           -
+        ^depends_lib:       -
+        ^depends_build:     -
+        ^depends_run:       -
+        ^depends_extract:   -
+        ^depends_fetch:     -
+        ^replaced_by:       -
+        ^revision:          -
+        ^subport:           -
+        ^subports:          -
+        ^license:           { # Handle special port selectors
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            # Remap friendly names to actual names
+            set field [map_friendly_field_names $field]
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp $field]
+            set el 1
+        }
+
+        ^depends:           { # A port selector shorthand for depends_{lib,build,run,fetch,extract}
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar field pat
+
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_lib"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_build"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_run"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_extract"]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp "depends_fetch"]
+
+            set el 1
+        }
+
+        ^dependentof:       -
+        ^rdependentof:      {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdependentof"]
+            add_multiple_ports reslist [get_dependent_ports $portname $recursive]
+            
+            set el 1
+        }
+        
+        ^depof:             -
+        ^rdepof:            {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            set recursive [string equal $selector "rdepof"]
+            add_multiple_ports reslist [get_dep_ports $portname $recursive]
+            
+            set el 1
+        }
+
+        ^subportof:         {
+            advance
+
+            # Break up the token, because older Tcl switch doesn't support -matchvar
+            regexp {^(\w+):(.*)} $token matchvar selector portname
+
+            add_multiple_ports reslist [get_subports $portname]
+
+            set el 1
+        }
+
+        [][?*]              { # Handle portname glob patterns
+            advance; add_multiple_ports reslist [get_matching_ports $token no glob]
+            set el 1
+        }
+
+        ^\\w+:.+            { # Handle a url by trying to open it as a port and mapping the name
+            advance
+            set name [url_to_portname $token]
+            if {$name ne ""} {
+                parsePortSpec version requested_variants options
+                add_to_portlist reslist [list url $token \
+                  name $name \
+                  version $version \
+                  requested_variants [array get requested_variants] \
+                  variants [array get requested_variants] \
+                  options [array get options]]
+                set el 1
+            } else {
+                ui_error "Can't open URL '$token' as a port"
+                set el 0
+            }
+        }
+
+        default             { # Treat anything else as a portspec (portname, version, variants, options
+            # or some combination thereof).
+            parseFullPortSpec url name version requested_variants options
+            add_to_portlist reslist [list url $url \
+              name $name \
+              version $version \
+              requested_variants [array get requested_variants] \
+              variants [array get requested_variants] \
+              options [array get options]]
+            set el 1
+        }
+    }
+
+    return $el
+}
+
+
+proc add_multiple_ports { resname ports {remainder ""} } {
+    upvar $resname reslist
+    
+    set version ""
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne ""} { set overrides(version) $version }
+    if {[array size variants]} {
+        # we always record the requested variants separately,
+        # but requested ones always override existing ones
+        set overrides(requested_variants) [array get variants]
+        set overrides(variants) [array get variants]
+    }
+    if {[array size options]} { set overrides(options) [array get options] }
+
+    add_ports_to_portlist reslist $ports [array get overrides]
+}
+
+
+proc unique_entries { entries } {
+    # Form the list of all the unique elements in the list a,
+    # considering only the port fullname, and taking the first
+    # found element first
+    set result {}
+    array unset unique
+    foreach item $entries {
+        array set port $item
+        if {[info exists unique($port(fullname))]} continue
+        set unique($port(fullname)) 1
+        lappend result $item
+    }
+    return $result
+}
+
+
+proc opUnion { a b } {
+    # Return the unique elements in the combined two lists
+    return [unique_entries [concat $a $b]]
+}
+
+
+proc opIntersection { a b } {
+    set result {}
+    
+    # Rules we follow in performing the intersection of two port lists:
+    #
+    #   a/, a/          ==> a/
+    #   a/, b/          ==>
+    #   a/, a/1.0       ==> a/1.0
+    #   a/1.0, a/       ==> a/1.0
+    #   a/1.0, a/2.0    ==>
+    #
+    #   If there's an exact match, we take it.
+    #   If there's a match between simple and discriminated, we take the later.
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem [unique_entries $b] {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, matching against b
+    foreach aitem [unique_entries $a] {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+        foreach match $matches {
+            if {$simpleform} {
+                set i $bfull($match)
+                lappend result [lindex $b $i]
+            } else {
+                lappend result $aitem
+            }
+        }
+    }
+    
+    return $result
+}
+
+
+proc opComplement { a b } {
+    set result {}
+    
+    # Return all elements of a not matching elements in b
+    
+    # First create a list of the fully discriminated names in b
+    array unset bfull
+    set i 0
+    foreach bitem $b {
+        array set port $bitem
+        set bfull($port(fullname)) $i
+        incr i
+    }
+    
+    # Walk through each item in a, taking all those items that don't match b
+    foreach aitem $a {
+        array set port $aitem
+        
+        # Quote the fullname and portname to avoid special characters messing up the regexp
+        set safefullname [regex_pat_sanitize $port(fullname)]
+        
+        set simpleform [expr { "$port(name)/" == $port(fullname) }]
+        if {$simpleform} {
+            set pat "^${safefullname}"
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat "^${safefullname}$|^${safename}/$"
+        }
+        
+        set matches [array names bfull -regexp $pat]
+
+        # We copy this element to result only if it didn't match against b
+        if {![llength $matches]} {
+            lappend result $aitem
+        }
+    }
+    
+    return $result
+}
+
+
+proc parseFullPortSpec { urlname namename vername varname optname } {
+    upvar $urlname porturl
+    upvar $namename portname
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    set portname ""
+    set portversion ""
+    array unset portvariants
+    array unset portoptions
+    
+    if { [moreargs] } {
+        # Look first for a potential portname
+        #
+        # We need to allow a wide variety of tokens here, because of actions like "provides"
+        # so we take a rather lenient view of what a "portname" is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder ""
+        if {![regexp {^(@|[-+]([[:alpha:]_]+[\w\.]*)|[[:alpha:]_]+[\w\.]*=)} $token match]} {
+            advance
+            regexp {^([^@]+)(@.*)?} $token match portname remainder
+            
+            # If the portname contains a /, then try to use it as a URL
+            if {[string match "*/*" $portname]} {
+                set url "file://$portname"
+                set name [url_to_portname $url 1]
+                if { $name ne "" } {
+                    # We mapped the url to valid port
+                    set porturl $url
+                    set portname $name
+                    # Continue to parse rest of portspec....
+                } else {
+                    # We didn't map the url to a port; treat it
+                    # as a raw string for something like port contents
+                    # or cd
+                    set porturl ""
+                    # Since this isn't a port, we don't try to parse
+                    # any remaining portspec....
+                    return
+                }
+            }
+        }
+        
+        # Now parse the rest of the spec
+        parsePortSpec portversion portvariants portoptions $remainder
+    }
+}
+
+# check if the install prefix is writable
+# should be called by actions that will modify it
+proc prefix_unwritable {} {
+    global macports::portdbpath
+    if {[file writable $portdbpath]} {
+        return 0
+    } else {
+        ui_error "Insufficient privileges to write to MacPorts install prefix."
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder ""} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion ""
+    array unset portoptions
+    array set portoptions [array get global_options]
+    array unset portvariants
+    
+    # Parse port version/variants/options
+    set opt $remainder
+    set adv 0
+    set consumed 0
+    for {set firstTime 1} {$opt ne "" || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq ""} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime && [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first "/" $opt]
+            if {$sepPos >= 0} {
+                # Version terminated by "/" to disambiguate -variant from part of version
+                set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                set opt [string range $opt [expr {$sepPos + 1}] end]
+            } else {
+                # Version terminated by "+", or else is complete
+                set sepPos [string first "+" $opt]
+                if {$sepPos >= 0} {
+                    # Version terminated by "+"
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt ""
+                }
+            }
+            set consumed 1
+        } else {
+            # Parse all other options
+            
+            # Look first for a variable setting: VARNAME=VALUE
+            if {[regexp {^([[:alpha:]_]+[\w\.]*)=(.*)} $opt match key val] == 1} {
+                # It's a variable setting
+                set portoptions($key) "\"$val\""
+                set opt ""
+                set consumed 1
+            } elseif {[regexp {^([-+])([[:alpha:]_]+[\w\.]*)} $opt match sign variant] == 1} {
+                # It's a variant
+                set portvariants($variant) $sign
+                set opt [string range $opt [expr {[string length $variant] + 1}] end]
+                set consumed 1
+            } else {
+                # Not an option we recognize, so break from port option processing
+                if { $consumed && $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds ""
+        if {[info exists cmd_opts_array($action)]} {
+            foreach opt $cmd_opts_array($action) {
+                if {[llength $opt] == 1} {
+                    set name $opt
+                    set optc 0
+                } else {
+                    set name [lindex $opt 0]
+                    set optc [lindex $opt 1]
+                }
+
+                append cmds " --$name"
+
+                for {set i 1} {$i <= $optc} {incr i} {
+                    append cmds " <arg$i>"
+                }
+            }
+        }
+        set args ""
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <arguments>"
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args " <portlist>"
+        }
+
+        set ret "Usage: "
+        set len [string length $action]
+        append ret [wrap "$action$cmds$args" 0 [string repeat " " [expr {8 + $len}]] 0]
+        append ret "\n"
+
+        return $ret
+    }
+
+    return -1
+}
+
+proc action_usage { action portlist opts } {
+    if {[llength $portlist] == 0} {
+        print_usage
+        return 0
+    }
+
+    foreach topic $portlist {
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile "$macports::prefix/var/macports/port-help.tcl"
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr "Error reading helpfile $helpfile: $err"
+            return 1
+        }
+    } else {
+        puts stderr "Unable to open help file $helpfile"
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr "No help for topic $topic"
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error "No usage for topic $topic"
+            return 1
+        }
+
+        puts stderr $porthelp($topic)
+    }
+
+    return 0
+}
+
+
+proc action_log { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array unset portinfo
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+            set portname $portinfo(name)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            array unset portinfo
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] "main.log"]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue "Could not open file $logfile: $result" 1 status
+            }
+            set data [read $fp]
+            set data [split $data "\n"]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase "\[a-z\]*"
+            }
+
+            if {[info exists global_options(ports_log_level)]} {
+                set index [lsearch -exact ${macports::ui_priorities} $global_options(ports_log_level)]
+                if {$index == -1} {
+                    set prefix ""
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] "|"]
+                }
+            } else {
+                set prefix "\[a-z\]*"
+            }
+            foreach line $data {
+                set exp "^:($prefix|any):($phase|any) (.*)$"
+                if {[regexp $exp $line -> lpriority lphase lmsg] == 1} {
+                    puts "[macports::ui_prefix_default $lpriority]$lmsg"
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue "Log file for port $portname not found" 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator ""
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] && $options(ports_info_index)} {
+            set index_only 1
+        }
+        puts -nonewline $separator
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq "" || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!$index_only} {
+            # Add any global_variations to the variations
+            # specified for the port (so we get e.g. dependencies right)
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+ 
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            unset options(subport)
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "no PortIndex entry found for $portname"
+            continue
+        }
+        array unset options ports_info_index
+
+        # Understand which info items are actually lists
+        # (this could be overloaded to provide a generic formatting code to
+        # allow us to, say, split off the prefix on libs)
+        array set list_map "
+            categories      1
+            depends_fetch   1
+            depends_extract 1
+            depends_build   1
+            depends_lib     1
+            depends_run     1
+            maintainers     1
+            platforms       1
+            variants        1
+            conflicts       1
+            subports        1
+        "
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     ""
+            variants    Variants
+            depends_fetch "Fetch Dependencies"
+            depends_extract "Extract Dependencies"
+            depends_build "Build Dependencies"
+            depends_run "Runtime Dependencies"
+            depends_lib "Library Dependencies"
+            description "Brief Description"
+            long_description "Description"
+            fullname    "Full Name: "
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   "Conflicts with"
+            replaced_by "Replaced by"
+            subports    "Sub-ports"
+        }
+
+        # Wrap-length map for pretty printing
+        array set pretty_wrap {
+            heading 0
+            replaced_by 22
+            variants 22
+            depends_fetch 22
+            depends_extract 22
+            depends_build 22
+            depends_run 22
+            depends_lib 22
+            description 22
+            long_description 22
+            homepage 22
+            platforms 22
+            license 22
+            conflicts 22
+            maintainers 22
+            subports 22
+        }
+
+        # Interpret a convenient field abbreviation
+        if {[info exists options(ports_info_depends)] && $options(ports_info_depends) eq "yes"} {
+            array unset options ports_info_depends
+            set options(ports_info_depends_fetch) yes
+            set options(ports_info_depends_extract) yes
+            set options(ports_info_depends_build) yes
+            set options(ports_info_depends_lib) yes
+            set options(ports_info_depends_run) yes
+        }
+                
+        # Set up our field separators
+        set show_label 1
+        set field_sep "\n"
+        set subfield_sep ", "
+        set pretty_print 0
+        
+        # For human-readable summary, which is the default with no options
+        if {[llength [array get options ports_info_*]] == 0} {
+            set pretty_print 1
+        } elseif {[info exists options(ports_info_pretty)]} {
+            set pretty_print 1
+            array unset options ports_info_pretty
+        }
+
+        # Tune for sort(1)
+        if {[info exists options(ports_info_line)]} {
+            array unset options ports_info_line
+            set noseparator 1
+            set show_label 0
+            set field_sep "\t"
+            set subfield_sep ","
+        }
+        
+        # Figure out whether to show field name
+        set quiet [macports::ui_isset ports_quiet]
+        if {$quiet} {
+            set show_label 0
+        }
+        # In pretty-print mode we also suppress messages, even though we show
+        # most of the labels:
+        if {$pretty_print} {
+            set quiet 1
+        }
+
+        # Spin through action options, emitting information for any found
+        set fields {}
+        set opts_todo [array names options ports_info_*]
+        set fields_tried {}
+        if {![llength $opts_todo]} {
+            set opts_todo {ports_info_heading
+                ports_info_replaced_by
+                ports_info_subports
+                ports_info_variants 
+                ports_info_skip_line
+                ports_info_long_description ports_info_homepage 
+                ports_info_skip_line ports_info_depends_fetch
+                ports_info_depends_extract ports_info_depends_build
+                ports_info_depends_lib ports_info_depends_run
+                ports_info_conflicts
+                ports_info_platforms ports_info_license
+                ports_info_maintainers
+            }
+        }
+        foreach { option } $opts_todo {
+            set opt [string range $option 11 end]
+            # Artificial field name for formatting
+            if {$pretty_print && $opt eq "skip_line"} {
+                lappend fields ""
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq "heading"} {
+                set inf "$portinfo(name) @$portinfo(version)"
+                set ropt "heading"
+                if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                    append inf "_$portinfo(revision)"
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf " ([join $portinfo(categories) ", "])"
+                }
+            } elseif {$opt eq "fullname"} {
+                set inf "$portinfo(name) @"
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt "fullname"
+            } else {
+                # Map from friendly name
+                set ropt [map_friendly_field_names $opt]
+                
+                # If there's no such info, move on
+                if {![info exists portinfo($ropt)]} {
+                    set inf ""
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label ""
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label "$opt: "
+            }
+            
+            # Format the data
+            if { $ropt eq "maintainers" } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq "variants"} {
+                    # Use the new format for variants iff it exists in
+                    # PortInfo. This key currently does not exist outside of
+                    # trunk (1.8.0).
+                    array unset vinfo
+                    if {[info exists portinfo(vinfo)]} {
+                        array set vinfo $portinfo(vinfo)
+                    }
+
+                    set pi_vars $inf
+                    set inf {}
+                    foreach v [lsort $pi_vars] {
+                        set varmodifier ""
+                        if {[info exists variations($v)]} {
+                            # selected by command line, prefixed with +/-
+                            set varmodifier $variations($v)
+                        } elseif {[info exists global_variations($v)]} {
+                            # selected by variants.conf, prefixed with (+)/(-)
+                            set varmodifier "($global_variations($v))"
+                            # Retrieve additional information from the new key.
+                        } elseif {[info exists vinfo]} {
+                            array unset variant
+                            array set variant $vinfo($v)
+                            if {[info exists variant(is_default)]} {
+                                set varmodifier "\[$variant(is_default)]"
+                            }
+                        }
+                        lappend inf "$varmodifier$v"
+                    }
+                } elseif {[string match "depend*" $ropt] 
+                          && ![macports::ui_isset ports_verbose]} {
+                    set pi_deps $inf
+                    set inf {}
+                    foreach d $pi_deps {
+                        lappend inf [lindex [split $d :] end]
+                    }
+                }
+            } 
+            #End of special pretty-print formatting for certain fields
+            if {[info exists list_map($ropt)]} {
+                set field [join $inf $subfield_sep]
+            } else {
+                set field $inf
+            }
+            
+            # Assemble the entry
+            if {$pretty_print} {
+                # The two special fields are considered headings and are
+                # emitted immediately, rather than waiting. Also they are not
+                # recorded on the list of fields tried
+                if {$ropt eq "heading" || $ropt eq "fullname"} {
+                    puts "$label$field"
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq ""} {
+                    continue
+                }
+                if {$label eq ""} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat " " $wrap_len]]
+                } else {
+                    set wrap_len [string length $label]
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wraplabel $label $field 0 [string repeat " " $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields "$label$field"
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print && [llength $fields_tried]} {
+                puts -nonewline "$portinfo(name) has no "
+                puts [join $fields_tried ", "]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator "--\n"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_location { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        if { [catch {set ilist [registry_installed $portname [composite_version $portversion [array get variations]]]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port location failed: $result" 1 status
+        } else {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0]
+            set version [lindex $ilist 1]
+            set revision [lindex $ilist 2]
+            set variants [lindex $ilist 3]
+            set epoch [lindex $ilist 5]
+        }
+
+        set ref [registry::open_entry $portname $version $revision $variants $epoch]
+        set imagedir [registry::property_retrieve $ref location]
+        ui_notice "Port $portname ${version}_${revision}${variants} is installed as an image in:"
+        puts $imagedir
+    }
+    
+    return $status
+}
+
+
+proc action_notes { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set status 0
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue "The lookup of '$portname' failed: $result" \
+                                1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "The port '$portname' was not found" 1 status
+            }
+
+            # Retrieve the port's URL.
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        }
+        
+        # Add any global_variations to the variations
+        # specified for the port
+        array unset merged_variations
+        array set merged_variations [array get variations]
+        foreach { variation value } [array get global_variations] { 
+            if { ![info exists merged_variations($variation)] } { 
+                set merged_variations($variation) $value 
+            } 
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+
+        # Open the Portfile associated with this port.
+        if {[catch {set mport [mportopen $porturl [array get options] \
+                                         [array get merged_variations]]} \
+                   result]} {
+            ui_debug $::errorInfo
+            break_softcontinue [concat "The URL '$porturl' could not be" \
+                                       "opened: $result"] 1 status
+        }
+        array unset portinfo
+        array set portinfo [mportinfo $mport]
+        mportclose $mport
+
+        # Return the notes associated with this Portfile.
+        if {[info exists portinfo(notes)]} {
+            set portnotes $portinfo(notes)
+        } else {
+            set portnotes {}
+        }
+
+        # Retrieve the port's name once more to ensure it has the proper case.
+        set portname $portinfo(name)
+
+        # Display the notes.
+        if {$portnotes ne {}} {
+            ui_notice "$portname has the following notes:"
+            foreach note $portnotes {
+                puts [wrap $note 0 "  " 1]
+            }
+        } else {
+            puts "$portname has no notes."
+        }
+    }
+    return $status
+}
+
+
+proc action_provides { action portlist opts } {
+    # In this case, portname is going to be used for the filename... since
+    # that is the first argument we expect... perhaps there is a better way
+    # to do this?
+    if { ![llength $portlist] } {
+        ui_error "Please specify a filename to check which port provides that file."
+        return 1
+    }
+    foreach filename $portlist {
+        set file [file normalize $filename]
+        if {[file exists $file] || ![catch {file type $file}]} {
+            if {![file isdirectory $file] || [file type $file] eq "link"} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts "$file is provided by: $port"
+                } else {
+                    puts "$file is not provided by a MacPorts port."
+                }
+            } else {
+                puts "$file is a directory."
+            }
+        } else {
+            puts "$file does not exist."
+        }
+    }
+    registry::close_file_map
+    
+    return 0
+}
+
+
+proc action_activate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_activate_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[$regref installtype] eq "image" && [registry::run_target $regref activate [array get options]]} {
+                continue
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::activate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port activate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping activate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_deactivate { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    set portlist [portlist_sortdependents $portlist]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_deactivate_no-exec)]
+            && ![catch {set ilist [registry::active $portname]}]} {
+
+            set i [lindex $ilist 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            if {$composite_version eq "" || $composite_version == "${iversion}_${irevision}${ivariants}"} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq "image" && [registry::run_target $regref deactivate [array get options]]} {
+                    continue
+                }
+            }
+        }
+        if {![macports::global_option_isset ports_dryrun]} {
+            if { [catch {portimage::deactivate_composite $portname $composite_version [array get options]} result] } {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "port deactivate failed: $result" 1 status
+            }
+        } else {
+            ui_msg "Skipping deactivate $portname (dry run)"
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug "action_select \[$portlist] \[$opts]..."
+
+    array set opts_array $opts
+    set commands [array names opts_array ports_select_*]
+    array unset opts_array
+
+    # Error out if no group is specified or command is not --summary.
+    if {[llength $portlist] < 1 && [string map {ports_select_ ""} [lindex $commands 0]] != "summary"} {
+        ui_error "port select \[--list|--set|--show|--summary] \<group> \[<version>]"
+        return 1
+    }
+
+    set group [lindex $portlist 0]
+    
+    # If no command (--set, --show, --list, --summary) is specified *but*
+    #  more than one argument is specified, default to the set command.
+    if {[llength $commands] < 1 && [llength $portlist] > 1} {
+        set command set
+        ui_debug [concat "Although no command was specified, more than " \
+                         "one argument was specified.  Defaulting to the " \
+                         "'set' command..."]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] < 1} {
+        set command list
+        ui_debug [concat "No command was specified. Defaulting to the " \
+                         "'list' command..."]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] > 1} {
+        ui_error [concat "Multiple commands were specified. Only one " \
+                         "command may be specified at a time."]
+        return 1
+    } else {
+        set command [string map {ports_select_ ""} [lindex $commands 0]]
+        ui_debug "The '$command' command was specified."
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'list' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn "Unable to get active selected version: $selected_version"
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error "The 'list' command failed: $versions"
+                return 1
+            }
+
+            ui_notice "Available versions for $group:"
+            foreach v $versions {
+                ui_notice -nonewline "\t"
+                if {$selected_version == $v} {
+                    ui_msg "$v (active)"
+                } else {
+                    ui_msg "$v"
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] < 2} {
+                ui_error [concat "The 'set' command expects two " \
+                                 "arguments: <group>, <version>"]
+                return 1
+            } elseif {[llength $portlist] > 2} {
+                ui_warn [concat "The 'set' command only expects two " \
+                                "arguments. Extra arguments will be " \
+                                "ignored."]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline "Selecting '$version' for '$group' "
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg "failed: $result"
+                return 1
+            }
+            ui_msg "succeeded. '$version' is now active."
+            return 0
+        }
+        show {
+            if {[llength $portlist] > 1} {
+                ui_warn [concat "The 'show' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error "The 'show' command failed: $selected_version"
+                return 1
+            }
+            puts [concat "The currently selected version for '$group' is " \
+                         "'$selected_version'."]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] > 0} {
+                ui_warn [concat "The 'summary' command does not expect any " \
+                                "arguments. Extra arguments will be ignored."]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error "The 'summary' command failed: $portgroups"
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr "%-*s  %-*s  %s"
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn "The list of options for the select group $pg could not be obtained: $versions"
+                    continue
+                }
+                # remove "none", sort the list, append none at the end
+                set noneidx [lsearch -exact $versions "none"]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions "none"
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn "The currently selected option for the select group $pg could not be obtained: $selected_version"
+                    continue
+                }
+                set groupdesc(selected) $selected_version
+
+                set w1 [expr {max($w1, [string length $pg])}]
+                set w2 [expr {max($w2, [string length $selected_version])}]
+
+                lappend groups [array get groupdesc]
+                array unset groupdesc
+            }
+            puts [format $formatStr $w1 "Name" $w2 "Selected" "Options"]
+            puts [format $formatStr $w1 "====" $w2 "========" "======="]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) " "]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error "An unknown command '$command' was specified."
+            return 1
+        }
+    }
+}
+
+
+proc action_selfupdate { action portlist opts } {
+    global global_options
+    if { [catch {macports::selfupdate [array get global_options] base_updated} result ] } {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_error "$result"
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg "Please run `port -v selfupdate' for details."
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal "port selfupdate failed: $result"
+    }
+    
+    if {$base_updated} {
+        # exit immediately if in batch/interactive mode
+        return -999
+    } else {
+        return 0
+    }
+}
+
+
+proc action_setrequested { action portlist opts } {
+    set status 0
+    if {[require_portlist portlist] || [prefix_unwritable]} {
+        return 1
+    }
+    # set or unset?
+    set val [string equal $action "setrequested"]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info "Setting requested flag for $portname to $val"
+            foreach i $ilist {
+                set regref [registry::open_entry $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+                registry::property_store $regref requested $val
+            }
+        } else {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist "yes"] || ([prefix_unwritable] && ![macports::global_option_isset ports_dryrun])} {
+        return 1
+    }
+
+    # shared depscache for all ports in the list
+    array set depscache {}
+    set status 0
+    foreachport $portlist {
+        if {![info exists depscache(port:$portname)]} {
+            set status [macports::upgrade $portname "port:$portname" [array get requested_variations] [array get options] depscache]
+            # status 2 means the port was not found in the index,
+            # status 3 means the port is not installed
+            if {$status != 0 && $status != 2 && $status != 3 && ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 && $status != 2 && $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] && ${macports::revupgrade_autorun} && ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+<<<<<<< HEAD
+    macports::doctor_main
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::doctor_main $opts
+>>>>>>> svn
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+<<<<<<< HEAD
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+>>>>>>> svn
+    macports::reclaim_main  
+    return 0
+}
+
+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 } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Version: "
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline "Platform: "
+    }
+    puts "${macports::os_platform} ${macports::os_major} ${macports::os_arch}"
+    return 0
+}
+
+
+proc action_dependents { action portlist opts } {
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set ilist {}
+
+    registry::open_dep_map
+
+    set status 0
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if { [catch {set ilist [registry::installed $portname $composite_version]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "$result" 1 status
+        } else {
+            # choose the active version if there is one
+            set index 0
+            foreach i $ilist {
+                if {[lindex $i 4]} {
+                    set found 1
+                    break
+                }
+                incr index
+            }
+            if {![info exists found]} {
+                set index 0
+            }
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist $index 0]
+            set iversion [lindex $ilist $index 1]
+            set irevision [lindex $ilist $index 2]
+            set ivariants [lindex $ilist $index 3]
+        }
+        
+        set deplist [registry::list_dependents $portname $iversion $irevision $ivariants]
+        if { [llength $deplist] > 0 } {
+            if {$action eq "rdependents"} {
+                set toplist $deplist
+                while 1 {
+                    set newlist {}
+                    foreach dep $deplist {
+                        set depname [lindex $dep 2]
+                        if {![info exists seen($depname)]} {
+                            set seen($depname) 1
+                            set rdeplist [registry::list_dependents $depname]
+                            foreach rdep $rdeplist {
+                                lappend newlist $rdep
+                            }
+                            set dependentsof($depname) $rdeplist
+                        }
+                    }
+                    if {[llength $newlist] > 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice "The following ports are dependent on ${portname}:"
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos >= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] <= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] && [string is true -strict $options(ports_rdependents_full)])} {
+                        puts "${spaces}${cur_portname}"
+                        set seen($cur_portname) 1
+                        incr cur_pos
+                        set pos_stack [lreplace $pos_stack end end $cur_pos]
+                        if {[info exists dependentsof($cur_portname)]} {
+                            lappend portstack $dependentsof($cur_portname)
+                            lappend pos_stack 0
+                        }
+                        continue
+                    }
+                    incr cur_pos
+                    set pos_stack [lreplace $pos_stack end end $cur_pos]
+                }
+            } else {
+                foreach dep $deplist {
+                    set depport [lindex $dep 2]
+                    if {[macports::ui_isset ports_quiet]} {
+                        ui_msg "$depport"
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg "$depport depends on $portname"
+                    } else {
+                        ui_msg "$depport depends on $portname (by [lindex $dep 1]:)"
+                    }
+                }
+            }
+        } else {
+            ui_notice "$portname has no dependents."
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator ""
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] && [string is true -strict $options(ports_${action}_no-build)]} {
+            set deptypes {depends_lib depends_run}
+        } else {
+            set deptypes {depends_fetch depends_extract depends_build depends_lib depends_run}
+        }
+
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne "file://."} {
+            # Extract the portdir from porturl and use it to search PortIndex.
+            # Only the last two elements of the path (porturl) make up the
+            # portdir.
+            set portdir [file split [macports::getportdir $porturl]]
+            set lsize [llength $portdir]
+            set portdir \
+                [file join [lindex $portdir [expr {$lsize - 2}]] \
+                           [lindex $portdir [expr {$lsize - 1}]]]
+            if {[catch {mportsearch $portdir no exact portdir} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Portdir $portdir not found" 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn "Portdir $portdir doesn't seem to belong to portname $portname"
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+            # Add any global_variations to the variations
+            # specified for the port, so we get dependencies right
+            array unset merged_variations
+            array set merged_variations [array get variations]
+            foreach { variation value } [array get global_variations] { 
+                if { ![info exists merged_variations($variation)] } { 
+                    set merged_variations($variation) $value 
+                } 
+            }
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn "port ${action} --index does not work with the 'current' pseudo-port"
+            continue
+        }
+        set portname $portinfo(name)
+
+        set deplist {}
+        set deps_output {}
+        set ndeps 0
+        array set labeldict {depends_fetch Fetch depends_extract Extract depends_build Build depends_lib Library depends_run Runtime}
+        # get list of direct deps
+        foreach type $deptypes {
+            if {[info exists portinfo($type)]} {
+                if {$action eq "rdeps" || [macports::ui_isset ports_verbose]} {
+                    foreach dep $portinfo($type) {
+                        lappend deplist $dep
+                    }
+                } else {
+                    foreach dep $portinfo($type) {
+                        lappend deplist [lindex [split $dep :] end]
+                    }
+                }
+                if {$action eq "deps"} {
+                    set label "$labeldict($type) Dependencies"
+                    lappend deps_output [wraplabel $label [join $deplist ", "] 0 [string repeat " " 22]]
+                    incr ndeps [llength $deplist]
+                    set deplist {}
+                }
+            }
+        }
+
+        set version $portinfo(version)
+        set revision $portinfo(revision)
+        if {[info exists portinfo(canonical_active_variants)]} {
+            set variants $portinfo(canonical_active_variants)
+        } else {
+            set variants {}
+        }
+
+        puts -nonewline $separator
+        if {$action eq "deps"} {
+            if {$ndeps == 0} {
+                ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+            } else {
+                ui_notice "Full Name: $portname @${version}_${revision}${variants}"
+                puts [join $deps_output "\n"]
+            }
+            set separator "--\n"
+            continue
+        }
+
+        set toplist $deplist
+        # gather all the deps
+        while 1 {
+            set newlist {}
+            foreach dep $deplist {
+                set depname [lindex [split $dep :] end]
+                if {![info exists seen($depname)]} {
+                    set seen($depname) 1
+                    
+                    # look up the dep
+                    if {[catch {mportlookup $depname} result]} {
+                        ui_debug "$::errorInfo"
+                        break_softcontinue "lookup of portname $depname failed: $result" 1 status
+                    }
+                    if {[llength $result] < 2} {
+                        break_softcontinue "Port $depname not found" 1 status
+                    }
+                    array unset portinfo
+                    array set portinfo [lindex $result 1]
+                    set porturl $portinfo(porturl)
+                    set options(subport) $portinfo(name)
+                    
+                    # open the portfile if requested
+                    if {!([info exists options(ports_${action}_index)] && $options(ports_${action}_index) eq "yes")} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug "$::errorInfo"
+                            break_softcontinue "Unable to open port: $result" 1 status
+                        }
+                        array unset portinfo
+                        array set portinfo [mportinfo $mport]
+                        mportclose $mport
+                    }
+                    
+                    # get list of the dep's deps
+                    set rdeplist {}
+                    foreach type $deptypes {
+                        if {[info exists portinfo($type)]} {
+                            foreach rdep $portinfo($type) {
+                                lappend rdeplist $rdep
+                                lappend newlist $rdep
+                            }
+                        }
+                    }
+                    set depsof($depname) $rdeplist
+                }
+            }
+            if {[llength $newlist] > 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] > 0} {
+            ui_notice "The following ports are dependencies of $portname @${version}_${revision}${variants}:"
+        } else {
+            ui_notice "$portname @${version}_${revision}${variants} has no dependencies."
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos >= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] <= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat " " [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] && [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts "${spaces}${cur_port}"
+                } else {
+                    puts "${spaces}${cur_portname}"
+                }
+                set seen($cur_portname) 1
+                incr cur_pos
+                set pos_stack [lreplace $pos_stack end end $cur_pos]
+                if {[info exists depsof($cur_portname)]} {
+                    lappend portstack $depsof($cur_portname)
+                    lappend pos_stack 0
+                }
+                continue
+            }
+            incr cur_pos
+            set pos_stack [lreplace $pos_stack end end $cur_pos]
+        }
+        set separator "--\n"
+    }
+    return $status
+}
+
+
+proc action_uninstall { action portlist opts } {
+    set status 0
+    if {[macports::global_option_isset port_uninstall_old]} {
+        # if -u then uninstall all inactive ports
+        # (union these to any other ports user has in the port list)
+        set portlist [opUnion $portlist [get_inactive_ports]]
+    } else {
+        # Otherwise the user hopefully supplied a portlist, or we'll default to the existing directory
+        if {[require_portlist portlist]} {
+            return 1
+        }
+    }
+    if {[prefix_unwritable]} {
+        return 1
+    }
+
+    set portlist [portlist_sortdependents $portlist]
+
+    foreachport $portlist {
+        if {![registry::entry_exists_for_name $portname]} {
+            # if the code path arrives here the port either isn't installed, or
+            # it doesn't exist at all. We can't be sure, but we can check the
+            # portindex whether a port by that name exists (in which case not
+            # uninstalling it is probably no problem). If there is no port by
+            # that name, alert the user in case of typos.
+            ui_info "$portname is not installed"
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn "no such port: $portname, skipping uninstall"
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            && ![catch {set ilist [registry::installed $portname $composite_version]}]
+            && [llength $ilist] == 1} {
+
+            set i [lindex $ilist 0]
+            set iactive [lindex $i 4]
+            set regref [registry::entry open $portname [lindex $i 1] [lindex $i 2] [lindex $i 3] [lindex $i 5]]
+            if {[registry::run_target $regref uninstall [array get options]]} {
+                continue
+            }
+        }
+
+        if { [catch {registry_uninstall::uninstall_composite $portname $composite_version [array get options]} result] } {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "port uninstall failed: $result" 1 status
+        }
+    }
+
+    return $status
+}
+
+
+proc action_installed { action portlist opts } {
+    global private_options
+    set status 0
+    set restrictedList 0
+    set ilist {}
+    
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreachport $portlist {
+            set composite_version [composite_version $portversion [array get variations]]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port installed failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] > 0 } {
+        ui_notice "The following ports are currently installed:"
+        foreach i [portlist_sortint $ilist] {
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [lindex $i 3]
+            set iactive [lindex $i 4]
+            set extra ""
+            set nvariants ""
+            if {[macports::ui_isset ports_verbose]} {
+                set regref [registry::open_entry $iname $iversion $irevision $ivariants [lindex $i 5]]
+                set nvariants [registry::property_retrieve $regref negated_variants]
+                if {$nvariants == 0} {
+                    set nvariants ""
+                }
+                set os_platform [registry::property_retrieve $regref os_platform]
+                set os_major [registry::property_retrieve $regref os_major]
+                set archs [registry::property_retrieve $regref archs]
+                if {$os_platform != 0 && $os_platform ne "" && $os_major != 0 && $os_major ne ""} {
+                    append extra " platform='$os_platform $os_major'"
+                }
+                if {$archs != 0 && $archs ne ""} {
+                    append extra " archs='$archs'"
+                }
+            }
+            if { $iactive == 0 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}"
+            } elseif { $iactive == 1 } {
+                puts "  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}"
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are installed."
+    } else {
+        ui_notice "No ports are installed."
+    }
+
+    return $status
+}
+
+
+proc action_outdated { action portlist opts } {
+    global private_options
+    set status 0
+
+    # If port names were supplied, limit ourselves to those ports, else check all installed ports
+    set ilist {}
+    set restrictedList 0
+    if { [llength $portlist] || (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq "no")} {
+        set restrictedList 1
+        foreach portspec $portlist {
+            array set port $portspec
+            set portname $port(name)
+            set composite_version [composite_version $port(version) $port(variants)]
+            if { [catch {set ilist [concat $ilist [registry::installed $portname $composite_version]]} result] } {
+                if {![string match "* not registered as installed." $result]} {
+                    global errorInfo
+                    ui_debug "$errorInfo"
+                    break_softcontinue "port outdated failed: $result" 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne "Registry error: No ports registered as installed."} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                ui_error "port installed failed: $result"
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] > 0 } {
+        foreach i [portlist_sortint $ilist] {
+        
+            # Get information about the installed port
+            set portname [lindex $i 0]
+            set installed_version [lindex $i 1]
+            set installed_revision [lindex $i 2]
+            set installed_compound "${installed_version}_${installed_revision}"
+
+            set is_active [lindex $i 4]
+            if {$is_active == 0} {
+                continue
+            }
+            set installed_epoch [lindex $i 5]
+
+            # Get info about the port from the index
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts "$portname ($installed_compound is installed; the port was not found in the port index)"
+                }
+                continue
+            }
+            array unset portinfo
+            array set portinfo [lindex $res 1]
+            
+            # Get information about latest available version and revision
+            if {![info exists portinfo(version)]} {
+                ui_warn "$portname has no version field"
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] && $portinfo(revision) > 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound "${latest_version}_${latest_revision}"
+            set latest_epoch 0
+            if {[info exists portinfo(epoch)]} { 
+                set latest_epoch $portinfo(epoch)
+            }
+            
+            # Compare versions, first checking epoch, then version, then revision
+            set epoch_comp_result [expr {$installed_epoch - $latest_epoch}]
+            set comp_result [vercmp $installed_version $latest_version]
+            if { $comp_result == 0 } {
+                set comp_result [expr {$installed_revision - $latest_revision}]
+            }
+            set reason ""
+            if {$epoch_comp_result != 0 && $installed_version != $latest_version} {
+                if {($comp_result >= 0 && $epoch_comp_result < 0) || ($comp_result <= 0 && $epoch_comp_result > 0)} {
+                    set reason { (epoch $installed_epoch $relation $latest_epoch)}
+                }
+                set comp_result $epoch_comp_result
+            } elseif {$comp_result == 0} {
+                set regref [registry::open_entry $portname $installed_version $installed_revision [lindex $i 3] $installed_epoch]
+                set os_platform_installed [registry::property_retrieve $regref os_platform]
+                set os_major_installed [registry::property_retrieve $regref os_major]
+                if {$os_platform_installed ne "" && $os_platform_installed != 0
+                    && $os_major_installed ne "" && $os_major_installed != 0
+                    && ($os_platform_installed != ${macports::os_platform} || $os_major_installed != ${macports::os_major})} {
+                    set comp_result -1
+                    set reason { (platform $os_platform_installed $os_major_installed != ${macports::os_platform} ${macports::os_major})}
+                }
+            }
+            
+            # Report outdated (or, for verbose, predated) versions
+            if { $comp_result != 0 } {
+                            
+                # Form a relation between the versions
+                set flag ""
+                if { $comp_result > 0 } {
+                    set relation ">"
+                    set flag "!"
+                } else {
+                    set relation "<"
+                }
+                
+                # Emit information
+                if {$comp_result < 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice "The following installed ports are outdated:"
+                    }
+                    incr num_outdated
+
+                    puts [format "%-30s %-24s %1s" $portname "$installed_compound $relation $latest_compound [subst $reason]" $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice "No installed ports are outdated."
+        }
+    } elseif { $restrictedList } {
+        ui_notice "None of the specified ports are outdated."
+    } else {
+        ui_notice "No ports are installed."
+    }
+    
+    return $status
+}
+
+
+proc action_contents { action portlist opts } {
+    global global_options
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {[info exists global_options(ports_contents_size)]} {
+        set units {}
+        if {[info exists global_options(ports_contents_units)]} {
+            set units [complete_size_units $global_options(ports_contents_units)]
+        }
+        set outstring {[format "%12s $file" [filesize $file $units]]}
+    } else {
+        set outstring {  $file}
+    }
+
+    foreachport $portlist {
+        if { ![catch {set ilist [registry::installed $portname]} result] } {
+            # set portname again since the one we were passed may not have had the correct case
+            set portname [lindex $ilist 0 0]
+        }
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                ui_notice "Port $portname contains:"
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice "Port $portname does not contain any files or is not active."
+            }
+        } else {
+            ui_notice "Port $portname is not installed."
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq "K" || $units eq "Ki"} {
+        return "KiB"
+    } elseif {$units eq "k"} {
+        return "kB"
+    } elseif {$units eq "Mi"} {
+        return "MiB"
+    } elseif {$units eq "M"} {
+        return "MB"
+    } elseif {$units eq "Gi"} {
+        return "GiB"
+    } elseif {$units eq "G"} {
+        return "GB"
+    } else {
+        return $units
+    }
+}
+
+# Show space used by the given ports' files
+proc action_space {action portlist opts} {
+    global global_options
+    require_portlist portlist
+
+    set units {}
+    if {[info exists global_options(ports_space_units)]} {
+        set units [complete_size_units $global_options(ports_space_units)]
+    }
+    set spaceall 0.0
+    foreachport $portlist {
+        set space 0.0
+        set files [registry::port_registered $portname]
+        if { $files != 0 } {
+            if { [llength $files] > 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne "yes"} {
+                    set msg "[bytesize $space $units] $portname"
+                    if { $portversion != {} } {
+                        append msg " @$portversion"
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr "Port $portname does not contain any file or is not active."
+            }
+        } else {
+            puts stderr "Port $portname is not installed."
+        }
+    }
+    if {[llength $portlist] > 1 || ([info exists options(ports_space_total)] && $options(ports_space_total) eq "yes")} {
+        puts "[bytesize $spaceall $units] total"
+    }
+    return 0
+}
+
+proc action_variants { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        if {$porturl eq ""} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $result] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] && $options(ports_variants_index) eq "yes")} {
+            if {![info exists options(subport)]} {
+                if {[info exists portinfo(name)]} {
+                    set options(subport) $portinfo(name)
+                } else {
+                    set options(subport) $portname
+                }
+            }
+            if {[catch {set mport [mportopen $porturl [array get options] [array get variations]]} result]} {
+                ui_debug "$::errorInfo"
+                break_softcontinue "Unable to open port: $result" 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+            if {[info exists portdir]} {
+                set portinfo(portdir) $portdir
+            }
+        } elseif {![info exists portinfo]} {
+            ui_warn "port variants --index does not work with 'current' pseudo-port"
+            continue
+        }
+
+        # set portname again since the one we were passed may not have had the correct case
+        set portname $portinfo(name)
+
+        # if this fails the port doesn't have any variants
+        if {![info exists portinfo(variants)]} {
+            ui_notice "$portname has no variants"
+        } else {
+            array unset vinfo
+            # Use the new format if it exists.
+            if {[info exists portinfo(vinfo)]} {
+                array set vinfo $portinfo(vinfo)
+            # Otherwise fall back to the old format.
+            } elseif {[info exists portinfo(variant_desc)]} {
+                array set vdescriptions $portinfo(variant_desc)
+            }
+
+            # print out all the variants
+            ui_notice "$portname has the variants:"
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier "   "
+                # Retrieve variants' information from the new format.
+                if {[info exists vinfo]} {
+                    array unset variant
+                    array set variant $vinfo($v)
+
+                    # Retrieve conflicts, description, is_default, and
+                    # vrequires.
+                    if {[info exists variant(conflicts)]} {
+                        set vconflicts $variant(conflicts)
+                    }
+                    if {[info exists variant(description)]} {
+                        set vdescription $variant(description)
+                    }
+
+                    # XXX Keep these varmodifiers in sync with action_info, or create a wrapper for it
+                    if {[info exists variations($v)]} {
+                        set varmodifier "  $variations($v)"
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier "($global_variations($v))"
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier "\[$variant(is_default)\]"
+                    }
+                    if {[info exists variant(requires)]} {
+                        set vrequires $variant(requires)
+                    }
+                # Retrieve variants' information from the old format,
+                # which only consists of the description.
+                } elseif {[info exists vdescriptions($v)]} {
+                    set vdescription $vdescriptions($v)
+                }
+
+                if {[info exists vdescription]} {
+                    puts [wraplabel "$varmodifier$v" [string trim $vdescription] 0 [string repeat " " [expr 5 + [string length $v]]]]
+                } else {
+                    puts "$varmodifier$v"
+                }
+                if {[info exists vconflicts]} {
+                    puts "     * conflicts with [string trim $vconflicts]"
+                }
+                if {[info exists vrequires]} {
+                    puts "     * requires [string trim $vrequires]"
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        ui_error "You must specify a search pattern"
+        return 1
+    }
+
+    # Copy global options as we are going to modify the array
+    array set options [array get global_options]
+
+    if {[info exists options(ports_search_depends)] && $options(ports_search_depends) eq "yes"} {
+        array unset options ports_search_depends
+        set options(ports_search_depends_fetch) yes
+        set options(ports_search_depends_extract) yes
+        set options(ports_search_depends_build) yes
+        set options(ports_search_depends_lib) yes
+        set options(ports_search_depends_run) yes
+    }
+
+    # Array to hold given filters
+    array set filters {}
+    # Default matchstyle
+    set filter_matchstyle "none"
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne "yes" } {
+            continue
+        }
+        switch -- $opt {
+            exact -
+            glob {
+                set filter_matchstyle $opt
+                continue
+            }
+            regex {
+                set filter_matchstyle regexp
+                continue
+            }
+            case-sensitive {
+                set filter_case yes
+                continue
+            }
+            line {
+                continue
+            }
+        }
+
+        set filters($opt) "yes"
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) "yes"
+        set filters(description) "yes"
+    }
+
+    set separator ""
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq "none"} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first "*" $portname] == -1 && [string first "?" $portname] == -1} {
+                set searchstring "*$portname*"
+            }
+            set matchstyle glob
+        }
+
+        set res {}
+        set portfound 0
+        foreach { opt } [array get filters] {
+            # Map from friendly name
+            set opt [map_friendly_field_names $opt]
+
+            if {[catch {eval set matches \[mportsearch \$searchstring $filter_case \$matchstyle $opt\]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for name $portname failed: $result" 1 status
+            }
+
+            set tmp {}
+            foreach {name info} $matches {
+                add_to_portlist tmp [concat [list name $name] $info]
+            }
+            set res [opUnion $res $tmp]
+        }
+        set res [portlist_sort $res]
+
+        set joiner ""
+        foreach info $res {
+            array unset portinfo
+            array set portinfo $info
+
+            # XXX is this the right place to verify an entry?
+            if {![info exists portinfo(name)]} {
+                puts stderr "Invalid port entry, missing portname"
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing description"
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr "Invalid port entry for $portinfo(name), missing version"
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        && $options(ports_search_line) eq "yes"} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts "$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)"
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts "$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)"
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline "$portinfo(name) @$portinfo(version)"
+                    if {[info exists portinfo(revision)] && $portinfo(revision) > 0} {
+                        puts -nonewline "_$portinfo(revision)"
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline " ([join $portinfo(categories) ", "])"
+                    }
+                    puts ""
+                    puts [wrap [join $portinfo(description)] 0 [string repeat " " 4]]
+                }
+            }
+
+            set joiner "\n"
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice "No match for $portname found"
+        } elseif {[llength $res] > 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne "yes")} {
+                ui_notice "\nFound [llength $res] ports."
+            }
+        }
+
+        set separator "--\n"
+    }
+
+    array unset options
+    array unset filters
+
+    return $status
+}
+
+
+proc action_list { action portlist opts } {
+    global private_options
+    set status 0
+    
+    # Default to list all ports if no portnames are supplied
+    if { ![llength $portlist] && [info exists private_options(ports_no_args)] && $private_options(ports_no_args) eq "yes"} {
+        add_to_portlist portlist [list name "-all-"]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq "-all-"} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "listing all ports failed: $result" 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "search for portname $search_string failed: $result" 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir ""
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format "%-30s @%-14s %s" $portinfo(name) $portinfo(version) $outdir]
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_echo { action portlist opts } {
+    global global_options
+
+    # Simply echo back the port specs given to this command
+    foreachport $portlist {
+        if {![macports::ui_isset ports_quiet]} {
+            set opts {}
+            foreach { key value } [array get options] {
+                if {![info exists global_options($key)]} {
+                    lappend opts "$key=$value"
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne "" } {
+                set ver_field "@$composite_version"
+            } else {
+                set ver_field ""
+            }
+            puts [format "%-30s %s %s" $portname $ver_field  [join $opts " "]]
+        } else {
+            puts "$portname"
+        }
+    }
+
+    return 0
+}
+
+
+proc action_portcmds { action portlist opts } {
+    # Operations on the port's directory and Portfile
+    global env boot_env current_portdir
+
+    array set local_options $opts
+    
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific, otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                break_softcontinue "Port $portname not found" 1 status
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+            set portname $portinfo(name)
+        }
+        
+        
+        # Calculate portdir, porturl, and portfile from initial porturl
+        set portdir [file normalize [macports::getportdir $porturl]]
+        set porturl "file://${portdir}";    # Rebuild url so it's fully qualified
+        set portfile "${portdir}/Portfile"
+        
+        # Now execute the specific action
+        if {[file readable $portfile]} {
+            switch -- $action {
+                cat {
+                    # Copy the portfile to standard output
+                    set f [open $portfile RDONLY]
+                    while { ![eof $f] } {
+                        puts -nonewline [read $f 4096]
+                    }
+                    close $f
+                }
+                
+                edit {
+                    # Edit the port's portfile with the user's editor
+                    
+                    # Restore our entire environment from start time.
+                    # We need it to evaluate the editor, and the editor
+                    # may want stuff from it as well, like TERM.
+                    array unset env_save; array set env_save [array get env]
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor ""
+                    set editor_var "ports_${action}_editor"
+                    if {[info exists local_options($editor_var)]} {
+                        set editor [join $local_options($editor_var)]
+                    } else {
+                        foreach ed { MP_EDITOR VISUAL EDITOR } {
+                            if {[info exists env($ed)]} {
+                                set editor $env($ed)
+                                break
+                            }
+                        }
+                    }
+                    
+                    # Use a reasonable canned default if no editor specified or set in env
+                    if { $editor eq "" } { set editor "/usr/bin/vi" }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec >@stdout <@stdin 2>@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug "$errorInfo"
+                        break_softcontinue "unable to invoke editor $editor: $result" 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq "10.5"} {
+                        unsetenv *
+                    }
+                    array set env [array get env_save]
+                }
+
+                dir {
+                    # output the path to the port's directory
+                    puts $portdir
+                }
+
+                work {
+                    # output the path to the port's work directory
+                    set workpath [macports::getportworkpath_from_portdir $portdir $portname]
+                    if {[file exists $workpath]} {
+                        puts $workpath
+                    }
+                }
+
+                cd {
+                    # Change to the port's directory, making it the default
+                    # port for any future commands
+                    set current_portdir $portdir
+                }
+
+                url {
+                    # output the url of the port's directory, suitable to feed back in later as a port descriptor
+                    puts $porturl
+                }
+
+                file {
+                    # output the path to the port's portfile
+                    puts $portfile
+                }
+
+                logfile {
+                    set logfile [file join [macports::getportlogpath $portdir $portname] "main.log"]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error "Log file not found for port in $portdir"
+                    }
+                }
+
+                gohome {
+                    set homepage ""
+
+                    # Get the homepage as read from PortIndex
+                    if {[info exists portinfo(homepage)]} {
+                        set homepage $portinfo(homepage)
+                    }
+
+                    # If not available, get the homepage for the port by opening the Portfile
+                    if {$homepage eq "" && ![catch {set ctx [mportopen $porturl]} result]} {
+                        array set portinfo [mportinfo $ctx]
+                        if {[info exists portinfo(homepage)]} {
+                            set homepage $portinfo(homepage)
+                        }
+                        mportclose $ctx
+                    }
+
+                    # Try to open a browser to the homepage for the given port
+                    if { $homepage ne "" } {
+                        if {[catch {system "${macports::autoconf::open_path} '$homepage'"} result]} {
+                            global errorInfo
+                            ui_debug "$errorInfo"
+                            break_softcontinue "unable to invoke browser using ${macports::autoconf::open_path}: $result" 1 status
+                        }
+                    } else {
+                        ui_error [format "No homepage for %s" $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue "Could not read $portfile" 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_sync { action portlist opts } {
+    global global_options
+
+    set status 0
+    if {[catch {mportsync [array get global_options]} result]} {
+        global errorInfo
+        ui_debug "$errorInfo"
+        ui_msg "port sync failed: $result"
+        set status 1
+    }
+    
+    return $status
+}
+
+
+proc action_target { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    if {($action eq "install" || $action eq "archive") && [prefix_unwritable] && ![macports::global_option_isset ports_dryrun]} {
+        return 1
+    }
+    foreachport $portlist {
+        array unset portinfo
+        # If we have a url, use that, since it's most specific
+        # otherwise try to map the portname to a url
+        if {$porturl eq ""} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug "$errorInfo"
+                break_softcontinue "lookup of portname $portname failed: $result" 1 status
+            }
+            if {[llength $res] < 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn "Skipping $portname (not in the ports tree)"
+                    continue
+                } else {
+                    break_softcontinue "Port $portname not found" 1 status
+                }
+            }
+            array set portinfo [lindex $res 1]
+            set porturl $portinfo(porturl)
+        }
+
+        # use existing variants iff none were explicitly requested
+        if {[array get requested_variations] eq "" && [array get variations] ne ""} {
+            array unset requested_variations
+            array set requested_variations [array get variations]
+        }
+
+        # Add any global_variations to the variations
+        # specified for the port
+        foreach { variation value } [array get global_variations] {
+            if { ![info exists requested_variations($variation)] } {
+                set requested_variations($variation) $value
+            }
+        }
+
+        # If version was specified, save it as a version glob for use
+        # in port actions (e.g. clean).
+        if {[string length $portversion]} {
+            set options(ports_version_glob) $portversion
+        }
+        # if installing, mark the port as explicitly requested
+        if {$action eq "install"} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq "archive"} {
+            set target install
+        } else {
+            set target $action
+        }
+        if {![info exists options(subport)]} {
+            if {[info exists portinfo(name)]} {
+                set options(subport) $portinfo(name)
+            } else {
+                set options(subport) $portname
+            }
+        }
+        if {[catch {set workername [mportopen $porturl [array get options] [array get requested_variations]]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to open port: $result" 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug "$errorInfo"
+            break_softcontinue "Unable to execute port: $result" 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue "Processing of port $portname failed" 1 status
+        }
+    }
+    
+    if {$status == 0 && $action eq "install" && ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] && ![info exists options(ports_install_no-rev-upgrade)] && ${macports::revupgrade_autorun}} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+
+proc action_exit { action portlist opts } {
+    # Return a semaphore telling the main loop to quit
+    return -999
+}
+
+
+##########################################
+# Command Parsing
+##########################################
+proc moreargs {} {
+    global cmd_argn cmd_argc
+    return [expr {$cmd_argn < $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn < $cmd_argc} {
+        return [lindex $cmd_argv $cmd_argn]
+    } else {
+        return _EOF_
+    }
+}
+
+
+proc advance {} {
+    global cmd_argn
+    incr cmd_argn
+}
+
+
+proc match s {
+    if {[lookahead] == $s} {
+        advance
+        return 1
+    }
+    return 0
+}
+
+# action_array specifies which action to run on the given command
+# and if the action wants an expanded portlist.
+# The value is a list of the form {action expand},
+# where action is a string and expand a value:
+#   0 none        Does not expect any text argument
+#   1 strings     Expects some strings as text argument
+#   2 ports       Wants an expanded list of ports as text argument
+global action_array
+
+# Define global constants
+const ACTION_ARGS_NONE 0
+const ACTION_ARGS_STRINGS 1
+const ACTION_ARGS_PORTS 2
+
+array set action_array [list \
+    usage       [list action_usage          [ACTION_ARGS_STRINGS]] \
+    help        [list action_help           [ACTION_ARGS_STRINGS]] \
+    \
+    echo        [list action_echo           [ACTION_ARGS_PORTS]] \
+    \
+    info        [list action_info           [ACTION_ARGS_PORTS]] \
+    location    [list action_location       [ACTION_ARGS_PORTS]] \
+    notes       [list action_notes          [ACTION_ARGS_PORTS]] \
+    provides    [list action_provides       [ACTION_ARGS_STRINGS]] \
+    log         [list action_log            [ACTION_ARGS_PORTS]] \
+    \
+    activate    [list action_activate       [ACTION_ARGS_PORTS]] \
+    deactivate  [list action_deactivate     [ACTION_ARGS_PORTS]] \
+    \
+    select      [list action_select         [ACTION_ARGS_STRINGS]] \
+    \
+    sync        [list action_sync           [ACTION_ARGS_NONE]] \
+    selfupdate  [list action_selfupdate     [ACTION_ARGS_NONE]] \
+    \
+    setrequested   [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    unsetrequested [list action_setrequested  [ACTION_ARGS_PORTS]] \
+    \
+    upgrade     [list action_upgrade        [ACTION_ARGS_PORTS]] \
+    rev-upgrade [list action_revupgrade     [ACTION_ARGS_NONE]] \
+    reclaim     [list action_reclaim        [ACTION_ARGS_NONE]] \
+    doctor      [list action_doctor         [ACTION_ARGS_NONE]] \
+    \
+    version     [list action_version        [ACTION_ARGS_NONE]] \
+    platform    [list action_platform       [ACTION_ARGS_NONE]] \
+    \
+    uninstall   [list action_uninstall      [ACTION_ARGS_PORTS]] \
+    \
+    installed   [list action_installed      [ACTION_ARGS_PORTS]] \
+    outdated    [list action_outdated       [ACTION_ARGS_PORTS]] \
+    contents    [list action_contents       [ACTION_ARGS_PORTS]] \
+    space       [list action_space          [ACTION_ARGS_PORTS]] \
+    dependents  [list action_dependents     [ACTION_ARGS_PORTS]] \
+    rdependents [list action_dependents     [ACTION_ARGS_PORTS]] \
+    deps        [list action_deps           [ACTION_ARGS_PORTS]] \
+    rdeps       [list action_deps           [ACTION_ARGS_PORTS]] \
+    variants    [list action_variants       [ACTION_ARGS_PORTS]] \
+    \
+    search      [list action_search         [ACTION_ARGS_STRINGS]] \
+    list        [list action_list           [ACTION_ARGS_PORTS]] \
+    \
+    edit        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cat         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    dir         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    work        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    cd          [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    url         [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    file        [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    logfile     [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    gohome      [list action_portcmds       [ACTION_ARGS_PORTS]] \
+    \
+    fetch       [list action_target         [ACTION_ARGS_PORTS]] \
+    checksum    [list action_target         [ACTION_ARGS_PORTS]] \
+    extract     [list action_target         [ACTION_ARGS_PORTS]] \
+    patch       [list action_target         [ACTION_ARGS_PORTS]] \
+    configure   [list action_target         [ACTION_ARGS_PORTS]] \
+    build       [list action_target         [ACTION_ARGS_PORTS]] \
+    destroot    [list action_target         [ACTION_ARGS_PORTS]] \
+    install     [list action_target         [ACTION_ARGS_PORTS]] \
+    clean       [list action_target         [ACTION_ARGS_PORTS]] \
+    test        [list action_target         [ACTION_ARGS_PORTS]] \
+    lint        [list action_target         [ACTION_ARGS_PORTS]] \
+    livecheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    distcheck   [list action_target         [ACTION_ARGS_PORTS]] \
+    mirror      [list action_target         [ACTION_ARGS_PORTS]] \
+    load        [list action_target         [ACTION_ARGS_PORTS]] \
+    unload      [list action_target         [ACTION_ARGS_PORTS]] \
+    distfiles   [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    archivefetch [list action_target         [ACTION_ARGS_PORTS]] \
+    archive     [list action_target         [ACTION_ARGS_PORTS]] \
+    unarchive   [list action_target         [ACTION_ARGS_PORTS]] \
+    dmg         [list action_target         [ACTION_ARGS_PORTS]] \
+    mdmg        [list action_target         [ACTION_ARGS_PORTS]] \
+    dpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    mpkg        [list action_target         [ACTION_ARGS_PORTS]] \
+    pkg         [list action_target         [ACTION_ARGS_PORTS]] \
+    portpkg     [list action_target         [ACTION_ARGS_PORTS]] \
+    rpm         [list action_target         [ACTION_ARGS_PORTS]] \
+    srpm        [list action_target         [ACTION_ARGS_PORTS]] \
+    \
+    quit        [list action_exit           [ACTION_ARGS_NONE]] \
+    exit        [list action_exit           [ACTION_ARGS_NONE]] \
+]
+
+# Expand "action".
+# Returns an action proc, or a list of matching action procs, or the action passed in
+proc find_action { action } {
+    global action_array
+    
+    if { ! [info exists action_array($action)] } {
+        set guess [guess_action $action]
+        if { [info exists action_array($guess)] } {
+            return $guess
+        }
+        return $guess
+    }
+    
+    return $action
+}
+
+# Expand action
+# If there's more than one match, return the next possibility
+proc find_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    } else {
+        set action [complete_action $action]
+        if { [info exists action_array($action)] } {
+            set action_proc [lindex $action_array($action) 0]
+        }
+    }
+    
+    return $action_proc
+}
+
+proc get_action_proc { action } {
+    global action_array
+    
+    set action_proc ""
+    if { [info exists action_array($action)] } {
+        set action_proc [lindex $action_array($action) 0]
+    }
+    
+    return $action_proc
+}
+
+# Returns whether an action expects text arguments at all,
+# expects text arguments or wants an expanded list of ports
+# Return values are constants:
+#   [ACTION_ARGS_NONE]     Does not expect any text argument
+#   [ACTION_ARGS_STRINGS]  Expects some strings as text argument
+#   [ACTION_ARGS_PORTS]    Wants an expanded list of ports as text argument
+proc action_needs_portlist { action } {
+    global action_array
+
+    set ret 0
+    if {[info exists action_array($action)]} {
+        set ret [lindex $action_array($action) 1]
+    }
+
+    return $ret
+}
+
+# cmd_opts_array specifies which arguments the commands accept
+# Commands not listed here do not accept any arguments
+# Syntax if {option argn}
+# Where option is the name of the option and argn specifies how many arguments
+# this argument takes
+global cmd_opts_array
+array set cmd_opts_array {
+    edit        {{editor 1}}
+    info        {category categories depends_fetch depends_extract
+                 depends_build depends_lib depends_run
+                 depends description epoch fullname heading homepage index license
+                 line long_description
+                 maintainer maintainers name platform platforms portdir pretty
+                 replaced_by revision subports variant variants version}
+    contents    {size {units 1}}
+    deps        {index no-build}
+    rdeps       {index no-build full}
+    rdependents {full}
+    search      {case-sensitive category categories depends_fetch
+                 depends_extract depends_build depends_lib depends_run
+                 depends description epoch exact glob homepage line
+                 long_description maintainer maintainers name platform
+                 platforms portdir regex revision variant variants version}
+    selfupdate  {nosync}
+    space       {{units 1} total}
+    activate    {no-exec}
+    deactivate  {no-exec}
+    install     {no-rev-upgrade unrequested}
+    uninstall   {follow-dependents follow-dependencies no-exec}
+    variants    {index}
+    clean       {all archive dist work logs}
+    mirror      {new}
+    lint        {nitpick}
+    select      {list set show summary}
+    log         {{phase 1} {level 1}}
+    upgrade     {force enforce-variants no-replace no-rev-upgrade}
+    rev-upgrade {id-loadcmd-check}
+    doctor      {quiet}
+}
+
+##
+# Checks whether the given option is valid
+#
+# @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} {
+    global cmd_opts_array
+
+    # This could be so easy with lsearch -index,
+    # but that's only available as of Tcl 8.5
+
+    if {![info exists cmd_opts_array($action)]} {
+        return {}
+    }
+
+    set result {}
+
+    foreach item $cmd_opts_array($action) {
+        if {[llength $item] == 1} {
+            set name $item
+            set argc 0
+        } else {
+            set name [lindex $item 0]
+            set argc [lindex $item 1]
+        }
+
+        if {$name == $option} {
+            set result [list [list $name $argc]]
+            break
+        } elseif {[string first $option $name] == 0} {
+            lappend result [list $name $argc]
+        }
+    }
+
+    return $result
+}
+
+# Parse global options
+#
+# Note that this is called several times:
+#   (1) Initially, to parse options that will be constant across all commands
+#       (options that come prior to any command, frozen into global_options_base)
+#   (2) Following each command (to parse options that will be unique to that command
+#       (the global_options array is reset to global_options_base prior to each command)
+#
+proc parse_options { action ui_options_name global_options_name } {
+    upvar $ui_options_name ui_options
+    upvar $global_options_name global_options
+    global cmdname cmd_opts_array
+    
+    while {[moreargs]} {
+        set arg [lookahead]
+        
+        if {[string index $arg 0] ne "-"} {
+            break
+        } elseif {[string index $arg 1] eq "-"} {
+            # Process long arguments
+            switch -- $arg {
+                -- { # This is the options terminator; do no further option processing
+                    advance; break
+                }
+                default {
+                    set key [string range $arg 2 end]
+                    set kopts [cmd_option_matches $action $key]
+                    if {[llength $kopts] == 0} {
+                        return -code error "${action} does not accept --${key}"
+                    } elseif {[llength $kopts] > 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst "--[lindex $e 0]"
+                        }
+                        return -code error "\"port ${action} --${key}\" is ambiguous: \n  port ${action} [join $errlst "\n  port ${action} "]"
+                    }
+                    set key   [lindex $kopts 0 0]
+                    set kargc [lindex $kopts 0 1]
+                    if {$kargc == 0} {
+                        set global_options(ports_${action}_${key}) yes
+                    } else {
+                        set args {}
+                        while {[moreargs] && $kargc > 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc > 0} {
+                            return -code error "--${key} expects [expr {$kargc + [llength $args]}] parameters!"
+                        }
+                        set global_options(ports_${action}_${key}) $args
+                    }
+                }
+            }
+        } else {
+            # Process short arg(s)
+            set opts [string range $arg 1 end]
+            foreach c [split $opts {}] {
+                switch -- $c {
+                    v {
+                        set ui_options(ports_verbose) yes
+                    }
+                    d {
+                        set ui_options(ports_debug) yes
+                        # debug implies verbose
+                        set ui_options(ports_verbose) yes
+                    }
+                    q {
+                        set ui_options(ports_quiet) yes
+                    }
+                    p {
+                        # Ignore errors while processing within a command
+                        set ui_options(ports_processall) yes
+                    }
+                    f {
+                        set global_options(ports_force) yes
+                    }
+                    o {
+                        set global_options(ports_ignore_different) yes
+                    }
+                    n {
+                        set global_options(ports_nodeps) yes
+                    }
+                    u {
+                        set global_options(port_uninstall_old) yes
+                    }
+                    R {
+                        set global_options(ports_do_dependents) yes
+                    }
+                    s {
+                        set global_options(ports_source_only) yes
+                    }
+                    b {
+                        set global_options(ports_binary_only) yes
+                    }
+                    c {
+                        set global_options(ports_autoclean) yes
+                    }
+                    k {
+                        set global_options(ports_autoclean) no
+                    }
+                    t {
+                        set global_options(ports_trace) yes
+                    }
+                    y {
+                        set global_options(ports_dryrun) yes
+                    }
+                    F {
+                        # Name a command file to process
+                        advance
+                        if {[moreargs]} {
+                            lappend ui_options(ports_commandfiles) [lookahead]
+                        }
+                    }
+                    D {
+                        advance
+                        if {[moreargs]} {
+                            cd [lookahead]
+                        }
+                        break
+                    }
+                    default {
+                        print_usage; exit 1
+                    }
+                }
+            }
+        }
+
+        advance
+    }
+}
+
+# acquire exclusive registry lock for actions that need it
+# returns 1 if locked, 0 otherwise
+proc lock_reg_if_needed {action} {
+    switch -- $action {
+        activate -
+        deactivate -
+        setrequested -
+        unsetrequested -
+        upgrade -
+        uninstall -
+        install {
+            registry::exclusive_lock
+            return 1
+        }
+    }
+    return 0
+}
+
+proc process_cmd { argv } {
+    global cmd_argc cmd_argv cmd_argn \
+           global_options global_options_base private_options ui_options \
+           current_portdir
+    set cmd_argv $argv
+    set cmd_argc [llength $argv]
+    set cmd_argn 0
+
+    set action_status 0
+
+    # Process an action if there is one
+    while {($action_status == 0 || [macports::ui_isset ports_processall]) && [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == ";" } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == "#" } {
+            while { [moreargs] } { advance }
+            break
+        }
+
+        set locked [lock_reg_if_needed $action]
+        # Always start out processing an action in current_portdir
+        cd $current_portdir
+        
+        # Reset global_options from base before each action, as we munge it just below...
+        array unset global_options
+        array set global_options $global_options_base
+        
+        # Find an action to execute
+        set actions [find_action $action]
+        if {[llength $actions] == 1} {
+            set action [lindex $actions 0]
+            set action_proc [get_action_proc $action]
+        } else {
+            if {[llength $actions] > 1} {
+                ui_error "\"port ${action}\" is ambiguous: \n  port [join $actions "\n  port "]"
+            } else {
+                ui_error "Unrecognized action \"port $action\""
+            }
+            set action_status 1
+            break
+        }
+
+        # Parse options that will be unique to this action
+        # (to avoid abiguity with -variants and a default port, either -- must be
+        # used to terminate option processing, or the pseudo-port current must be specified).
+        if {[catch {parse_options $action ui_options global_options} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            ui_error $result
+            set action_status 1
+            break
+        }
+
+        # What kind of arguments does the command expect?
+        set expand [action_needs_portlist $action]
+
+        # Parse action arguments, setting a special flag if there were none
+        # We otherwise can't tell the difference between arguments that evaluate
+        # to the empty set, and the empty set itself.
+        set portlist {}
+        switch -- [lookahead] {
+            ;       -
+            _EOF_ {
+                set private_options(ports_no_args) yes
+            }
+            default {
+                if {[ACTION_ARGS_NONE] == $expand} {
+                    ui_error "$action does not accept string arguments"
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] && ![match ";"] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error "Improper expression syntax while processing parameters"
+                        set action_status 1
+                        break
+                    }
+                }
+            }
+        }
+        
+        # execute the action
+        set action_status [$action_proc $action $portlist [array get global_options]]
+
+        # unlock if needed
+        if {$locked} {
+            registry::exclusive_unlock
+        }
+
+        # Print notifications of just-activated ports.
+        portclient::notifications::display
+
+        # semaphore to exit
+        if {$action_status == -999} break
+    }
+    
+    return $action_status
+}
+
+
+proc complete_portname { text state } { 
+    global complete_choices complete_position
+    
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices {}
+
+        # Build a list of ports with text as their prefix
+        if {[catch {set res [mportsearch "${text}*" false glob]} result]} {
+            global errorInfo
+            ui_debug "$errorInfo"
+            fatal "search for portname $pattern failed: $result"
+        }
+        foreach {name info} $res {
+            lappend complete_choices $name
+        }
+    }
+    
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+    
+    return $word
+}
+
+
+# return text action beginning with $text
+proc complete_action { text state } {   
+    global action_array complete_choices complete_position
+
+    if {$state == 0} {
+        set complete_position 0
+        set complete_choices [array names action_array "[string tolower $text]*"]
+    }
+
+    set word [lindex $complete_choices $complete_position]
+    incr complete_position
+
+    return $word
+}
+
+# return all actions beginning with $text
+proc guess_action { text } {   
+    global action_array
+
+    return [array names action_array "[string tolower $text]*"]
+
+    if { [llength $complete_choices ] == 1 } {
+        return [lindex $complete_choices 0]
+    }
+
+    return {}
+}
+
+proc attempt_completion { text word start end } {
+    # If the word starts with '~', or contains '.' or '/', then use the build-in
+    # completion to complete the word
+    if { [regexp {^~|[/.]} $word] } {
+        return ""
+    }
+
+    # Decide how to do completion based on where we are in the string
+    set prefix [string range $text 0 [expr {$start - 1}]]
+    
+    # If only whitespace characters preceed us, or if the
+    # previous non-whitespace character was a ;, then we're
+    # an action (the first word of a command)
+    if { [regexp {(^\s*$)|(;\s*$)} $prefix] } {
+        return complete_action
+    }
+    
+    # Otherwise, do completion on portname
+    return complete_portname
+}
+
+
+proc get_next_cmdline { in out use_readline prompt linename } {
+    upvar $linename line
+    
+    set line ""
+    while { $line eq "" } {
+
+        if {$use_readline} {
+            set len [readline read -attempted_completion attempt_completion line $prompt]
+        } else {
+            puts -nonewline $out $prompt
+            flush $out
+            set len [gets $in line]
+        }
+
+        if { $len < 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline && $line ne "" } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in "stdin"]
+    set name "port"
+    set use_readline [expr {$isstdin && [readline init $name]}]
+    set history_file [file normalize "${macports::macports_user_dir}/history"]
+
+    # Read readline history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin && ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts "MacPorts [macports::version]"
+        puts "Entering interactive mode... (\"help\" for help, \"quit\" to quit)"
+    }
+
+    # Main command loop
+    set exit_status 0
+    while { $exit_status == 0 || $isstdin || [macports::ui_isset ports_processall] } {
+
+        # Calculate our prompt
+        if { $noisy } {
+            set shortdir [eval file join [lrange [file split $current_portdir] end-1 end]]
+            set prompt "\[$shortdir\] > "
+        } else {
+            set prompt ""
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] <= 0  } {
+            puts ""
+            break
+        }
+
+        # Process the command
+        set exit_status [process_cmd $line]
+        
+        # Check for semaphore to exit
+        if {$exit_status == -999} {
+            set exit_status 0
+            break
+        }
+    }
+
+    # Create macports user directory if it does not exist yet
+    if {$use_readline && ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline && [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts "Goodbye"
+    }
+
+    return $exit_status
+}
+
+
+proc process_command_files { filelist } {
+    set exit_status 0
+
+    # For each file in the command list, process commands
+    # in the file
+    foreach file $filelist {
+        if {$file eq "-"} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal "Failed to open command file; $result"
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne "stdin"} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 && ![macports::ui_isset ports_processall]} {
+            return $exit_status
+        }
+    }
+
+    return $exit_status
+}
+
+namespace eval portclient::progress {
+    ##
+    # Maximum width of the progress bar or indicator when displaying it.
+    variable maxWidth 50
+
+    ##
+    # The start time of the last progress callback as returned by [clock time].
+    # Since only one progress indicator is active at a time, this variable is
+    # shared between the different variants of progress functions.
+    variable startTime
+
+    ##
+    # Delay in milliseconds after the start of the operation before deciding
+    # that showing a progress bar makes sense.
+    variable showTimeThreshold 500
+
+    ##
+    # Percentage value between 0 and 1 that must not have been reached yet when
+    # $showTimeThreshold has passed for a progress bar to be shown. If the
+    # operation has proceeded above e.g. 75% after 500ms we won't bother
+    # displaying a progress indicator anymore -- the operation will be finished
+    # in well below a second anyway.
+    variable showPercentageThreshold 0.75
+
+    ##
+    # Boolean indication whether the progress indicator should be shown or is
+    # still hidden because the current operation didn't need enough time for
+    # a progress indicator to make sense, yet.
+    variable show no
+
+    ##
+    # Initialize the progress bar display delay; call this from the start
+    # action of the progress functions.
+    proc initDelay {} {
+        variable show
+        variable startTime
+
+        set startTime [clock milliseconds]
+        set show no
+    }
+
+    ##
+    # Determine whether a progress bar should be shown for the current
+    # operation in its current state. You must have called initDelay for the
+    # current operation before calling this method.
+    #
+    # @param cur
+    #        Current progress in abstract units.
+    # @param total
+    #        Total number of abstract units to be processed, if known. Pass
+    #        0 if unknown.
+    # @return
+    #        "yes", if the progress indicator should be shown, "no" otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq "yes"} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] > $showTimeThreshold &&
+                ($total == 0 || [expr {double($cur) / double($total)}] < $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of "start", "update", "intermission" or "finish", where start
+    #        will be called before any number of update calls, interrupted by
+    #        any number of intermission calls (called because other output is
+    #        being produced), followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        "intermission" and "finish", the args are empty and unused. For
+    #        "update", args contains $cur and $total, where $cur is the current
+    #        number of units processed and $total is the total number of units
+    #        to be processed. If the total is not known, it is 0.
+    proc generic {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {now total} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            progressbar $now $total [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        } else {
+                            unprogressbar [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen)}] $barPrefix
+                        }
+                    }
+                }
+            }
+            intermission -
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of "start", "update" or "finish", where start will be called
+    #        before any number of update calls, followed by one call to finish.
+    # @param args
+    #        A list of variadic args that differ for each action. For "start",
+    #        contains a single argument "ul" or "dl" indicating whether this is
+    #        an up- or download. For "update", contains the arguments
+    #        ("ul"|"dl") $total $now $speed where ul/dl are as for start, and
+    #        total, now and speed are doubles indicating the total transfer
+    #        size, currently transferred amount and average speed per second in
+    #        bytes. Unused for "finish".
+    proc download {action args} {
+        global env
+        variable maxWidth
+
+        switch -nocase -- $action {
+            start {
+                initDelay
+            }
+            update {
+                # the for loop is a simple hack because Tcl 8.4 doesn't have
+                # lassign
+                foreach {type total now speed} $args {
+                    if {[showProgress $now $total] eq "yes"} {
+                        set barPrefix "      "
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format "        speed: %-13s" "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format " %-10s     speed: %-13s" [bytesize $now {} "%6.1f"] "[bytesize $speed {} "%.1f"]/s"]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            unprogressbar $barLen $barPrefix $barSuffix
+                        }
+                    }
+                }
+            }
+            finish {
+                # erase to start of line
+                ::term::ansi::send::esol
+                # return cursor to start of line
+                puts -nonewline "\r"
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Draw a progress bar using unicode block drawing characters
+    #
+    # @param current
+    #        The current progress value.
+    # @param total
+    #        The progress value representing 100%.
+    # @param width
+    #        The width in characters of the progress bar. This includes percentage
+    #        output, which takes up 8 characters.
+    # @param prefix
+    #        Prefix to be printed in front of the progress bar.
+    # @param suffix
+    #        Suffix to be printed after the progress bar.
+    proc progressbar {current total width {prefix ""} {suffix ""}} {
+        # Subtract the width of the percentage output, also subtract the two
+        # characters [ and ] bounding the progress bar.
+        set percentageWidth 8
+        set barWidth      [expr {entier($width) - $percentageWidth - 2}]
+
+        # Map the range (0, $total) to (0, 4 * $width) where $width is the maximum
+        # numebr of characters to be printed for the progress bar. Multiply the
+        # upper bound with 8 because we have 8 sub-states per character.
+        set barProgress   [expr {entier(round(($current * $barWidth * 8) / $total))}]
+
+        set barInteger    [expr {$barProgress / 8}]
+        #set barRemainder  [expr {$barProgress % 8}]
+
+        # Finally, also provide a percentage value to print behind the progress bar
+        set percentage [expr {double($current) * 100 / double($total)}]
+
+        # clear the current line, enable reverse video
+        set progressbar "\033\[7m"
+        for {set i 0} {$i < $barInteger} {incr i} {
+            # U+2588 FULL BLOCK doesn't match the other blocks in some fonts :/
+            # Two half blocks work better in some fonts, but not in others (because
+            # they leave ugly spaces). So, one or the other choice isn't better or
+            # worse and even just using full blocks looks ugly in a few fonts.
+
+            # Use pure ASCII until somebody fixes most of the default terminal fonts :/
+            append progressbar " "
+        }
+        # back to normal output
+        append progressbar "\033\[0m"
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger < $barWidth} {
+        #            append progressbar " "
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar "\u258f"
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar "\u258e"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar "\u258d"
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar "\u258c"
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar "\u258b"
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar "\u258a"
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar "\u2589"
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i < $barWidth} {incr i} {
+            append progressbar " "
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format " %[expr {$percentageWidth - 3}].1f %%" $percentage]
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}"
+        flush stdout
+    }
+
+
+    ##
+    # Internal state of the progress indicator; unless you're hacking the
+    # unprogressbar code you should never touch this.
+    variable unprogressState 0
+
+    ##
+    # Draw a progress indicator
+    #
+    # @param width
+    #        The width in characters of the progress indicator.
+    # @param prefix
+    #        Prefix to be printed in front of the progress indicator.
+    # @param suffix
+    #        Suffix to be printed after the progress indicator.
+    proc unprogressbar {width {prefix ""} {suffix ""}} {
+        variable unprogressState
+
+        # Subtract the two characters [ and ] bounding the progress indicator
+        # from the width.
+        set barWidth [expr {int($width) - 2}]
+
+        # Number of states of the progress bar, or rather: the number of
+        # characters before the sequence repeats.
+        set numStates 4
+
+        set unprogressState [expr {($unprogressState + 1) % $numStates}]
+
+        set progressbar ""
+        for {set i 0} {$i < $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar "\u2022"
+            } else {
+                append progressbar " "
+            }
+        }
+
+        puts -nonewline "\r${prefix}\[${progressbar}\]${suffix}"
+        flush stdout
+    }
+}
+
+namespace eval portclient::notifications {
+    ##
+    # Ports whose notifications to display; these were either installed
+    # or requested to be installed.
+    variable notificationsToPrint
+    array set notificationsToPrint {}
+
+    ##
+    # Add a port to the list for printing notifications.
+    #
+    # @param name
+    #        The name of the port.
+    # @param note
+    #        A list of notes to be stored for the given port.
+    proc append {name notes} {
+        variable notificationsToPrint
+
+        set notificationsToPrint($name) $notes
+    }
+
+    ##
+    # Print port notifications.
+    #
+    proc display {} {
+        global env
+        variable notificationsToPrint
+
+        # Display notes at the end of the activation phase.
+        if {[array size notificationsToPrint] > 0} {
+            ui_notice "--->  Some of the ports you installed have notes:"
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice "  $name has the following notes:"
+
+                # If env(COLUMNS) exists, limit each line's width to this width.
+                if {[info exists env(COLUMNS)]} {
+                    set maxlen $env(COLUMNS)
+
+                    foreach note $notes {
+                        foreach line [split $note "\n"] {
+                            set joiner ""
+                            set lines ""
+                            set newline "    "
+
+                            foreach word [split $line " "] {
+                                if {[string length $newline] + [string length $word] >= $maxlen} {
+                                    lappend lines $newline
+                                    set newline "    "
+                                    set joiner ""
+                                }
+                                ::append newline $joiner $word
+                                set joiner " "
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines "\n"]
+                        }
+                    }
+                } else {
+                    foreach note $notes {
+                        ui_notice $note
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+##########################################
+# Main
+##########################################
+
+# Global arrays passed to the macports1.0 layer
+array set ui_options        {}
+array set global_options    {}
+array set global_variations {}
+
+# Global options private to this script
+array set private_options {}
+
+# Make sure we get the size of the terminal
+# We do this here to save it in the boot_env, in case we determined it manually
+term_init_size
+
+global env boot_env argv0 cmdname argc argv cmd_argc cmd_argv cmd_argn \
+       current_portdir global_options_base exit_status
+
+# Save off a copy of the environment before mportinit monkeys with it
+array set boot_env [array get env]
+
+set cmdname [file tail $argv0]
+
+# Setp cmd_argv to match argv
+set cmd_argv $argv
+set cmd_argc $argc
+set cmd_argn 0
+
+# make sure we're using a sane umask
+umask 022
+
+# If we've been invoked as portf, then the first argument is assumed
+# to be the name of a command file (i.e., there is an implicit -F
+# before any arguments).
+if {[moreargs] && $cmdname eq "portf"} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options "global" ui_options global_options} result]} {
+    puts "Error: $result"
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    && $portclient::progress::hasTermAnsiSend eq "yes"
+    && (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne "yes")} {
+    set ui_options(progress_download) portclient::progress::download
+    set ui_options(progress_generic)  portclient::progress::generic
+}
+
+set ui_options(notifications_append) portclient::notifications::append
+
+# Get arguments remaining after option processing
+set remaining_args [lrange $cmd_argv $cmd_argn end]
+
+# If we have no arguments remaining after option processing then force
+# interactive mode
+if { [llength $remaining_args] == 0 && ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq "selfupdate" || [lookahead] eq "sync"} {
+    # tell mportinit not to tell the user they should selfupdate
+    set ui_options(ports_no_old_index_warning) 1
+}
+
+# Initialize mport
+# This must be done following parse of global options, as some options are
+# evaluated by mportinit.
+if {[catch {mportinit ui_options global_options global_variations} result]} {
+    global errorInfo
+    puts "$errorInfo"
+    fatal "Failed to initialize MacPorts, $result"
+}
+
+# Set up some global state for our code
+set current_portdir [pwd]
+
+# Freeze global_options into global_options_base; global_options
+# will be reset to global_options_base prior to processing each command.
+set global_options_base [array get global_options]
+
+# First process any remaining args as action(s)
+set exit_status 0
+if { [llength $remaining_args] > 0 } {
+
+    # If there are remaining arguments, process those as a command
+    set exit_status [process_cmd $remaining_args]
+}
+
+# Process any prescribed command files, including standard input
+if { ($exit_status == 0 || [macports::ui_isset ports_processall]) && [info exists ui_options(ports_commandfiles)] } {
+    set exit_status [process_command_files $ui_options(ports_commandfiles)]
+}
+if {$exit_status == -999} {
+    set exit_status 0
+}
+
+# shut down macports1.0
+mportshutdown
+
+# Return with exit_status
+exit $exit_status
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20140813/4691a054/attachment-0001.html>


More information about the macports-changes mailing list