<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[123747] branches/gsoc14-cleanup</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="https://trac.macports.org/changeset/123747">123747</a></dd>
<dt>Author</dt> <dd>ksammons@macports.org</dd>
<dt>Date</dt> <dd>2014-08-13 15:14:51 -0700 (Wed, 13 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Final (hopefully) changes</pre>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesgsoc14cleanupDS_Store">branches/gsoc14-cleanup/.DS_Store</a></li>
<li>branches/gsoc14-cleanup/base/</li>
<li><a href="#branchesgsoc14cleanupbaseDS_Store">branches/gsoc14-cleanup/base/.DS_Store</a></li>
<li>branches/gsoc14-cleanup/base/doc/</li>
<li><a href="#branchesgsoc14cleanupbasedocDS_Store">branches/gsoc14-cleanup/base/doc/.DS_Store</a></li>
<li>branches/gsoc14-cleanup/base/doc/exampleport/</li>
<li><a href="#branchesgsoc14cleanupbasedocexampleportDS_Store">branches/gsoc14-cleanup/base/doc/exampleport/.DS_Store</a></li>
<li><a href="#branchesgsoc14cleanupsrcDS_Store">branches/gsoc14-cleanup/src/.DS_Store</a></li>
<li><a href="#branchesgsoc14cleanupsrcmacports10DS_Store">branches/gsoc14-cleanup/src/macports1.0/.DS_Store</a></li>
<li><a href="#branchesgsoc14cleanupsrcmacports10testsDS_Store">branches/gsoc14-cleanup/src/macports1.0/tests/.DS_Store</a></li>
<li><a href="#branchesgsoc14cleanupsrcportportBACKUP23878">branches/gsoc14-cleanup/src/port/port.BACKUP.23878</a></li>
<li><a href="#branchesgsoc14cleanupsrcportportBASE23878">branches/gsoc14-cleanup/src/port/port.BASE.23878</a></li>
<li><a href="#branchesgsoc14cleanupsrcportportLOCAL23878">branches/gsoc14-cleanup/src/port/port.LOCAL.23878</a></li>
<li><a href="#branchesgsoc14cleanupsrcportportREMOTE23878">branches/gsoc14-cleanup/src/port/port.REMOTE.23878</a></li>
<li><a href="#branchesgsoc14cleanupsrcportportorig">branches/gsoc14-cleanup/src/port/port.orig</a></li>
<li><a href="#branchesgsoc14cleanupsrcportporttclorig">branches/gsoc14-cleanup/src/port/port.tcl.orig</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesgsoc14cleanupDS_Store"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/.DS_Store (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- branches/gsoc14-cleanup/.DS_Store                                (rev 0)
+++ branches/gsoc14-cleanup/.DS_Store        2014-08-13 22:14:51 UTC (rev 123747)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+Bud1   #cal.m4  @\x80 @\x80 @\x80 @#
+aclocal.m4IlocblobF(\xFF\xFF\xFF\xFF\xFF\xFFbaseIlocblob\xCC(\xFF\xFFbasebwspblob\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\xACbasevSrnlong        ChangeLogIlocblobR(\xFF\xFF\xFF\xFF\xFF\xFFconfigIlocblob\xD8(\xFF\xFF\xFF\xFF\xFF\xFF config.guessIlocblob^(\xFF\xFF\xFF\xFF\xFF\xFF
+config.logIlocblob\xE4(\xFF\xFF\xFF\xFF\xFF\xFF +config.statusIlocblobF\x98\xFF\xFF\xFF\xFF\xFF\xFF
+config.subIlocblob\xCC\x98\xFF\xFF\xFF\xFF\xFF\xFF        configureIlocblobR\x98\xFF\xFF\xFF\xFF\xFF\xFF configure.acIlocblob\xD8\x98\xFF\xFF\xFF\xFF\xFF\xFFdocIlocblob^\x98\xFF\xFF\xFF\xFF\xFF\xFFDoxyfileIlocblob\xE4\x98\xFF\xFF\xFF\xFF\xFF\xFF Doxyfile.inIlocblobF\xFF\xFF\xFF\xFF\xFF\xFFHACKINGIlocblob\xCC\xFF\xFF\xFF\xFF\xFF\xFF
+install.shIlocblobR\xFF\xFF\xFF\xFF\xFF\xFFLICENSEIlocblob\xD8\xFF\xFF\xFF\xFF\xFF\xFFm4Ilocblob^\xFF\xFF\xFF\xFF\xFF\xFFmacports-pubkey.pemIlocblob\xE4\xFF\xFF\xFF\xFF\xFF\xFFMakefileIlocblobFx\xFF\xFF\xFF\xFF\xFF\xFF Makefile.inIlocblob\xCCx\xFF\xFF\xFF\xFF\xFF\xFFMkIlocblobRx\xFF\xFF\xFF\xFF\xFF\xFFNEWSIlocblob\xD8x\xFF\xFF\xFF\xFF\xFF\xFFportmgrIlocblob^x\xFF\xFF\xFF\xFF\xFF\xFF        README.mdIlocblob\xE4x\xFF\xFF\xFF\xFF\xFF\xFFregen.shIlocblobF\xE8\xFF\xFF\xFF\xFF\xFF\xFF +setupenv.bashIlocblob\xCC\xE8\xFF\xFF\xFF\xFF\xFF\xFFsetupenv.bash.inIlocblobR\xE8\xFF\xFF\xFF\xFF\xFF\xFFsrcIlocblob\xD8\xE8\xFF\xFFsrcbwspblob\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\xACsrcvSrnlongstandard_configure.shIlocblob^\xE8\xFF\xFF\xFF\xFF\xFF\xFFtestsIlocblob\xE4\xE8\xFF\xFF\xFF\xFF\xFF\xFFvendorIlocblobFX\xFF\xFF\xFF\xFF\xFF\xFF  E DSDB `\x80(0@\x80 @\x80 @MkIlocblobRx\xFF\xFF\xFF\xFF\xFF\xFFNEWSIlocblob\xD8x\xFF\xFF\xFF\xFF\xFF\xFFportmgrIlocblob^x\xFF\xFF\xFF\xFF\xFF\xFF        README.mdIlocblob\xE4x\xFF\xFF\xFF\xFF\xFF\xFFregen.shIlocblobF\xE8\xFF\xFF\xFF\xFF\xFF\xFF +setupenv.bashIlocblob\xCC\xE8\xFF\xFF\xFF\xFF\xFF\xFFsetupenv.bash.inIlocblobR\xE8\xFF\xFF\xFF\xFF\xFF\xFFsrcIlocblob\xD8\xE8\xFF\xFFsrcbwspblob\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\xACsrcvSrnlongstandard_configure.shIlocblob^\xE8\xFF\xFF\xFF\xFF\xFF\xFFtestsIlocblob\xE4\xE8\xFF\xFF\xFF\xFF\xFF\xFFve
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchesgsoc14cleanupbaseDS_Store"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/base/.DS_Store (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- branches/gsoc14-cleanup/base/.DS_Store                                (rev 0)
+++ branches/gsoc14-cleanup/base/.DS_Store        2014-08-13 22:14:51 UTC (rev 123747)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+Bud1 cal.m4  @\x80 @\x80 @\x80 @
+aclocal.m4IlocblobF(\xFF\xFF\xFF\xFF\xFF\xFF        ChangeLogIlocblob\xCC(\xFF\xFF\xFF\xFF\xFF\xFFconfigIlocblobR(\xFF\xFF\xFF\xFF\xFF\xFF config.guessIlocblob\xD8(\xFF\xFF\xFF\xFF\xFF\xFF
+config.subIlocblob^(\xFF\xFF\xFF\xFF\xFF\xFF        configureIlocblob\xE4(\xFF\xFF\xFF\xFF\xFF\xFF configure.acIlocblobF\x98\xFF\xFF\xFF\xFF\xFF\xFFdocIlocblob\xCC\x98\xFF\xFFdocbwspblob\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\xACdocvSrnlong Doxyfile.inIlocblobR\x98\xFF\xFF\xFF\xFF\xFF\xFFHACKINGIlocblob\xD8\x98\xFF\xFF\xFF\xFF\xFF\xFF
+install.shIlocblob^\x98\xFF\xFF\xFF\xFF\xFF\xFFLICENSEIlocblob\xE4\x98\xFF\xFF\xFF\xFF\xFF\xFFm4IlocblobF\xFF\xFF\xFF\xFF\xFF\xFFmacports-pubkey.pemIlocblob\xCC\xFF\xFF\xFF\xFF\xFF\xFF Makefile.inIlocblobR\xFF\xFF\xFF\xFF\xFF\xFFMkIlocblob\xD8\xFF\xFF\xFF\xFF\xFF\xFFNEWSIlocblob^\xFF\xFF\xFF\xFF\xFF\xFFportmgrIlocblob\xE4\xFF\xFF\xFF\xFF\xFF\xFFregen.shIlocblobFx\xFF\xFF\xFF\xFF\xFF\xFFsetupenv.bash.inIlocblob\xCCx\xFF\xFF\xFF\xFF\xFF\xFFsrcIlocblobRx\xFF\xFF\xFF\xFF\xFF\xFFstandard_configure.shIlocblob\xD8x\xFF\xFF\xFF\xFF\xFF\xFFtestsIlocblob^x\xFF\xFF\xFF\xFF\xFF\xFFvendorIlocblob\xE4x\xFF\xFF\xFF\xFF\xFF\xFF E DSDB `\x80 @\x80 @\x80 @IlocblobRx\xFF\xFF\xFF\xFF\xFF\xFFstandard_configure.shIlocblob\xD8x\xFF\xFF\xFF\xFF\xFF\xFFtestsIlocblob^x\xFF\xFF\xFF\xFF\xFF\xFFvendorIlocblob\xE4x\xFF\xFF\xFF\xFF\xFF\xFF
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchesgsoc14cleanupbasedocDS_Store"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/base/doc/.DS_Store (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+Bud1 ive_si  @\x80 @\x80 @\x80 @archive_sites.confIlocblobF(\xFF\xFF\xFF\xFF\xFF\xFF +base.mtree.inIlocblob\xCC(\xFF\xFF\xFF\xFF\xFF\xFF exampleportIlocblobR(\xFF\xFF exampleportbwspblob\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 exampleportvSrnlong        INTERNALSIlocblob\xD8(\xFF\xFF\xFF\xFF\xFF\xFFmacosx.mtree.inIlocblob^(\xFF\xFF\xFF\xFF\xFF\xFFmacports.conf.5Ilocblob\xE4(\xFF\xFF\xFF\xFF\xFF\xFFmacports.conf.inIlocblobF\x98\xFF\xFF\xFF\xFF\xFF\xFF Makefile.inIlocblob\xCC\x98\xFF\xFF\xFF\xFF\xFF\xFFport.1IlocblobR\x98\xFF\xFF\xFF\xFF\xFF\xFF
+portfile.7Ilocblob\xD8\x98\xFF\xFF\xFF\xFF\xFF\xFF portgroup.7Ilocblob^\x98\xFF\xFF\xFF\xFF\xFF\xFF
+porthier.7Ilocblob\xE4\x98\xFF\xFF\xFF\xFF\xFF\xFF portstyle.7IlocblobF\xFF\xFF\xFF\xFF\xFF\xFFprefix.mtree.inIlocblob\xCC\xFF\xFF\xFF\xFF\xFF\xFFpubkeys.conf.inIlocblobR\xFF\xFF\xFF\xFF\xFF\xFF sources.confIlocblob\xD8\xFF\xFF\xFF\xFF\xFF\xFF +variants.confIlocblob^\xFF\xFF\xFF\xFF\xFF\xFF E DSDB `\x80 @\x80 @\x80 @
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchesgsoc14cleanupbasedocexampleportDS_Store"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/base/doc/exampleport/.DS_Store (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+Bud1\x86fileIlocPortfileIlocblobF(\xFF\xFF\xFF\xFF\xFF\xFF  @\x80 @\x80 @\x80 @ E\x86DSDB `\xC0 @\x80 @\x80 @
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchesgsoc14cleanupsrcDS_Store"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/.DS_Store (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- branches/gsoc14-cleanup/src/.DS_Store                                (rev 0)
+++ branches/gsoc14-cleanup/src/.DS_Store        2014-08-13 22:14:51 UTC (rev 123747)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+Bud1 b1.0Iloc  @\x80 @\x80 @\x80 @cflib1.0IlocblobF(\xFF\xFF\xFF\xFF\xFF\xFF config.h.inIlocblob\xCC(\xFF\xFF\xFF\xFF\xFF\xFF        cregistryIlocblobR(\xFF\xFF\xFF\xFF\xFF\xFFdarwintracelib1.0Ilocblob\xD8(\xFF\xFF\xFF\xFF\xFF\xFFdedup_portfiles.tcl.inIlocblob^(\xFF\xFF\xFF\xFF\xFF\xFFimages_to_archives.tcl.inIlocblob\xE4(\xFF\xFF\xFF\xFF\xFF\xFF machista1.0IlocblobF\x98\xFF\xFF\xFF\xFF\xFF\xFF macports1.0Ilocblob\xCC\x98\xFF\xFF macports1.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 macports1.0vSrnlong Makefile.inIlocblobR\x98\xFF\xFF\xFF\xFF\xFF\xFF
+package1.0Ilocblob\xD8\x98\xFF\xFF\xFF\xFF\xFF\xFF
+pextlib1.0Ilocblob^\x98\xFF\xFF\xFF\xFF\xFF\xFFpkg_mkindex.sh.inIlocblob\xE4\x98\xFF\xFF\xFF\xFF\xFF\xFFportIlocblobF\xFF\xFF\xFF\xFF\xFF\xFFport1.0Ilocblob\xCC\xFF\xFF\xFF\xFF\xFF\xFFprogramsIlocblobR\xFF\xFF\xFF\xFF\xFF\xFF registry2.0Ilocblob\xD8\xFF\xFF\xFF\xFF\xFF\xFF
+tclobjc1.0Ilocblob^\xFF\xFF\xFF\xFF\xFF\xFF#upgrade_sources_conf_default.tcl.inIlocblob\xE4\xFF\xFF\xFF\xFF\xFF\xFF E DSDB `\x80 @\x80 @\x80 @sources_conf_default.tcl.inIlocblob\xE4\xFF\xFF\xFF\xFF\xFF\xFF
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchesgsoc14cleanupsrcmacports10DS_Store"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/macports1.0/.DS_Store (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+Bud1 or.tcl  @\x80 @\x80 @\x80 @
+doctor.tclIlocblobFx\xFF\xFF\xFF\xFF\xFF\xFFdoctor.tcl.origIlocblobF(\xFF\xFF\xFF\xFF\xFF\xFF!get_systemconfiguration_proxies.cIlocblob\xCC(\xFF\xFF\xFF\xFF\xFF\xFF!get_systemconfiguration_proxies.hIlocblobR(\xFF\xFF\xFF\xFF\xFF\xFF
+macports.cIlocblob\xCC\x98\xFF\xFF\xFF\xFF\xFF\xFF macports.tclIlocblobR\x98\xFF\xFF\xFF\xFF\xFF\xFFmacports.tcl.BACKUP.21722.tclIlocblob\xD8\x98\xFF\xFF\xFF\xFF\xFF\xFFmacports.tcl.BASE.21722.tclIlocblob^\x98\xFF\xFF\xFF\xFF\xFF\xFFmacports.tcl.LOCAL.21722.tclIlocblob\xE4\x98\xFF\xFF\xFF\xFF\xFF\xFFmacports.tcl.origIlocblobF\xFF\xFF\xFF\xFF\xFF\xFFmacports.tcl.REMOTE.21722.tclIlocblob\xCC\xFF\xFF\xFF\xFF\xFF\xFFmacports_autoconf.tcl.inIlocblob\xD8(\xFF\xFF\xFF\xFF\xFF\xFFmacports_dlist.tclIlocblob^(\xFF\xFF\xFF\xFF\xFF\xFFmacports_test_autoconf.tcl.inIlocblob\xE4(\xFF\xFF\xFF\xFF\xFF\xFFmacports_util.tclIlocblobF\x98\xFF\xFF\xFF\xFF\xFF\xFF Makefile.inIlocblobR\xFF\xFF\xFF\xFF\xFF\xFF reclaim.tclIlocblob\xCCx\xFF\xFF\xFF\xFF\xFF\xFFsysctl.cIlocblob\xD8\xFF\xFF\xFF\xFF\xFF\xFFsysctl.hIlocblob^\xFF\xFF\xFF\xFF\xFF\xFFtestsIlocblob\xE4\xFF\xFFtestsbwspblob\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\xACtestsvSrnlong E DSDB `\x80 @\x80 @\x80 @l.cIlocblob\xD8\xFF\xFF\xFF\xFF\xFF\xFFsysctl.hIlocblob^\xFF\xFF\xFF\xFF\xFF\xFFtestsIlocblob\xE4\xFF\xFFtestsbwspblob\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\xACtestsvSrnlong
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchesgsoc14cleanupsrcmacports10testsDS_Store"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/macports1.0/tests/.DS_Store (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+Bud1        ary.tc library.tclIlocblobF(\xFF\xFF\xFF\xFF\xFF\xFF +macports.testIlocblob\xD8(\xFF\xFF\xFF\xFF\xFF\xFFmacports_dlist.testIlocblob\xCC(\xFF\xFF\xFF\xFF\xFF\xFFmacports_util.testIlocblobR(\xFF\xFF\xFF\xFF\xFF\xFFPortfileIlocblob^(\xFF\xFF\xFF\xFF\xFF\xFF sources.confIlocblob\xE4(\xFF\xFF\xFF\xFF\xFF\xFFtest.tclIlocblobF\x98\xFF\xFF\xFF\xFF\xFF\xFF  @\x80 @\x80 @\x80 @ E        DSDB `\x80 @\x80 @\x80 @
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchesgsoc14cleanupsrcportportBACKUP23878"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/port/port.BACKUP.23878 (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,5362 @@
</span><ins>+#!/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@macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw &lt;rshaw@opendarwin.org&gt;
+# 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 &quot;AS IS&quot;
+# 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. &quot;yes&quot;, if the package is available, &quot;no&quot; 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 &quot;Usage: $cmdname$syntax&quot;
+        puts stderr &quot;\&quot;$cmdname help\&quot; or \&quot;man 1 port\&quot; for more information.&quot;
+    } else {
+        puts stderr &quot;$cmdname$syntax&quot;
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds &quot;&quot;
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen &gt; 65} {
+            set cmds &quot;$cmds,\n&quot;
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new &quot;$cmd&quot;
+        } else {
+            set new &quot;, $cmd&quot;
+        }
+        incr lineLen [string length $new]
+        set cmds &quot;$cmds$new&quot;
+    }
+
+    set cmdText &quot;Supported actions
+------------------
+$cmds
+&quot;
+
+    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 &quot;$cmdText$text&quot;
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error &quot;$argv0: $s&quot;
+    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 &gt; 0x40000000} {
+            set unit &quot;GiB&quot;
+        } elseif {$siz &gt; 0x100000} {
+            set unit &quot;MiB&quot;
+        } elseif {$siz &gt; 0x400} {
+            set unit &quot;KiB&quot;
+        } else {
+            set unit &quot;B&quot;
+        }
+    }
+    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 &quot;Unknown file size unit '$unit' specified&quot;
+            set unit &quot;B&quot;
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return &quot;$siz $unit&quot;
+}
+
+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 &quot;/usr/local&quot; &amp;&amp; ${macports::prefix} ne &quot;/usr&quot;} {
+        ui_error &quot;Follow http://guide.macports.org/#project.tickets to report a bug.&quot;
+    }
+}
+
+# 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 &quot;+&quot;} {
+            lappend pos $key
+        } elseif {$val eq &quot;-&quot;} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version &quot;&quot;
+    if {$version ne &quot;&quot; || $emptyVersionOkay} {
+        set pos_str &quot;&quot;
+        set neg_str &quot;&quot;
+
+        if {[llength $pos]} {
+            set pos_str &quot;+[join [lsort -ascii $pos] &quot;+&quot;]&quot;
+        }
+        if {[llength $neg]} {
+            set neg_str &quot;-[join [lsort -ascii $neg] &quot;-&quot;]&quot;
+        }
+
+        set composite_version &quot;$version$pos_str$neg_str&quot;
+    }
+
+    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 &quot;${field}s&quot;
+        }
+        category {
+            set field &quot;categories&quot;
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion &quot;&quot;}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] &gt; 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 &quot;The following versions of $portname are currently installed:&quot;
+        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 &quot;  $iname @${iversion}_${irevision}${ivariants}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants} (active)&quot;
+            }
+        }
+        return -code error &quot;Registry error: Please specify the full version as recorded in the port registry.&quot;
+    } 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=&gt;+-)
+    #   requested_variants array  (variant=&gt;+-)
+    #   options array   (key=&gt;value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) &quot;&quot; }
+    if {![info exists port(name)]}      { set port(name) &quot;&quot; }
+    if {![info exists port(version)]}   { set port(version) &quot;&quot; }
+    if {![info exists port(variants)]}  { set port(variants) &quot;&quot; }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) &quot;&quot; }
+    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 &quot;&quot; &amp;&amp; $port(name) eq &quot;&quot; } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq &quot;&quot;} {
+            ui_error &quot;A default port name could not be supplied.&quot;
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) &quot;$port(name)/[composite_version $port(version) $port(variants)]&quot;
+    
+    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 &quot;&quot;}} {
+    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 &quot;&quot;
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg &quot;Can't map the URL '$url' to a port description file (\&quot;${result}\&quot;).&quot;
+            ui_msg &quot;Please verify that the directory and portfile syntax are correct.&quot;
+        }
+    } 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 &quot;no&quot;} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 &amp;&amp; (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq &quot;no&quot;)} {
+        if {${is_upgrade} == &quot;yes&quot;} {
+            # $&gt; port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # &quot;upgrade&quot;, let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg &quot;Nothing to upgrade.&quot;
+            return 1
+        }
+        ui_error &quot;No ports matched the given expression&quot;
+        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 &quot;array unset portspec; array set portspec { $portspec }&quot;
+        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) &quot;_&quot;]
+    set bvr_ [split $b_(version) &quot;_&quot;]
+    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_ &lt; $br_} {
+        return -1
+    } elseif {$ar_ &gt; $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name@version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list &quot;name&quot; [lindex $a 0] &quot;version&quot; &quot;[lindex $a 1]_[lindex $a 2]&quot;]
+    array set b_ [list &quot;name&quot; [lindex $b 0] &quot;version&quot; &quot;[lindex $b 1]_[lindex $b 2]&quot;]
+    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 {\\&amp;}]
+    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)] &amp;&amp; [lindex $size 0] &gt; 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] &amp;&amp; [lindex $size 1] &gt; 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 &quot;&quot;} {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 &quot;\n&quot;] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;} {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 &quot; &quot;]
+    if {$indentfirstline == 0} {
+        set newline &quot;&quot;
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner &quot; &quot;
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] &gt;= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner &quot;&quot;
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 &amp;&amp; $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner &quot; &quot;
+    }
+    lappend lines $newline
+    return [join $lines &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;}} {
+    append label &quot;: [string repeat &quot; &quot; [expr {[string length $indent] - [string length &quot;$label: &quot;]}]]&quot;
+    return &quot;$label[wrap $string $maxlen $indent 0]&quot;
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first &quot;@&quot; $m] &lt; 0} {
+            if {[string first &quot;:&quot; $m] &gt;= 0} {
+                set m [regsub -- &quot;(.*):(.*)&quot; $m &quot;\\2@\\1&quot;] 
+            } else {
+                set m &quot;$m@macports.org&quot;
+            }
+        }
+        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 &quot;$errorInfo&quot;
+        fatal &quot;search for portname $pattern failed: $result&quot;
+    }
+    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 &quot;$errorInfo&quot;
+            fatal &quot;listing all ports failed: $result&quot;
+        }
+        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 &quot;&quot;} {
+        ui_msg &quot;To use the current port, you must be in a port's directory.&quot;
+        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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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} == &quot;yes&quot; || (${active} == &quot;yes&quot;) == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] &gt; 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  &quot;${installed_version}_${installed_revision}&quot;
+            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 &quot;$errorInfo&quot;
+                fatal &quot;lookup of portname $portname failed: $result&quot;
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &lt; 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 &quot;$::errorInfo&quot;
+            break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+        }
+
+        if {[llength $result] &lt; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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 &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq &quot;&quot;} {
+            add_to_portlist results [list name $iname version &quot;[lindex $i 1]_[lindex $i 2]&quot; 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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+                        return -code error &quot;lookup of portname $depname failed: $result&quot;
+                    }
+                    if {[llength $result] &lt; 2} {
+                        ui_error &quot;Port $depname not found&quot;
+                        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 &quot;$::errorInfo&quot;
+                        ui_error &quot;Unable to open port: $result&quot;
+                        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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;&quot;
+    set name &quot;&quot;
+    set version &quot;&quot;
+    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 &quot;)&quot;]} {
+                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 &quot;depends_lib&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_build&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_run&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_extract&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_fetch&quot;]
+
+            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 &quot;rdependentof&quot;]
+            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 &quot;rdepof&quot;]
+            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 &quot;&quot;} {
+                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 &quot;Can't open URL '$token' as a port&quot;
+                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 &quot;&quot;} } {
+    upvar $resname reslist
+    
+    set version &quot;&quot;
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne &quot;&quot;} { 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/          ==&gt; a/
+    #   a/, b/          ==&gt;
+    #   a/, a/1.0       ==&gt; a/1.0
+    #   a/1.0, a/       ==&gt; a/1.0
+    #   a/1.0, a/2.0    ==&gt;
+    #
+    #   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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 &quot;&quot;
+    set portversion &quot;&quot;
+    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 &quot;provides&quot;
+        # so we take a rather lenient view of what a &quot;portname&quot; is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder &quot;&quot;
+        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 &quot;*/*&quot; $portname]} {
+                set url &quot;file://$portname&quot;
+                set name [url_to_portname $url 1]
+                if { $name ne &quot;&quot; } {
+                    # 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 &quot;&quot;
+                    # 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 &quot;Insufficient privileges to write to MacPorts install prefix.&quot;
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder &quot;&quot;} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion &quot;&quot;
+    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 &quot;&quot; || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq &quot;&quot;} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime &amp;&amp; [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first &quot;/&quot; $opt]
+            if {$sepPos &gt;= 0} {
+                # Version terminated by &quot;/&quot; 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 &quot;+&quot;, or else is complete
+                set sepPos [string first &quot;+&quot; $opt]
+                if {$sepPos &gt;= 0} {
+                    # Version terminated by &quot;+&quot;
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt &quot;&quot;
+                }
+            }
+            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) &quot;\&quot;$val\&quot;&quot;
+                set opt &quot;&quot;
+                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 &amp;&amp; $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds &quot;&quot;
+        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 &quot; --$name&quot;
+
+                for {set i 1} {$i &lt;= $optc} {incr i} {
+                    append cmds &quot; &lt;arg$i&gt;&quot;
+                }
+            }
+        }
+        set args &quot;&quot;
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;arguments&gt;&quot;
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;portlist&gt;&quot;
+        }
+
+        set ret &quot;Usage: &quot;
+        set len [string length $action]
+        append ret [wrap &quot;$action$cmds$args&quot; 0 [string repeat &quot; &quot; [expr {8 + $len}]] 0]
+        append ret &quot;\n&quot;
+
+        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 &quot;No usage for topic $topic&quot;
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile &quot;$macports::prefix/var/macports/port-help.tcl&quot;
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr &quot;Error reading helpfile $helpfile: $err&quot;
+            return 1
+        }
+    } else {
+        puts stderr &quot;Unable to open help file $helpfile&quot;
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr &quot;No help for topic $topic&quot;
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error &quot;No usage for topic $topic&quot;
+            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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 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 &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] &quot;main.log&quot;]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue &quot;Could not open file $logfile: $result&quot; 1 status
+            }
+            set data [read $fp]
+            set data [split $data &quot;\n&quot;]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase &quot;\[a-z\]*&quot;
+            }
+
+            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 &quot;&quot;
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] &quot;|&quot;]
+                }
+            } else {
+                set prefix &quot;\[a-z\]*&quot;
+            }
+            foreach line $data {
+                set exp &quot;^:($prefix|any):($phase|any) (.*)$&quot;
+                if {[regexp $exp $line -&gt; lpriority lphase lmsg] == 1} {
+                    puts &quot;[macports::ui_prefix_default $lpriority]$lmsg&quot;
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue &quot;Log file for port $portname not found&quot; 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator &quot;&quot;
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] &amp;&amp; $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 &quot;&quot; || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;no PortIndex entry found for $portname&quot;
+            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 &quot;
+            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
+        &quot;
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     &quot;&quot;
+            variants    Variants
+            depends_fetch &quot;Fetch Dependencies&quot;
+            depends_extract &quot;Extract Dependencies&quot;
+            depends_build &quot;Build Dependencies&quot;
+            depends_run &quot;Runtime Dependencies&quot;
+            depends_lib &quot;Library Dependencies&quot;
+            description &quot;Brief Description&quot;
+            long_description &quot;Description&quot;
+            fullname    &quot;Full Name: &quot;
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   &quot;Conflicts with&quot;
+            replaced_by &quot;Replaced by&quot;
+            subports    &quot;Sub-ports&quot;
+        }
+
+        # 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)] &amp;&amp; $options(ports_info_depends) eq &quot;yes&quot;} {
+            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 &quot;\n&quot;
+        set subfield_sep &quot;, &quot;
+        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 &quot;\t&quot;
+            set subfield_sep &quot;,&quot;
+        }
+        
+        # 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 &amp;&amp; $opt eq &quot;skip_line&quot;} {
+                lappend fields &quot;&quot;
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq &quot;heading&quot;} {
+                set inf &quot;$portinfo(name) @$portinfo(version)&quot;
+                set ropt &quot;heading&quot;
+                if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                    append inf &quot;_$portinfo(revision)&quot;
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                }
+            } elseif {$opt eq &quot;fullname&quot;} {
+                set inf &quot;$portinfo(name) @&quot;
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt &quot;fullname&quot;
+            } 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 &quot;&quot;
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label &quot;&quot;
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label &quot;$opt: &quot;
+            }
+            
+            # Format the data
+            if { $ropt eq &quot;maintainers&quot; } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq &quot;variants&quot;} {
+                    # 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 &quot;&quot;
+                        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 &quot;($global_variations($v))&quot;
+                            # 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 &quot;\[$variant(is_default)]&quot;
+                            }
+                        }
+                        lappend inf &quot;$varmodifier$v&quot;
+                    }
+                } elseif {[string match &quot;depend*&quot; $ropt] 
+                          &amp;&amp; ![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 &quot;heading&quot; || $ropt eq &quot;fullname&quot;} {
+                    puts &quot;$label$field&quot;
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq &quot;&quot;} {
+                    continue
+                }
+                if {$label eq &quot;&quot;} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat &quot; &quot; $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 &quot; &quot; $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields &quot;$label$field&quot;
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print &amp;&amp; [llength $fields_tried]} {
+                puts -nonewline &quot;$portinfo(name) has no &quot;
+                puts [join $fields_tried &quot;, &quot;]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator &quot;--\n&quot;
+        }
+    }
+    
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port location failed: $result&quot; 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 &quot;Port $portname ${version}_${revision}${variants} is installed as an image in:&quot;
+        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 &quot;&quot;} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue &quot;The lookup of '$portname' failed: $result&quot; \
+                                1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;The port '$portname' was not found&quot; 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 &quot;The URL '$porturl' could not be&quot; \
+                                       &quot;opened: $result&quot;] 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 &quot;$portname has the following notes:&quot;
+            foreach note $portnotes {
+                puts [wrap $note 0 &quot;  &quot; 1]
+            }
+        } else {
+            puts &quot;$portname has no notes.&quot;
+        }
+    }
+    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 &quot;Please specify a filename to check which port provides that file.&quot;
+        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 &quot;link&quot;} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts &quot;$file is provided by: $port&quot;
+                } else {
+                    puts &quot;$file is not provided by a MacPorts port.&quot;
+                }
+            } else {
+                puts &quot;$file is a directory.&quot;
+            }
+        } else {
+            puts &quot;$file does not exist.&quot;
+        }
+    }
+    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)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port activate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping activate $portname (dry run)&quot;
+        }
+    }
+    
+    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)]
+            &amp;&amp; ![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 &quot;&quot; || $composite_version == &quot;${iversion}_${irevision}${ivariants}&quot;} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port deactivate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping deactivate $portname (dry run)&quot;
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug &quot;action_select \[$portlist] \[$opts]...&quot;
+
+    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] &lt; 1 &amp;&amp; [string map {ports_select_ &quot;&quot;} [lindex $commands 0]] != &quot;summary&quot;} {
+        ui_error &quot;port select \[--list|--set|--show|--summary] \&lt;group&gt; \[&lt;version&gt;]&quot;
+        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] &lt; 1 &amp;&amp; [llength $portlist] &gt; 1} {
+        set command set
+        ui_debug [concat &quot;Although no command was specified, more than &quot; \
+                         &quot;one argument was specified.  Defaulting to the &quot; \
+                         &quot;'set' command...&quot;]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] &lt; 1} {
+        set command list
+        ui_debug [concat &quot;No command was specified. Defaulting to the &quot; \
+                         &quot;'list' command...&quot;]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] &gt; 1} {
+        ui_error [concat &quot;Multiple commands were specified. Only one &quot; \
+                         &quot;command may be specified at a time.&quot;]
+        return 1
+    } else {
+        set command [string map {ports_select_ &quot;&quot;} [lindex $commands 0]]
+        ui_debug &quot;The '$command' command was specified.&quot;
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'list' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn &quot;Unable to get active selected version: $selected_version&quot;
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error &quot;The 'list' command failed: $versions&quot;
+                return 1
+            }
+
+            ui_notice &quot;Available versions for $group:&quot;
+            foreach v $versions {
+                ui_notice -nonewline &quot;\t&quot;
+                if {$selected_version == $v} {
+                    ui_msg &quot;$v (active)&quot;
+                } else {
+                    ui_msg &quot;$v&quot;
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] &lt; 2} {
+                ui_error [concat &quot;The 'set' command expects two &quot; \
+                                 &quot;arguments: &lt;group&gt;, &lt;version&gt;&quot;]
+                return 1
+            } elseif {[llength $portlist] &gt; 2} {
+                ui_warn [concat &quot;The 'set' command only expects two &quot; \
+                                &quot;arguments. Extra arguments will be &quot; \
+                                &quot;ignored.&quot;]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline &quot;Selecting '$version' for '$group' &quot;
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg &quot;failed: $result&quot;
+                return 1
+            }
+            ui_msg &quot;succeeded. '$version' is now active.&quot;
+            return 0
+        }
+        show {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'show' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error &quot;The 'show' command failed: $selected_version&quot;
+                return 1
+            }
+            puts [concat &quot;The currently selected version for '$group' is &quot; \
+                         &quot;'$selected_version'.&quot;]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] &gt; 0} {
+                ui_warn [concat &quot;The 'summary' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error &quot;The 'summary' command failed: $portgroups&quot;
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr &quot;%-*s  %-*s  %s&quot;
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn &quot;The list of options for the select group $pg could not be obtained: $versions&quot;
+                    continue
+                }
+                # remove &quot;none&quot;, sort the list, append none at the end
+                set noneidx [lsearch -exact $versions &quot;none&quot;]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions &quot;none&quot;
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn &quot;The currently selected option for the select group $pg could not be obtained: $selected_version&quot;
+                    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 &quot;Name&quot; $w2 &quot;Selected&quot; &quot;Options&quot;]
+            puts [format $formatStr $w1 &quot;====&quot; $w2 &quot;========&quot; &quot;=======&quot;]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) &quot; &quot;]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error &quot;An unknown command '$command' was specified.&quot;
+            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 &quot;$errorInfo&quot;
+        ui_error &quot;$result&quot;
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg &quot;Please run `port -v selfupdate' for details.&quot;
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal &quot;port selfupdate failed: $result&quot;
+    }
+    
+    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 &quot;setrequested&quot;]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info &quot;Setting requested flag for $portname to $val&quot;
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist &quot;yes&quot;] || ([prefix_unwritable] &amp;&amp; ![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 &quot;port:$portname&quot; [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 &amp;&amp; $status != 2 &amp;&amp; $status != 3 &amp;&amp; ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 &amp;&amp; $status != 2 &amp;&amp; $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] &amp;&amp; ${macports::revupgrade_autorun} &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
+    macports::doctor_main
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::doctor_main $opts
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; svn
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; 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 &quot;Version: &quot;
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline &quot;Platform: &quot;
+    }
+    puts &quot;${macports::os_platform} ${macports::os_major} ${macports::os_arch}&quot;
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 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] &gt; 0 } {
+            if {$action eq &quot;rdependents&quot;} {
+                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] &gt; 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice &quot;The following ports are dependent on ${portname}:&quot;
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos &gt;= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] &lt;= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] &amp;&amp; [string is true -strict $options(ports_rdependents_full)])} {
+                        puts &quot;${spaces}${cur_portname}&quot;
+                        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 &quot;$depport&quot;
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg &quot;$depport depends on $portname&quot;
+                    } else {
+                        ui_msg &quot;$depport depends on $portname (by [lindex $dep 1]:)&quot;
+                    }
+                }
+            }
+        } else {
+            ui_notice &quot;$portname has no dependents.&quot;
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator &quot;&quot;
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] &amp;&amp; [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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn &quot;port ${action} --index does not work with the 'current' pseudo-port&quot;
+            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 &quot;rdeps&quot; || [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 &quot;deps&quot;} {
+                    set label &quot;$labeldict($type) Dependencies&quot;
+                    lappend deps_output [wraplabel $label [join $deplist &quot;, &quot;] 0 [string repeat &quot; &quot; 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 &quot;deps&quot;} {
+            if {$ndeps == 0} {
+                ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+            } else {
+                ui_notice &quot;Full Name: $portname @${version}_${revision}${variants}&quot;
+                puts [join $deps_output &quot;\n&quot;]
+            }
+            set separator &quot;--\n&quot;
+            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 &quot;$::errorInfo&quot;
+                        break_softcontinue &quot;lookup of portname $depname failed: $result&quot; 1 status
+                    }
+                    if {[llength $result] &lt; 2} {
+                        break_softcontinue &quot;Port $depname not found&quot; 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)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug &quot;$::errorInfo&quot;
+                            break_softcontinue &quot;Unable to open port: $result&quot; 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] &gt; 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] &gt; 0} {
+            ui_notice &quot;The following ports are dependencies of $portname @${version}_${revision}${variants}:&quot;
+        } else {
+            ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos &gt;= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] &lt;= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] &amp;&amp; [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts &quot;${spaces}${cur_port}&quot;
+                } else {
+                    puts &quot;${spaces}${cur_portname}&quot;
+                }
+                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 &quot;--\n&quot;
+    }
+    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 &quot;$portname is not installed&quot;
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn &quot;no such port: $portname, skipping uninstall&quot;
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port uninstall failed: $result&quot; 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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port installed failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] &gt; 0 } {
+        ui_notice &quot;The following ports are currently installed:&quot;
+        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 &quot;&quot;
+            set nvariants &quot;&quot;
+            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 &quot;&quot;
+                }
+                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 &amp;&amp; $os_platform ne &quot;&quot; &amp;&amp; $os_major != 0 &amp;&amp; $os_major ne &quot;&quot;} {
+                    append extra &quot; platform='$os_platform $os_major'&quot;
+                }
+                if {$archs != 0 &amp;&amp; $archs ne &quot;&quot;} {
+                    append extra &quot; archs='$archs'&quot;
+                }
+            }
+            if { $iactive == 0 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}&quot;
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are installed.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+
+    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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port outdated failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] &gt; 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 &quot;${installed_version}_${installed_revision}&quot;
+
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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 &quot;$portname has no version field&quot;
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot;
+            if {$epoch_comp_result != 0 &amp;&amp; $installed_version != $latest_version} {
+                if {($comp_result &gt;= 0 &amp;&amp; $epoch_comp_result &lt; 0) || ($comp_result &lt;= 0 &amp;&amp; $epoch_comp_result &gt; 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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &quot;&quot;
+                if { $comp_result &gt; 0 } {
+                    set relation &quot;&gt;&quot;
+                    set flag &quot;!&quot;
+                } else {
+                    set relation &quot;&lt;&quot;
+                }
+                
+                # Emit information
+                if {$comp_result &lt; 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice &quot;The following installed ports are outdated:&quot;
+                    }
+                    incr num_outdated
+
+                    puts [format &quot;%-30s %-24s %1s&quot; $portname &quot;$installed_compound $relation $latest_compound [subst $reason]&quot; $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice &quot;No installed ports are outdated.&quot;
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are outdated.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+    
+    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 &quot;%12s $file&quot; [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] &gt; 0 } {
+                ui_notice &quot;Port $portname contains:&quot;
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice &quot;Port $portname does not contain any files or is not active.&quot;
+            }
+        } else {
+            ui_notice &quot;Port $portname is not installed.&quot;
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq &quot;K&quot; || $units eq &quot;Ki&quot;} {
+        return &quot;KiB&quot;
+    } elseif {$units eq &quot;k&quot;} {
+        return &quot;kB&quot;
+    } elseif {$units eq &quot;Mi&quot;} {
+        return &quot;MiB&quot;
+    } elseif {$units eq &quot;M&quot;} {
+        return &quot;MB&quot;
+    } elseif {$units eq &quot;Gi&quot;} {
+        return &quot;GiB&quot;
+    } elseif {$units eq &quot;G&quot;} {
+        return &quot;GB&quot;
+    } 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] &gt; 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne &quot;yes&quot;} {
+                    set msg &quot;[bytesize $space $units] $portname&quot;
+                    if { $portversion != {} } {
+                        append msg &quot; @$portversion&quot;
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr &quot;Port $portname does not contain any file or is not active.&quot;
+            }
+        } else {
+            puts stderr &quot;Port $portname is not installed.&quot;
+        }
+    }
+    if {[llength $portlist] &gt; 1 || ([info exists options(ports_space_total)] &amp;&amp; $options(ports_space_total) eq &quot;yes&quot;)} {
+        puts &quot;[bytesize $spaceall $units] total&quot;
+    }
+    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 &quot;&quot;} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] &amp;&amp; $options(ports_variants_index) eq &quot;yes&quot;)} {
+            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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;port variants --index does not work with 'current' pseudo-port&quot;
+            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 &quot;$portname has no variants&quot;
+        } 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 &quot;$portname has the variants:&quot;
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier &quot;   &quot;
+                # 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 &quot;  $variations($v)&quot;
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier &quot;($global_variations($v))&quot;
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier &quot;\[$variant(is_default)\]&quot;
+                    }
+                    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 &quot;$varmodifier$v&quot; [string trim $vdescription] 0 [string repeat &quot; &quot; [expr 5 + [string length $v]]]]
+                } else {
+                    puts &quot;$varmodifier$v&quot;
+                }
+                if {[info exists vconflicts]} {
+                    puts &quot;     * conflicts with [string trim $vconflicts]&quot;
+                }
+                if {[info exists vrequires]} {
+                    puts &quot;     * requires [string trim $vrequires]&quot;
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        ui_error &quot;You must specify a search pattern&quot;
+        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)] &amp;&amp; $options(ports_search_depends) eq &quot;yes&quot;} {
+        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 &quot;none&quot;
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne &quot;yes&quot; } {
+            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) &quot;yes&quot;
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) &quot;yes&quot;
+        set filters(description) &quot;yes&quot;
+    }
+
+    set separator &quot;&quot;
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq &quot;none&quot;} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first &quot;*&quot; $portname] == -1 &amp;&amp; [string first &quot;?&quot; $portname] == -1} {
+                set searchstring &quot;*$portname*&quot;
+            }
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for name $portname failed: $result&quot; 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 &quot;&quot;
+        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 &quot;Invalid port entry, missing portname&quot;
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing description&quot;
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing version&quot;
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        &amp;&amp; $options(ports_search_line) eq &quot;yes&quot;} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)&quot;
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)&quot;
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline &quot;$portinfo(name) @$portinfo(version)&quot;
+                    if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                        puts -nonewline &quot;_$portinfo(revision)&quot;
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                    }
+                    puts &quot;&quot;
+                    puts [wrap [join $portinfo(description)] 0 [string repeat &quot; &quot; 4]]
+                }
+            }
+
+            set joiner &quot;\n&quot;
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice &quot;No match for $portname found&quot;
+        } elseif {[llength $res] &gt; 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne &quot;yes&quot;)} {
+                ui_notice &quot;\nFound [llength $res] ports.&quot;
+            }
+        }
+
+        set separator &quot;--\n&quot;
+    }
+
+    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] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        add_to_portlist portlist [list name &quot;-all-&quot;]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq &quot;-all-&quot;} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;listing all ports failed: $result&quot; 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $search_string failed: $result&quot; 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir &quot;&quot;
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format &quot;%-30s @%-14s %s&quot; $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 &quot;$key=$value&quot;
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne &quot;&quot; } {
+                set ver_field &quot;@$composite_version&quot;
+            } else {
+                set ver_field &quot;&quot;
+            }
+            puts [format &quot;%-30s %s %s&quot; $portname $ver_field  [join $opts &quot; &quot;]]
+        } else {
+            puts &quot;$portname&quot;
+        }
+    }
+
+    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 &quot;&quot;} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://${portdir}&quot;;    # Rebuild url so it's fully qualified
+        set portfile &quot;${portdir}/Portfile&quot;
+        
+        # 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 &quot;10.5&quot;} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor &quot;&quot;
+                    set editor_var &quot;ports_${action}_editor&quot;
+                    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 &quot;&quot; } { set editor &quot;/usr/bin/vi&quot; }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec &gt;@stdout &lt;@stdin 2&gt;@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug &quot;$errorInfo&quot;
+                        break_softcontinue &quot;unable to invoke editor $editor: $result&quot; 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq &quot;10.5&quot;} {
+                        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] &quot;main.log&quot;]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error &quot;Log file not found for port in $portdir&quot;
+                    }
+                }
+
+                gohome {
+                    set homepage &quot;&quot;
+
+                    # 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 &quot;&quot; &amp;&amp; ![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 &quot;&quot; } {
+                        if {[catch {system &quot;${macports::autoconf::open_path} '$homepage'&quot;} result]} {
+                            global errorInfo
+                            ui_debug &quot;$errorInfo&quot;
+                            break_softcontinue &quot;unable to invoke browser using ${macports::autoconf::open_path}: $result&quot; 1 status
+                        }
+                    } else {
+                        ui_error [format &quot;No homepage for %s&quot; $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue &quot;Could not read $portfile&quot; 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 &quot;$errorInfo&quot;
+        ui_msg &quot;port sync failed: $result&quot;
+        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 &quot;install&quot; || $action eq &quot;archive&quot;) &amp;&amp; [prefix_unwritable] &amp;&amp; ![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 &quot;&quot;} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn &quot;Skipping $portname (not in the ports tree)&quot;
+                    continue
+                } else {
+                    break_softcontinue &quot;Port $portname not found&quot; 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 &quot;&quot; &amp;&amp; [array get variations] ne &quot;&quot;} {
+            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 &quot;install&quot;} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq &quot;archive&quot;} {
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to execute port: $result&quot; 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue &quot;Processing of port $portname failed&quot; 1 status
+        }
+    }
+    
+    if {$status == 0 &amp;&amp; $action eq &quot;install&quot; &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] &amp;&amp; ![info exists options(ports_install_no-rev-upgrade)] &amp;&amp; ${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 &lt; $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn &lt; $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 &quot;action&quot;.
+# 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 &quot;&quot;
+    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 &quot;&quot;
+    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 &quot;-&quot;} {
+            break
+        } elseif {[string index $arg 1] eq &quot;-&quot;} {
+            # 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 &quot;${action} does not accept --${key}&quot;
+                    } elseif {[llength $kopts] &gt; 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst &quot;--[lindex $e 0]&quot;
+                        }
+                        return -code error &quot;\&quot;port ${action} --${key}\&quot; is ambiguous: \n  port ${action} [join $errlst &quot;\n  port ${action} &quot;]&quot;
+                    }
+                    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] &amp;&amp; $kargc &gt; 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc &gt; 0} {
+                            return -code error &quot;--${key} expects [expr {$kargc + [llength $args]}] parameters!&quot;
+                        }
+                        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]) &amp;&amp; [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == &quot;;&quot; } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == &quot;#&quot; } {
+            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] &gt; 1} {
+                ui_error &quot;\&quot;port ${action}\&quot; is ambiguous: \n  port [join $actions &quot;\n  port &quot;]&quot;
+            } else {
+                ui_error &quot;Unrecognized action \&quot;port $action\&quot;&quot;
+            }
+            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 &quot;$errorInfo&quot;
+            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 &quot;$action does not accept string arguments&quot;
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] &amp;&amp; ![match &quot;;&quot;] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error &quot;Improper expression syntax while processing parameters&quot;
+                        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 &quot;${text}*&quot; false glob]} result]} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;search for portname $pattern failed: $result&quot;
+        }
+        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 &quot;[string tolower $text]*&quot;]
+    }
+
+    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 &quot;[string tolower $text]*&quot;]
+
+    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 &quot;&quot;
+    }
+
+    # 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 &quot;&quot;
+    while { $line eq &quot;&quot; } {
+
+        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 &lt; 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline &amp;&amp; $line ne &quot;&quot; } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in &quot;stdin&quot;]
+    set name &quot;port&quot;
+    set use_readline [expr {$isstdin &amp;&amp; [readline init $name]}]
+    set history_file [file normalize &quot;${macports::macports_user_dir}/history&quot;]
+
+    # Read readline history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin &amp;&amp; ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts &quot;MacPorts [macports::version]&quot;
+        puts &quot;Entering interactive mode... (\&quot;help\&quot; for help, \&quot;quit\&quot; to quit)&quot;
+    }
+
+    # 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 &quot;\[$shortdir\] &gt; &quot;
+        } else {
+            set prompt &quot;&quot;
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] &lt;= 0  } {
+            puts &quot;&quot;
+            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 &amp;&amp; ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts &quot;Goodbye&quot;
+    }
+
+    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 &quot;-&quot;} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal &quot;Failed to open command file; $result&quot;
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne &quot;stdin&quot;} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 &amp;&amp; ![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
+    #        &quot;yes&quot;, if the progress indicator should be shown, &quot;no&quot; otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq &quot;yes&quot;} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] &gt; $showTimeThreshold &amp;&amp;
+                ($total == 0 || [expr {double($cur) / double($total)}] &lt; $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot;, &quot;intermission&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        &quot;intermission&quot; and &quot;finish&quot;, the args are empty and unused. For
+    #        &quot;update&quot;, 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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        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 &quot;\r&quot;
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        contains a single argument &quot;ul&quot; or &quot;dl&quot; indicating whether this is
+    #        an up- or download. For &quot;update&quot;, contains the arguments
+    #        (&quot;ul&quot;|&quot;dl&quot;) $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 &quot;finish&quot;.
+    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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format &quot;        speed: %-13s&quot; &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format &quot; %-10s     speed: %-13s&quot; [bytesize $now {} &quot;%6.1f&quot;] &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            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 &quot;\r&quot;
+                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 &quot;&quot;} {suffix &quot;&quot;}} {
+        # 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 &quot;\033\[7m&quot;
+        for {set i 0} {$i &lt; $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 &quot; &quot;
+        }
+        # back to normal output
+        append progressbar &quot;\033\[0m&quot;
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger &lt; $barWidth} {
+        #            append progressbar &quot; &quot;
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar &quot;\u258f&quot;
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar &quot;\u258e&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar &quot;\u258c&quot;
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258b&quot;
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar &quot;\u258a&quot;
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar &quot;\u2589&quot;
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i &lt; $barWidth} {incr i} {
+            append progressbar &quot; &quot;
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format &quot; %[expr {$percentageWidth - 3}].1f %%&quot; $percentage]
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}&quot;
+        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 &quot;&quot;} {suffix &quot;&quot;}} {
+        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 &quot;&quot;
+        for {set i 0} {$i &lt; $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar &quot;\u2022&quot;
+            } else {
+                append progressbar &quot; &quot;
+            }
+        }
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${suffix}&quot;
+        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] &gt; 0} {
+            ui_notice &quot;---&gt;  Some of the ports you installed have notes:&quot;
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice &quot;  $name has the following notes:&quot;
+
+                # 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 &quot;\n&quot;] {
+                            set joiner &quot;&quot;
+                            set lines &quot;&quot;
+                            set newline &quot;    &quot;
+
+                            foreach word [split $line &quot; &quot;] {
+                                if {[string length $newline] + [string length $word] &gt;= $maxlen} {
+                                    lappend lines $newline
+                                    set newline &quot;    &quot;
+                                    set joiner &quot;&quot;
+                                }
+                                ::append newline $joiner $word
+                                set joiner &quot; &quot;
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines &quot;\n&quot;]
+                        }
+                    }
+                } 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] &amp;&amp; $cmdname eq &quot;portf&quot;} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options &quot;global&quot; ui_options global_options} result]} {
+    puts &quot;Error: $result&quot;
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    &amp;&amp; $portclient::progress::hasTermAnsiSend eq &quot;yes&quot;
+    &amp;&amp; (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne &quot;yes&quot;)} {
+    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 &amp;&amp; ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq &quot;selfupdate&quot; || [lookahead] eq &quot;sync&quot;} {
+    # 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 &quot;$errorInfo&quot;
+    fatal &quot;Failed to initialize MacPorts, $result&quot;
+}
+
+# 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] &gt; 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]) &amp;&amp; [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
</ins></span></pre></div>
<a id="branchesgsoc14cleanupsrcportportBASE23878"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/port/port.BASE.23878 (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,5343 @@
</span><ins>+#!/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@macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw &lt;rshaw@opendarwin.org&gt;
+# 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 &quot;AS IS&quot;
+# 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. &quot;yes&quot;, if the package is available, &quot;no&quot; 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 &quot;Usage: $cmdname$syntax&quot;
+        puts stderr &quot;\&quot;$cmdname help\&quot; or \&quot;man 1 port\&quot; for more information.&quot;
+    } else {
+        puts stderr &quot;$cmdname$syntax&quot;
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds &quot;&quot;
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen &gt; 65} {
+            set cmds &quot;$cmds,\n&quot;
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new &quot;$cmd&quot;
+        } else {
+            set new &quot;, $cmd&quot;
+        }
+        incr lineLen [string length $new]
+        set cmds &quot;$cmds$new&quot;
+    }
+
+    set cmdText &quot;Supported actions
+------------------
+$cmds
+&quot;
+
+    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 &quot;$cmdText$text&quot;
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error &quot;$argv0: $s&quot;
+    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 &gt; 0x40000000} {
+            set unit &quot;GiB&quot;
+        } elseif {$siz &gt; 0x100000} {
+            set unit &quot;MiB&quot;
+        } elseif {$siz &gt; 0x400} {
+            set unit &quot;KiB&quot;
+        } else {
+            set unit &quot;B&quot;
+        }
+    }
+    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 &quot;Unknown file size unit '$unit' specified&quot;
+            set unit &quot;B&quot;
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return &quot;$siz $unit&quot;
+}
+
+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 &quot;/usr/local&quot; &amp;&amp; ${macports::prefix} ne &quot;/usr&quot;} {
+        ui_error &quot;Follow http://guide.macports.org/#project.tickets to report a bug.&quot;
+    }
+}
+
+# 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 &quot;+&quot;} {
+            lappend pos $key
+        } elseif {$val eq &quot;-&quot;} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version &quot;&quot;
+    if {$version ne &quot;&quot; || $emptyVersionOkay} {
+        set pos_str &quot;&quot;
+        set neg_str &quot;&quot;
+
+        if {[llength $pos]} {
+            set pos_str &quot;+[join [lsort -ascii $pos] &quot;+&quot;]&quot;
+        }
+        if {[llength $neg]} {
+            set neg_str &quot;-[join [lsort -ascii $neg] &quot;-&quot;]&quot;
+        }
+
+        set composite_version &quot;$version$pos_str$neg_str&quot;
+    }
+
+    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 &quot;${field}s&quot;
+        }
+        category {
+            set field &quot;categories&quot;
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion &quot;&quot;}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] &gt; 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 &quot;The following versions of $portname are currently installed:&quot;
+        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 &quot;  $iname @${iversion}_${irevision}${ivariants}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants} (active)&quot;
+            }
+        }
+        return -code error &quot;Registry error: Please specify the full version as recorded in the port registry.&quot;
+    } 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=&gt;+-)
+    #   requested_variants array  (variant=&gt;+-)
+    #   options array   (key=&gt;value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) &quot;&quot; }
+    if {![info exists port(name)]}      { set port(name) &quot;&quot; }
+    if {![info exists port(version)]}   { set port(version) &quot;&quot; }
+    if {![info exists port(variants)]}  { set port(variants) &quot;&quot; }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) &quot;&quot; }
+    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 &quot;&quot; &amp;&amp; $port(name) eq &quot;&quot; } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq &quot;&quot;} {
+            ui_error &quot;A default port name could not be supplied.&quot;
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) &quot;$port(name)/[composite_version $port(version) $port(variants)]&quot;
+    
+    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 &quot;&quot;}} {
+    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 &quot;&quot;
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg &quot;Can't map the URL '$url' to a port description file (\&quot;${result}\&quot;).&quot;
+            ui_msg &quot;Please verify that the directory and portfile syntax are correct.&quot;
+        }
+    } 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 &quot;no&quot;} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 &amp;&amp; (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq &quot;no&quot;)} {
+        if {${is_upgrade} == &quot;yes&quot;} {
+            # $&gt; port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # &quot;upgrade&quot;, let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg &quot;Nothing to upgrade.&quot;
+            return 1
+        }
+        ui_error &quot;No ports matched the given expression&quot;
+        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 &quot;array unset portspec; array set portspec { $portspec }&quot;
+        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) &quot;_&quot;]
+    set bvr_ [split $b_(version) &quot;_&quot;]
+    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_ &lt; $br_} {
+        return -1
+    } elseif {$ar_ &gt; $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name@version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list &quot;name&quot; [lindex $a 0] &quot;version&quot; &quot;[lindex $a 1]_[lindex $a 2]&quot;]
+    array set b_ [list &quot;name&quot; [lindex $b 0] &quot;version&quot; &quot;[lindex $b 1]_[lindex $b 2]&quot;]
+    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 {\\&amp;}]
+    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)] &amp;&amp; [lindex $size 0] &gt; 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] &amp;&amp; [lindex $size 1] &gt; 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 &quot;&quot;} {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 &quot;\n&quot;] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;} {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 &quot; &quot;]
+    if {$indentfirstline == 0} {
+        set newline &quot;&quot;
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner &quot; &quot;
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] &gt;= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner &quot;&quot;
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 &amp;&amp; $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner &quot; &quot;
+    }
+    lappend lines $newline
+    return [join $lines &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;}} {
+    append label &quot;: [string repeat &quot; &quot; [expr {[string length $indent] - [string length &quot;$label: &quot;]}]]&quot;
+    return &quot;$label[wrap $string $maxlen $indent 0]&quot;
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first &quot;@&quot; $m] &lt; 0} {
+            if {[string first &quot;:&quot; $m] &gt;= 0} {
+                set m [regsub -- &quot;(.*):(.*)&quot; $m &quot;\\2@\\1&quot;] 
+            } else {
+                set m &quot;$m@macports.org&quot;
+            }
+        }
+        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 &quot;$errorInfo&quot;
+        fatal &quot;search for portname $pattern failed: $result&quot;
+    }
+    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 &quot;$errorInfo&quot;
+            fatal &quot;listing all ports failed: $result&quot;
+        }
+        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 &quot;&quot;} {
+        ui_msg &quot;To use the current port, you must be in a port's directory.&quot;
+        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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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} == &quot;yes&quot; || (${active} == &quot;yes&quot;) == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] &gt; 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  &quot;${installed_version}_${installed_revision}&quot;
+            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 &quot;$errorInfo&quot;
+                fatal &quot;lookup of portname $portname failed: $result&quot;
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &lt; 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 &quot;$::errorInfo&quot;
+            break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+        }
+
+        if {[llength $result] &lt; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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 &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq &quot;&quot;} {
+            add_to_portlist results [list name $iname version &quot;[lindex $i 1]_[lindex $i 2]&quot; 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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+                        return -code error &quot;lookup of portname $depname failed: $result&quot;
+                    }
+                    if {[llength $result] &lt; 2} {
+                        ui_error &quot;Port $depname not found&quot;
+                        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 &quot;$::errorInfo&quot;
+                        ui_error &quot;Unable to open port: $result&quot;
+                        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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;&quot;
+    set name &quot;&quot;
+    set version &quot;&quot;
+    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 &quot;)&quot;]} {
+                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 &quot;depends_lib&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_build&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_run&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_extract&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_fetch&quot;]
+
+            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 &quot;rdependentof&quot;]
+            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 &quot;rdepof&quot;]
+            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 &quot;&quot;} {
+                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 &quot;Can't open URL '$token' as a port&quot;
+                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 &quot;&quot;} } {
+    upvar $resname reslist
+    
+    set version &quot;&quot;
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne &quot;&quot;} { 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/          ==&gt; a/
+    #   a/, b/          ==&gt;
+    #   a/, a/1.0       ==&gt; a/1.0
+    #   a/1.0, a/       ==&gt; a/1.0
+    #   a/1.0, a/2.0    ==&gt;
+    #
+    #   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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 &quot;&quot;
+    set portversion &quot;&quot;
+    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 &quot;provides&quot;
+        # so we take a rather lenient view of what a &quot;portname&quot; is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder &quot;&quot;
+        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 &quot;*/*&quot; $portname]} {
+                set url &quot;file://$portname&quot;
+                set name [url_to_portname $url 1]
+                if { $name ne &quot;&quot; } {
+                    # 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 &quot;&quot;
+                    # 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 &quot;Insufficient privileges to write to MacPorts install prefix.&quot;
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder &quot;&quot;} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion &quot;&quot;
+    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 &quot;&quot; || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq &quot;&quot;} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime &amp;&amp; [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first &quot;/&quot; $opt]
+            if {$sepPos &gt;= 0} {
+                # Version terminated by &quot;/&quot; 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 &quot;+&quot;, or else is complete
+                set sepPos [string first &quot;+&quot; $opt]
+                if {$sepPos &gt;= 0} {
+                    # Version terminated by &quot;+&quot;
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt &quot;&quot;
+                }
+            }
+            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) &quot;\&quot;$val\&quot;&quot;
+                set opt &quot;&quot;
+                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 &amp;&amp; $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds &quot;&quot;
+        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 &quot; --$name&quot;
+
+                for {set i 1} {$i &lt;= $optc} {incr i} {
+                    append cmds &quot; &lt;arg$i&gt;&quot;
+                }
+            }
+        }
+        set args &quot;&quot;
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;arguments&gt;&quot;
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;portlist&gt;&quot;
+        }
+
+        set ret &quot;Usage: &quot;
+        set len [string length $action]
+        append ret [wrap &quot;$action$cmds$args&quot; 0 [string repeat &quot; &quot; [expr {8 + $len}]] 0]
+        append ret &quot;\n&quot;
+
+        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 &quot;No usage for topic $topic&quot;
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile &quot;$macports::prefix/var/macports/port-help.tcl&quot;
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr &quot;Error reading helpfile $helpfile: $err&quot;
+            return 1
+        }
+    } else {
+        puts stderr &quot;Unable to open help file $helpfile&quot;
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr &quot;No help for topic $topic&quot;
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error &quot;No usage for topic $topic&quot;
+            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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 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 &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] &quot;main.log&quot;]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue &quot;Could not open file $logfile: $result&quot; 1 status
+            }
+            set data [read $fp]
+            set data [split $data &quot;\n&quot;]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase &quot;\[a-z\]*&quot;
+            }
+
+            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 &quot;&quot;
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] &quot;|&quot;]
+                }
+            } else {
+                set prefix &quot;\[a-z\]*&quot;
+            }
+            foreach line $data {
+                set exp &quot;^:($prefix|any):($phase|any) (.*)$&quot;
+                if {[regexp $exp $line -&gt; lpriority lphase lmsg] == 1} {
+                    puts &quot;[macports::ui_prefix_default $lpriority]$lmsg&quot;
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue &quot;Log file for port $portname not found&quot; 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator &quot;&quot;
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] &amp;&amp; $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 &quot;&quot; || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;no PortIndex entry found for $portname&quot;
+            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 &quot;
+            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
+        &quot;
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     &quot;&quot;
+            variants    Variants
+            depends_fetch &quot;Fetch Dependencies&quot;
+            depends_extract &quot;Extract Dependencies&quot;
+            depends_build &quot;Build Dependencies&quot;
+            depends_run &quot;Runtime Dependencies&quot;
+            depends_lib &quot;Library Dependencies&quot;
+            description &quot;Brief Description&quot;
+            long_description &quot;Description&quot;
+            fullname    &quot;Full Name: &quot;
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   &quot;Conflicts with&quot;
+            replaced_by &quot;Replaced by&quot;
+            subports    &quot;Sub-ports&quot;
+        }
+
+        # 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)] &amp;&amp; $options(ports_info_depends) eq &quot;yes&quot;} {
+            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 &quot;\n&quot;
+        set subfield_sep &quot;, &quot;
+        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 &quot;\t&quot;
+            set subfield_sep &quot;,&quot;
+        }
+        
+        # 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 &amp;&amp; $opt eq &quot;skip_line&quot;} {
+                lappend fields &quot;&quot;
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq &quot;heading&quot;} {
+                set inf &quot;$portinfo(name) @$portinfo(version)&quot;
+                set ropt &quot;heading&quot;
+                if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                    append inf &quot;_$portinfo(revision)&quot;
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                }
+            } elseif {$opt eq &quot;fullname&quot;} {
+                set inf &quot;$portinfo(name) @&quot;
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt &quot;fullname&quot;
+            } 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 &quot;&quot;
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label &quot;&quot;
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label &quot;$opt: &quot;
+            }
+            
+            # Format the data
+            if { $ropt eq &quot;maintainers&quot; } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq &quot;variants&quot;} {
+                    # 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 &quot;&quot;
+                        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 &quot;($global_variations($v))&quot;
+                            # 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 &quot;\[$variant(is_default)]&quot;
+                            }
+                        }
+                        lappend inf &quot;$varmodifier$v&quot;
+                    }
+                } elseif {[string match &quot;depend*&quot; $ropt] 
+                          &amp;&amp; ![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 &quot;heading&quot; || $ropt eq &quot;fullname&quot;} {
+                    puts &quot;$label$field&quot;
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq &quot;&quot;} {
+                    continue
+                }
+                if {$label eq &quot;&quot;} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat &quot; &quot; $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 &quot; &quot; $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields &quot;$label$field&quot;
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print &amp;&amp; [llength $fields_tried]} {
+                puts -nonewline &quot;$portinfo(name) has no &quot;
+                puts [join $fields_tried &quot;, &quot;]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator &quot;--\n&quot;
+        }
+    }
+    
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port location failed: $result&quot; 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 &quot;Port $portname ${version}_${revision}${variants} is installed as an image in:&quot;
+        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 &quot;&quot;} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue &quot;The lookup of '$portname' failed: $result&quot; \
+                                1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;The port '$portname' was not found&quot; 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 &quot;The URL '$porturl' could not be&quot; \
+                                       &quot;opened: $result&quot;] 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 &quot;$portname has the following notes:&quot;
+            foreach note $portnotes {
+                puts [wrap $note 0 &quot;  &quot; 1]
+            }
+        } else {
+            puts &quot;$portname has no notes.&quot;
+        }
+    }
+    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 &quot;Please specify a filename to check which port provides that file.&quot;
+        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 &quot;link&quot;} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts &quot;$file is provided by: $port&quot;
+                } else {
+                    puts &quot;$file is not provided by a MacPorts port.&quot;
+                }
+            } else {
+                puts &quot;$file is a directory.&quot;
+            }
+        } else {
+            puts &quot;$file does not exist.&quot;
+        }
+    }
+    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)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port activate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping activate $portname (dry run)&quot;
+        }
+    }
+    
+    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)]
+            &amp;&amp; ![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 &quot;&quot; || $composite_version == &quot;${iversion}_${irevision}${ivariants}&quot;} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port deactivate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping deactivate $portname (dry run)&quot;
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug &quot;action_select \[$portlist] \[$opts]...&quot;
+
+    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] &lt; 1 &amp;&amp; [string map {ports_select_ &quot;&quot;} [lindex $commands 0]] != &quot;summary&quot;} {
+        ui_error &quot;port select \[--list|--set|--show|--summary] \&lt;group&gt; \[&lt;version&gt;]&quot;
+        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] &lt; 1 &amp;&amp; [llength $portlist] &gt; 1} {
+        set command set
+        ui_debug [concat &quot;Although no command was specified, more than &quot; \
+                         &quot;one argument was specified.  Defaulting to the &quot; \
+                         &quot;'set' command...&quot;]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] &lt; 1} {
+        set command list
+        ui_debug [concat &quot;No command was specified. Defaulting to the &quot; \
+                         &quot;'list' command...&quot;]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] &gt; 1} {
+        ui_error [concat &quot;Multiple commands were specified. Only one &quot; \
+                         &quot;command may be specified at a time.&quot;]
+        return 1
+    } else {
+        set command [string map {ports_select_ &quot;&quot;} [lindex $commands 0]]
+        ui_debug &quot;The '$command' command was specified.&quot;
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'list' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn &quot;Unable to get active selected version: $selected_version&quot;
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error &quot;The 'list' command failed: $versions&quot;
+                return 1
+            }
+
+            ui_notice &quot;Available versions for $group:&quot;
+            foreach v $versions {
+                ui_notice -nonewline &quot;\t&quot;
+                if {$selected_version == $v} {
+                    ui_msg &quot;$v (active)&quot;
+                } else {
+                    ui_msg &quot;$v&quot;
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] &lt; 2} {
+                ui_error [concat &quot;The 'set' command expects two &quot; \
+                                 &quot;arguments: &lt;group&gt;, &lt;version&gt;&quot;]
+                return 1
+            } elseif {[llength $portlist] &gt; 2} {
+                ui_warn [concat &quot;The 'set' command only expects two &quot; \
+                                &quot;arguments. Extra arguments will be &quot; \
+                                &quot;ignored.&quot;]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline &quot;Selecting '$version' for '$group' &quot;
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg &quot;failed: $result&quot;
+                return 1
+            }
+            ui_msg &quot;succeeded. '$version' is now active.&quot;
+            return 0
+        }
+        show {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'show' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error &quot;The 'show' command failed: $selected_version&quot;
+                return 1
+            }
+            puts [concat &quot;The currently selected version for '$group' is &quot; \
+                         &quot;'$selected_version'.&quot;]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] &gt; 0} {
+                ui_warn [concat &quot;The 'summary' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error &quot;The 'summary' command failed: $portgroups&quot;
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr &quot;%-*s  %-*s  %s&quot;
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn &quot;The list of options for the select group $pg could not be obtained: $versions&quot;
+                    continue
+                }
+                # remove &quot;none&quot;, sort the list, append none at the end
+                set noneidx [lsearch -exact $versions &quot;none&quot;]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions &quot;none&quot;
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn &quot;The currently selected option for the select group $pg could not be obtained: $selected_version&quot;
+                    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 &quot;Name&quot; $w2 &quot;Selected&quot; &quot;Options&quot;]
+            puts [format $formatStr $w1 &quot;====&quot; $w2 &quot;========&quot; &quot;=======&quot;]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) &quot; &quot;]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error &quot;An unknown command '$command' was specified.&quot;
+            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 &quot;$errorInfo&quot;
+        ui_error &quot;$result&quot;
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg &quot;Please run `port -v selfupdate' for details.&quot;
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal &quot;port selfupdate failed: $result&quot;
+    }
+    
+    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 &quot;setrequested&quot;]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info &quot;Setting requested flag for $portname to $val&quot;
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist &quot;yes&quot;] || ([prefix_unwritable] &amp;&amp; ![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 &quot;port:$portname&quot; [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 &amp;&amp; $status != 2 &amp;&amp; $status != 3 &amp;&amp; ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 &amp;&amp; $status != 2 &amp;&amp; $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] &amp;&amp; ${macports::revupgrade_autorun} &amp;&amp; ![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 &quot;Version: &quot;
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline &quot;Platform: &quot;
+    }
+    puts &quot;${macports::os_platform} ${macports::os_major} ${macports::os_arch}&quot;
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 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] &gt; 0 } {
+            if {$action eq &quot;rdependents&quot;} {
+                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] &gt; 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice &quot;The following ports are dependent on ${portname}:&quot;
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos &gt;= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] &lt;= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] &amp;&amp; [string is true -strict $options(ports_rdependents_full)])} {
+                        puts &quot;${spaces}${cur_portname}&quot;
+                        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 &quot;$depport&quot;
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg &quot;$depport depends on $portname&quot;
+                    } else {
+                        ui_msg &quot;$depport depends on $portname (by [lindex $dep 1]:)&quot;
+                    }
+                }
+            }
+        } else {
+            ui_notice &quot;$portname has no dependents.&quot;
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator &quot;&quot;
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] &amp;&amp; [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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn &quot;port ${action} --index does not work with the 'current' pseudo-port&quot;
+            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 &quot;rdeps&quot; || [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 &quot;deps&quot;} {
+                    set label &quot;$labeldict($type) Dependencies&quot;
+                    lappend deps_output [wraplabel $label [join $deplist &quot;, &quot;] 0 [string repeat &quot; &quot; 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 &quot;deps&quot;} {
+            if {$ndeps == 0} {
+                ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+            } else {
+                ui_notice &quot;Full Name: $portname @${version}_${revision}${variants}&quot;
+                puts [join $deps_output &quot;\n&quot;]
+            }
+            set separator &quot;--\n&quot;
+            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 &quot;$::errorInfo&quot;
+                        break_softcontinue &quot;lookup of portname $depname failed: $result&quot; 1 status
+                    }
+                    if {[llength $result] &lt; 2} {
+                        break_softcontinue &quot;Port $depname not found&quot; 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)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug &quot;$::errorInfo&quot;
+                            break_softcontinue &quot;Unable to open port: $result&quot; 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] &gt; 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] &gt; 0} {
+            ui_notice &quot;The following ports are dependencies of $portname @${version}_${revision}${variants}:&quot;
+        } else {
+            ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos &gt;= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] &lt;= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] &amp;&amp; [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts &quot;${spaces}${cur_port}&quot;
+                } else {
+                    puts &quot;${spaces}${cur_portname}&quot;
+                }
+                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 &quot;--\n&quot;
+    }
+    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 &quot;$portname is not installed&quot;
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn &quot;no such port: $portname, skipping uninstall&quot;
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port uninstall failed: $result&quot; 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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port installed failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] &gt; 0 } {
+        ui_notice &quot;The following ports are currently installed:&quot;
+        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 &quot;&quot;
+            set nvariants &quot;&quot;
+            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 &quot;&quot;
+                }
+                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 &amp;&amp; $os_platform ne &quot;&quot; &amp;&amp; $os_major != 0 &amp;&amp; $os_major ne &quot;&quot;} {
+                    append extra &quot; platform='$os_platform $os_major'&quot;
+                }
+                if {$archs != 0 &amp;&amp; $archs ne &quot;&quot;} {
+                    append extra &quot; archs='$archs'&quot;
+                }
+            }
+            if { $iactive == 0 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}&quot;
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are installed.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+
+    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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port outdated failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] &gt; 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 &quot;${installed_version}_${installed_revision}&quot;
+
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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 &quot;$portname has no version field&quot;
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot;
+            if {$epoch_comp_result != 0 &amp;&amp; $installed_version != $latest_version} {
+                if {($comp_result &gt;= 0 &amp;&amp; $epoch_comp_result &lt; 0) || ($comp_result &lt;= 0 &amp;&amp; $epoch_comp_result &gt; 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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &quot;&quot;
+                if { $comp_result &gt; 0 } {
+                    set relation &quot;&gt;&quot;
+                    set flag &quot;!&quot;
+                } else {
+                    set relation &quot;&lt;&quot;
+                }
+                
+                # Emit information
+                if {$comp_result &lt; 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice &quot;The following installed ports are outdated:&quot;
+                    }
+                    incr num_outdated
+
+                    puts [format &quot;%-30s %-24s %1s&quot; $portname &quot;$installed_compound $relation $latest_compound [subst $reason]&quot; $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice &quot;No installed ports are outdated.&quot;
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are outdated.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+    
+    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 &quot;%12s $file&quot; [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] &gt; 0 } {
+                ui_notice &quot;Port $portname contains:&quot;
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice &quot;Port $portname does not contain any files or is not active.&quot;
+            }
+        } else {
+            ui_notice &quot;Port $portname is not installed.&quot;
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq &quot;K&quot; || $units eq &quot;Ki&quot;} {
+        return &quot;KiB&quot;
+    } elseif {$units eq &quot;k&quot;} {
+        return &quot;kB&quot;
+    } elseif {$units eq &quot;Mi&quot;} {
+        return &quot;MiB&quot;
+    } elseif {$units eq &quot;M&quot;} {
+        return &quot;MB&quot;
+    } elseif {$units eq &quot;Gi&quot;} {
+        return &quot;GiB&quot;
+    } elseif {$units eq &quot;G&quot;} {
+        return &quot;GB&quot;
+    } 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] &gt; 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne &quot;yes&quot;} {
+                    set msg &quot;[bytesize $space $units] $portname&quot;
+                    if { $portversion != {} } {
+                        append msg &quot; @$portversion&quot;
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr &quot;Port $portname does not contain any file or is not active.&quot;
+            }
+        } else {
+            puts stderr &quot;Port $portname is not installed.&quot;
+        }
+    }
+    if {[llength $portlist] &gt; 1 || ([info exists options(ports_space_total)] &amp;&amp; $options(ports_space_total) eq &quot;yes&quot;)} {
+        puts &quot;[bytesize $spaceall $units] total&quot;
+    }
+    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 &quot;&quot;} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] &amp;&amp; $options(ports_variants_index) eq &quot;yes&quot;)} {
+            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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;port variants --index does not work with 'current' pseudo-port&quot;
+            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 &quot;$portname has no variants&quot;
+        } 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 &quot;$portname has the variants:&quot;
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier &quot;   &quot;
+                # 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 &quot;  $variations($v)&quot;
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier &quot;($global_variations($v))&quot;
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier &quot;\[$variant(is_default)\]&quot;
+                    }
+                    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 &quot;$varmodifier$v&quot; [string trim $vdescription] 0 [string repeat &quot; &quot; [expr 5 + [string length $v]]]]
+                } else {
+                    puts &quot;$varmodifier$v&quot;
+                }
+                if {[info exists vconflicts]} {
+                    puts &quot;     * conflicts with [string trim $vconflicts]&quot;
+                }
+                if {[info exists vrequires]} {
+                    puts &quot;     * requires [string trim $vrequires]&quot;
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        ui_error &quot;You must specify a search pattern&quot;
+        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)] &amp;&amp; $options(ports_search_depends) eq &quot;yes&quot;} {
+        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 &quot;none&quot;
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne &quot;yes&quot; } {
+            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) &quot;yes&quot;
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) &quot;yes&quot;
+        set filters(description) &quot;yes&quot;
+    }
+
+    set separator &quot;&quot;
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq &quot;none&quot;} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first &quot;*&quot; $portname] == -1 &amp;&amp; [string first &quot;?&quot; $portname] == -1} {
+                set searchstring &quot;*$portname*&quot;
+            }
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for name $portname failed: $result&quot; 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 &quot;&quot;
+        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 &quot;Invalid port entry, missing portname&quot;
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing description&quot;
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing version&quot;
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        &amp;&amp; $options(ports_search_line) eq &quot;yes&quot;} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)&quot;
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)&quot;
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline &quot;$portinfo(name) @$portinfo(version)&quot;
+                    if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                        puts -nonewline &quot;_$portinfo(revision)&quot;
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                    }
+                    puts &quot;&quot;
+                    puts [wrap [join $portinfo(description)] 0 [string repeat &quot; &quot; 4]]
+                }
+            }
+
+            set joiner &quot;\n&quot;
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice &quot;No match for $portname found&quot;
+        } elseif {[llength $res] &gt; 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne &quot;yes&quot;)} {
+                ui_notice &quot;\nFound [llength $res] ports.&quot;
+            }
+        }
+
+        set separator &quot;--\n&quot;
+    }
+
+    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] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        add_to_portlist portlist [list name &quot;-all-&quot;]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq &quot;-all-&quot;} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;listing all ports failed: $result&quot; 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $search_string failed: $result&quot; 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir &quot;&quot;
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format &quot;%-30s @%-14s %s&quot; $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 &quot;$key=$value&quot;
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne &quot;&quot; } {
+                set ver_field &quot;@$composite_version&quot;
+            } else {
+                set ver_field &quot;&quot;
+            }
+            puts [format &quot;%-30s %s %s&quot; $portname $ver_field  [join $opts &quot; &quot;]]
+        } else {
+            puts &quot;$portname&quot;
+        }
+    }
+
+    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 &quot;&quot;} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://${portdir}&quot;;    # Rebuild url so it's fully qualified
+        set portfile &quot;${portdir}/Portfile&quot;
+        
+        # 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 &quot;10.5&quot;} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor &quot;&quot;
+                    set editor_var &quot;ports_${action}_editor&quot;
+                    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 &quot;&quot; } { set editor &quot;/usr/bin/vi&quot; }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec &gt;@stdout &lt;@stdin 2&gt;@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug &quot;$errorInfo&quot;
+                        break_softcontinue &quot;unable to invoke editor $editor: $result&quot; 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq &quot;10.5&quot;} {
+                        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] &quot;main.log&quot;]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error &quot;Log file not found for port in $portdir&quot;
+                    }
+                }
+
+                gohome {
+                    set homepage &quot;&quot;
+
+                    # 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 &quot;&quot; &amp;&amp; ![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 &quot;&quot; } {
+                        if {[catch {system &quot;${macports::autoconf::open_path} '$homepage'&quot;} result]} {
+                            global errorInfo
+                            ui_debug &quot;$errorInfo&quot;
+                            break_softcontinue &quot;unable to invoke browser using ${macports::autoconf::open_path}: $result&quot; 1 status
+                        }
+                    } else {
+                        ui_error [format &quot;No homepage for %s&quot; $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue &quot;Could not read $portfile&quot; 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 &quot;$errorInfo&quot;
+        ui_msg &quot;port sync failed: $result&quot;
+        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 &quot;install&quot; || $action eq &quot;archive&quot;) &amp;&amp; [prefix_unwritable] &amp;&amp; ![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 &quot;&quot;} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn &quot;Skipping $portname (not in the ports tree)&quot;
+                    continue
+                } else {
+                    break_softcontinue &quot;Port $portname not found&quot; 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 &quot;&quot; &amp;&amp; [array get variations] ne &quot;&quot;} {
+            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 &quot;install&quot;} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq &quot;archive&quot;} {
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to execute port: $result&quot; 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue &quot;Processing of port $portname failed&quot; 1 status
+        }
+    }
+    
+    if {$status == 0 &amp;&amp; $action eq &quot;install&quot; &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] &amp;&amp; ![info exists options(ports_install_no-rev-upgrade)] &amp;&amp; ${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 &lt; $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn &lt; $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 &quot;action&quot;.
+# 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 &quot;&quot;
+    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 &quot;&quot;
+    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 &quot;-&quot;} {
+            break
+        } elseif {[string index $arg 1] eq &quot;-&quot;} {
+            # 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 &quot;${action} does not accept --${key}&quot;
+                    } elseif {[llength $kopts] &gt; 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst &quot;--[lindex $e 0]&quot;
+                        }
+                        return -code error &quot;\&quot;port ${action} --${key}\&quot; is ambiguous: \n  port ${action} [join $errlst &quot;\n  port ${action} &quot;]&quot;
+                    }
+                    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] &amp;&amp; $kargc &gt; 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc &gt; 0} {
+                            return -code error &quot;--${key} expects [expr {$kargc + [llength $args]}] parameters!&quot;
+                        }
+                        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]) &amp;&amp; [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == &quot;;&quot; } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == &quot;#&quot; } {
+            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] &gt; 1} {
+                ui_error &quot;\&quot;port ${action}\&quot; is ambiguous: \n  port [join $actions &quot;\n  port &quot;]&quot;
+            } else {
+                ui_error &quot;Unrecognized action \&quot;port $action\&quot;&quot;
+            }
+            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 &quot;$errorInfo&quot;
+            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 &quot;$action does not accept string arguments&quot;
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] &amp;&amp; ![match &quot;;&quot;] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error &quot;Improper expression syntax while processing parameters&quot;
+                        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 &quot;${text}*&quot; false glob]} result]} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;search for portname $pattern failed: $result&quot;
+        }
+        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 &quot;[string tolower $text]*&quot;]
+    }
+
+    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 &quot;[string tolower $text]*&quot;]
+
+    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 &quot;&quot;
+    }
+
+    # 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 &quot;&quot;
+    while { $line eq &quot;&quot; } {
+
+        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 &lt; 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline &amp;&amp; $line ne &quot;&quot; } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in &quot;stdin&quot;]
+    set name &quot;port&quot;
+    set use_readline [expr {$isstdin &amp;&amp; [readline init $name]}]
+    set history_file [file normalize &quot;${macports::macports_user_dir}/history&quot;]
+
+    # Read readline history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin &amp;&amp; ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts &quot;MacPorts [macports::version]&quot;
+        puts &quot;Entering interactive mode... (\&quot;help\&quot; for help, \&quot;quit\&quot; to quit)&quot;
+    }
+
+    # 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 &quot;\[$shortdir\] &gt; &quot;
+        } else {
+            set prompt &quot;&quot;
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] &lt;= 0  } {
+            puts &quot;&quot;
+            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 &amp;&amp; ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts &quot;Goodbye&quot;
+    }
+
+    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 &quot;-&quot;} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal &quot;Failed to open command file; $result&quot;
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne &quot;stdin&quot;} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 &amp;&amp; ![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
+    #        &quot;yes&quot;, if the progress indicator should be shown, &quot;no&quot; otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq &quot;yes&quot;} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] &gt; $showTimeThreshold &amp;&amp;
+                ($total == 0 || [expr {double($cur) / double($total)}] &lt; $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot;, &quot;intermission&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        &quot;intermission&quot; and &quot;finish&quot;, the args are empty and unused. For
+    #        &quot;update&quot;, 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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        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 &quot;\r&quot;
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        contains a single argument &quot;ul&quot; or &quot;dl&quot; indicating whether this is
+    #        an up- or download. For &quot;update&quot;, contains the arguments
+    #        (&quot;ul&quot;|&quot;dl&quot;) $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 &quot;finish&quot;.
+    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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format &quot;        speed: %-13s&quot; &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format &quot; %-10s     speed: %-13s&quot; [bytesize $now {} &quot;%6.1f&quot;] &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            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 &quot;\r&quot;
+                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 &quot;&quot;} {suffix &quot;&quot;}} {
+        # 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 &quot;\033\[7m&quot;
+        for {set i 0} {$i &lt; $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 &quot; &quot;
+        }
+        # back to normal output
+        append progressbar &quot;\033\[0m&quot;
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger &lt; $barWidth} {
+        #            append progressbar &quot; &quot;
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar &quot;\u258f&quot;
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar &quot;\u258e&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar &quot;\u258c&quot;
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258b&quot;
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar &quot;\u258a&quot;
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar &quot;\u2589&quot;
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i &lt; $barWidth} {incr i} {
+            append progressbar &quot; &quot;
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format &quot; %[expr {$percentageWidth - 3}].1f %%&quot; $percentage]
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}&quot;
+        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 &quot;&quot;} {suffix &quot;&quot;}} {
+        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 &quot;&quot;
+        for {set i 0} {$i &lt; $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar &quot;\u2022&quot;
+            } else {
+                append progressbar &quot; &quot;
+            }
+        }
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${suffix}&quot;
+        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] &gt; 0} {
+            ui_notice &quot;---&gt;  Some of the ports you installed have notes:&quot;
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice &quot;  $name has the following notes:&quot;
+
+                # 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 &quot;\n&quot;] {
+                            set joiner &quot;&quot;
+                            set lines &quot;&quot;
+                            set newline &quot;    &quot;
+
+                            foreach word [split $line &quot; &quot;] {
+                                if {[string length $newline] + [string length $word] &gt;= $maxlen} {
+                                    lappend lines $newline
+                                    set newline &quot;    &quot;
+                                    set joiner &quot;&quot;
+                                }
+                                ::append newline $joiner $word
+                                set joiner &quot; &quot;
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines &quot;\n&quot;]
+                        }
+                    }
+                } 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] &amp;&amp; $cmdname eq &quot;portf&quot;} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options &quot;global&quot; ui_options global_options} result]} {
+    puts &quot;Error: $result&quot;
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    &amp;&amp; $portclient::progress::hasTermAnsiSend eq &quot;yes&quot;
+    &amp;&amp; (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne &quot;yes&quot;)} {
+    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 &amp;&amp; ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq &quot;selfupdate&quot; || [lookahead] eq &quot;sync&quot;} {
+    # 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 &quot;$errorInfo&quot;
+    fatal &quot;Failed to initialize MacPorts, $result&quot;
+}
+
+# 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] &gt; 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]) &amp;&amp; [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
</ins></span></pre></div>
<a id="branchesgsoc14cleanupsrcportportLOCAL23878"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/port/port.LOCAL.23878 (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,5348 @@
</span><ins>+#!/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@macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw &lt;rshaw@opendarwin.org&gt;
+# 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 &quot;AS IS&quot;
+# 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. &quot;yes&quot;, if the package is available, &quot;no&quot; 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 &quot;Usage: $cmdname$syntax&quot;
+        puts stderr &quot;\&quot;$cmdname help\&quot; or \&quot;man 1 port\&quot; for more information.&quot;
+    } else {
+        puts stderr &quot;$cmdname$syntax&quot;
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds &quot;&quot;
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen &gt; 65} {
+            set cmds &quot;$cmds,\n&quot;
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new &quot;$cmd&quot;
+        } else {
+            set new &quot;, $cmd&quot;
+        }
+        incr lineLen [string length $new]
+        set cmds &quot;$cmds$new&quot;
+    }
+
+    set cmdText &quot;Supported actions
+------------------
+$cmds
+&quot;
+
+    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 &quot;$cmdText$text&quot;
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error &quot;$argv0: $s&quot;
+    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 &gt; 0x40000000} {
+            set unit &quot;GiB&quot;
+        } elseif {$siz &gt; 0x100000} {
+            set unit &quot;MiB&quot;
+        } elseif {$siz &gt; 0x400} {
+            set unit &quot;KiB&quot;
+        } else {
+            set unit &quot;B&quot;
+        }
+    }
+    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 &quot;Unknown file size unit '$unit' specified&quot;
+            set unit &quot;B&quot;
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return &quot;$siz $unit&quot;
+}
+
+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 &quot;/usr/local&quot; &amp;&amp; ${macports::prefix} ne &quot;/usr&quot;} {
+        ui_error &quot;Follow http://guide.macports.org/#project.tickets to report a bug.&quot;
+    }
+}
+
+# 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 &quot;+&quot;} {
+            lappend pos $key
+        } elseif {$val eq &quot;-&quot;} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version &quot;&quot;
+    if {$version ne &quot;&quot; || $emptyVersionOkay} {
+        set pos_str &quot;&quot;
+        set neg_str &quot;&quot;
+
+        if {[llength $pos]} {
+            set pos_str &quot;+[join [lsort -ascii $pos] &quot;+&quot;]&quot;
+        }
+        if {[llength $neg]} {
+            set neg_str &quot;-[join [lsort -ascii $neg] &quot;-&quot;]&quot;
+        }
+
+        set composite_version &quot;$version$pos_str$neg_str&quot;
+    }
+
+    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 &quot;${field}s&quot;
+        }
+        category {
+            set field &quot;categories&quot;
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion &quot;&quot;}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] &gt; 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 &quot;The following versions of $portname are currently installed:&quot;
+        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 &quot;  $iname @${iversion}_${irevision}${ivariants}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants} (active)&quot;
+            }
+        }
+        return -code error &quot;Registry error: Please specify the full version as recorded in the port registry.&quot;
+    } 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=&gt;+-)
+    #   requested_variants array  (variant=&gt;+-)
+    #   options array   (key=&gt;value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) &quot;&quot; }
+    if {![info exists port(name)]}      { set port(name) &quot;&quot; }
+    if {![info exists port(version)]}   { set port(version) &quot;&quot; }
+    if {![info exists port(variants)]}  { set port(variants) &quot;&quot; }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) &quot;&quot; }
+    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 &quot;&quot; &amp;&amp; $port(name) eq &quot;&quot; } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq &quot;&quot;} {
+            ui_error &quot;A default port name could not be supplied.&quot;
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) &quot;$port(name)/[composite_version $port(version) $port(variants)]&quot;
+    
+    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 &quot;&quot;}} {
+    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 &quot;&quot;
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg &quot;Can't map the URL '$url' to a port description file (\&quot;${result}\&quot;).&quot;
+            ui_msg &quot;Please verify that the directory and portfile syntax are correct.&quot;
+        }
+    } 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 &quot;no&quot;} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 &amp;&amp; (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq &quot;no&quot;)} {
+        if {${is_upgrade} == &quot;yes&quot;} {
+            # $&gt; port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # &quot;upgrade&quot;, let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg &quot;Nothing to upgrade.&quot;
+            return 1
+        }
+        ui_error &quot;No ports matched the given expression&quot;
+        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 &quot;array unset portspec; array set portspec { $portspec }&quot;
+        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) &quot;_&quot;]
+    set bvr_ [split $b_(version) &quot;_&quot;]
+    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_ &lt; $br_} {
+        return -1
+    } elseif {$ar_ &gt; $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name@version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list &quot;name&quot; [lindex $a 0] &quot;version&quot; &quot;[lindex $a 1]_[lindex $a 2]&quot;]
+    array set b_ [list &quot;name&quot; [lindex $b 0] &quot;version&quot; &quot;[lindex $b 1]_[lindex $b 2]&quot;]
+    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 {\\&amp;}]
+    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)] &amp;&amp; [lindex $size 0] &gt; 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] &amp;&amp; [lindex $size 1] &gt; 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 &quot;&quot;} {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 &quot;\n&quot;] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;} {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 &quot; &quot;]
+    if {$indentfirstline == 0} {
+        set newline &quot;&quot;
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner &quot; &quot;
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] &gt;= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner &quot;&quot;
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 &amp;&amp; $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner &quot; &quot;
+    }
+    lappend lines $newline
+    return [join $lines &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;}} {
+    append label &quot;: [string repeat &quot; &quot; [expr {[string length $indent] - [string length &quot;$label: &quot;]}]]&quot;
+    return &quot;$label[wrap $string $maxlen $indent 0]&quot;
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first &quot;@&quot; $m] &lt; 0} {
+            if {[string first &quot;:&quot; $m] &gt;= 0} {
+                set m [regsub -- &quot;(.*):(.*)&quot; $m &quot;\\2@\\1&quot;] 
+            } else {
+                set m &quot;$m@macports.org&quot;
+            }
+        }
+        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 &quot;$errorInfo&quot;
+        fatal &quot;search for portname $pattern failed: $result&quot;
+    }
+    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 &quot;$errorInfo&quot;
+            fatal &quot;listing all ports failed: $result&quot;
+        }
+        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 &quot;&quot;} {
+        ui_msg &quot;To use the current port, you must be in a port's directory.&quot;
+        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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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} == &quot;yes&quot; || (${active} == &quot;yes&quot;) == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] &gt; 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  &quot;${installed_version}_${installed_revision}&quot;
+            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 &quot;$errorInfo&quot;
+                fatal &quot;lookup of portname $portname failed: $result&quot;
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &lt; 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 &quot;$::errorInfo&quot;
+            break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+        }
+
+        if {[llength $result] &lt; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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 &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq &quot;&quot;} {
+            add_to_portlist results [list name $iname version &quot;[lindex $i 1]_[lindex $i 2]&quot; 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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+                        return -code error &quot;lookup of portname $depname failed: $result&quot;
+                    }
+                    if {[llength $result] &lt; 2} {
+                        ui_error &quot;Port $depname not found&quot;
+                        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 &quot;$::errorInfo&quot;
+                        ui_error &quot;Unable to open port: $result&quot;
+                        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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;&quot;
+    set name &quot;&quot;
+    set version &quot;&quot;
+    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 &quot;)&quot;]} {
+                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 &quot;depends_lib&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_build&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_run&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_extract&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_fetch&quot;]
+
+            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 &quot;rdependentof&quot;]
+            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 &quot;rdepof&quot;]
+            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 &quot;&quot;} {
+                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 &quot;Can't open URL '$token' as a port&quot;
+                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 &quot;&quot;} } {
+    upvar $resname reslist
+    
+    set version &quot;&quot;
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne &quot;&quot;} { 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/          ==&gt; a/
+    #   a/, b/          ==&gt;
+    #   a/, a/1.0       ==&gt; a/1.0
+    #   a/1.0, a/       ==&gt; a/1.0
+    #   a/1.0, a/2.0    ==&gt;
+    #
+    #   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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 &quot;&quot;
+    set portversion &quot;&quot;
+    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 &quot;provides&quot;
+        # so we take a rather lenient view of what a &quot;portname&quot; is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder &quot;&quot;
+        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 &quot;*/*&quot; $portname]} {
+                set url &quot;file://$portname&quot;
+                set name [url_to_portname $url 1]
+                if { $name ne &quot;&quot; } {
+                    # 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 &quot;&quot;
+                    # 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 &quot;Insufficient privileges to write to MacPorts install prefix.&quot;
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder &quot;&quot;} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion &quot;&quot;
+    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 &quot;&quot; || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq &quot;&quot;} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime &amp;&amp; [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first &quot;/&quot; $opt]
+            if {$sepPos &gt;= 0} {
+                # Version terminated by &quot;/&quot; 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 &quot;+&quot;, or else is complete
+                set sepPos [string first &quot;+&quot; $opt]
+                if {$sepPos &gt;= 0} {
+                    # Version terminated by &quot;+&quot;
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt &quot;&quot;
+                }
+            }
+            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) &quot;\&quot;$val\&quot;&quot;
+                set opt &quot;&quot;
+                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 &amp;&amp; $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds &quot;&quot;
+        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 &quot; --$name&quot;
+
+                for {set i 1} {$i &lt;= $optc} {incr i} {
+                    append cmds &quot; &lt;arg$i&gt;&quot;
+                }
+            }
+        }
+        set args &quot;&quot;
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;arguments&gt;&quot;
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;portlist&gt;&quot;
+        }
+
+        set ret &quot;Usage: &quot;
+        set len [string length $action]
+        append ret [wrap &quot;$action$cmds$args&quot; 0 [string repeat &quot; &quot; [expr {8 + $len}]] 0]
+        append ret &quot;\n&quot;
+
+        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 &quot;No usage for topic $topic&quot;
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile &quot;$macports::prefix/var/macports/port-help.tcl&quot;
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr &quot;Error reading helpfile $helpfile: $err&quot;
+            return 1
+        }
+    } else {
+        puts stderr &quot;Unable to open help file $helpfile&quot;
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr &quot;No help for topic $topic&quot;
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error &quot;No usage for topic $topic&quot;
+            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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 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 &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] &quot;main.log&quot;]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue &quot;Could not open file $logfile: $result&quot; 1 status
+            }
+            set data [read $fp]
+            set data [split $data &quot;\n&quot;]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase &quot;\[a-z\]*&quot;
+            }
+
+            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 &quot;&quot;
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] &quot;|&quot;]
+                }
+            } else {
+                set prefix &quot;\[a-z\]*&quot;
+            }
+            foreach line $data {
+                set exp &quot;^:($prefix|any):($phase|any) (.*)$&quot;
+                if {[regexp $exp $line -&gt; lpriority lphase lmsg] == 1} {
+                    puts &quot;[macports::ui_prefix_default $lpriority]$lmsg&quot;
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue &quot;Log file for port $portname not found&quot; 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator &quot;&quot;
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] &amp;&amp; $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 &quot;&quot; || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;no PortIndex entry found for $portname&quot;
+            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 &quot;
+            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
+        &quot;
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     &quot;&quot;
+            variants    Variants
+            depends_fetch &quot;Fetch Dependencies&quot;
+            depends_extract &quot;Extract Dependencies&quot;
+            depends_build &quot;Build Dependencies&quot;
+            depends_run &quot;Runtime Dependencies&quot;
+            depends_lib &quot;Library Dependencies&quot;
+            description &quot;Brief Description&quot;
+            long_description &quot;Description&quot;
+            fullname    &quot;Full Name: &quot;
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   &quot;Conflicts with&quot;
+            replaced_by &quot;Replaced by&quot;
+            subports    &quot;Sub-ports&quot;
+        }
+
+        # 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)] &amp;&amp; $options(ports_info_depends) eq &quot;yes&quot;} {
+            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 &quot;\n&quot;
+        set subfield_sep &quot;, &quot;
+        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 &quot;\t&quot;
+            set subfield_sep &quot;,&quot;
+        }
+        
+        # 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 &amp;&amp; $opt eq &quot;skip_line&quot;} {
+                lappend fields &quot;&quot;
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq &quot;heading&quot;} {
+                set inf &quot;$portinfo(name) @$portinfo(version)&quot;
+                set ropt &quot;heading&quot;
+                if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                    append inf &quot;_$portinfo(revision)&quot;
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                }
+            } elseif {$opt eq &quot;fullname&quot;} {
+                set inf &quot;$portinfo(name) @&quot;
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt &quot;fullname&quot;
+            } 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 &quot;&quot;
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label &quot;&quot;
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label &quot;$opt: &quot;
+            }
+            
+            # Format the data
+            if { $ropt eq &quot;maintainers&quot; } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq &quot;variants&quot;} {
+                    # 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 &quot;&quot;
+                        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 &quot;($global_variations($v))&quot;
+                            # 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 &quot;\[$variant(is_default)]&quot;
+                            }
+                        }
+                        lappend inf &quot;$varmodifier$v&quot;
+                    }
+                } elseif {[string match &quot;depend*&quot; $ropt] 
+                          &amp;&amp; ![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 &quot;heading&quot; || $ropt eq &quot;fullname&quot;} {
+                    puts &quot;$label$field&quot;
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq &quot;&quot;} {
+                    continue
+                }
+                if {$label eq &quot;&quot;} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat &quot; &quot; $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 &quot; &quot; $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields &quot;$label$field&quot;
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print &amp;&amp; [llength $fields_tried]} {
+                puts -nonewline &quot;$portinfo(name) has no &quot;
+                puts [join $fields_tried &quot;, &quot;]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator &quot;--\n&quot;
+        }
+    }
+    
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port location failed: $result&quot; 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 &quot;Port $portname ${version}_${revision}${variants} is installed as an image in:&quot;
+        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 &quot;&quot;} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue &quot;The lookup of '$portname' failed: $result&quot; \
+                                1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;The port '$portname' was not found&quot; 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 &quot;The URL '$porturl' could not be&quot; \
+                                       &quot;opened: $result&quot;] 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 &quot;$portname has the following notes:&quot;
+            foreach note $portnotes {
+                puts [wrap $note 0 &quot;  &quot; 1]
+            }
+        } else {
+            puts &quot;$portname has no notes.&quot;
+        }
+    }
+    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 &quot;Please specify a filename to check which port provides that file.&quot;
+        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 &quot;link&quot;} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts &quot;$file is provided by: $port&quot;
+                } else {
+                    puts &quot;$file is not provided by a MacPorts port.&quot;
+                }
+            } else {
+                puts &quot;$file is a directory.&quot;
+            }
+        } else {
+            puts &quot;$file does not exist.&quot;
+        }
+    }
+    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)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port activate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping activate $portname (dry run)&quot;
+        }
+    }
+    
+    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)]
+            &amp;&amp; ![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 &quot;&quot; || $composite_version == &quot;${iversion}_${irevision}${ivariants}&quot;} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port deactivate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping deactivate $portname (dry run)&quot;
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug &quot;action_select \[$portlist] \[$opts]...&quot;
+
+    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] &lt; 1 &amp;&amp; [string map {ports_select_ &quot;&quot;} [lindex $commands 0]] != &quot;summary&quot;} {
+        ui_error &quot;port select \[--list|--set|--show|--summary] \&lt;group&gt; \[&lt;version&gt;]&quot;
+        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] &lt; 1 &amp;&amp; [llength $portlist] &gt; 1} {
+        set command set
+        ui_debug [concat &quot;Although no command was specified, more than &quot; \
+                         &quot;one argument was specified.  Defaulting to the &quot; \
+                         &quot;'set' command...&quot;]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] &lt; 1} {
+        set command list
+        ui_debug [concat &quot;No command was specified. Defaulting to the &quot; \
+                         &quot;'list' command...&quot;]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] &gt; 1} {
+        ui_error [concat &quot;Multiple commands were specified. Only one &quot; \
+                         &quot;command may be specified at a time.&quot;]
+        return 1
+    } else {
+        set command [string map {ports_select_ &quot;&quot;} [lindex $commands 0]]
+        ui_debug &quot;The '$command' command was specified.&quot;
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'list' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn &quot;Unable to get active selected version: $selected_version&quot;
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error &quot;The 'list' command failed: $versions&quot;
+                return 1
+            }
+
+            ui_notice &quot;Available versions for $group:&quot;
+            foreach v $versions {
+                ui_notice -nonewline &quot;\t&quot;
+                if {$selected_version == $v} {
+                    ui_msg &quot;$v (active)&quot;
+                } else {
+                    ui_msg &quot;$v&quot;
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] &lt; 2} {
+                ui_error [concat &quot;The 'set' command expects two &quot; \
+                                 &quot;arguments: &lt;group&gt;, &lt;version&gt;&quot;]
+                return 1
+            } elseif {[llength $portlist] &gt; 2} {
+                ui_warn [concat &quot;The 'set' command only expects two &quot; \
+                                &quot;arguments. Extra arguments will be &quot; \
+                                &quot;ignored.&quot;]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline &quot;Selecting '$version' for '$group' &quot;
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg &quot;failed: $result&quot;
+                return 1
+            }
+            ui_msg &quot;succeeded. '$version' is now active.&quot;
+            return 0
+        }
+        show {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'show' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error &quot;The 'show' command failed: $selected_version&quot;
+                return 1
+            }
+            puts [concat &quot;The currently selected version for '$group' is &quot; \
+                         &quot;'$selected_version'.&quot;]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] &gt; 0} {
+                ui_warn [concat &quot;The 'summary' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error &quot;The 'summary' command failed: $portgroups&quot;
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr &quot;%-*s  %-*s  %s&quot;
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn &quot;The list of options for the select group $pg could not be obtained: $versions&quot;
+                    continue
+                }
+                # remove &quot;none&quot;, sort the list, append none at the end
+                set noneidx [lsearch -exact $versions &quot;none&quot;]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions &quot;none&quot;
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn &quot;The currently selected option for the select group $pg could not be obtained: $selected_version&quot;
+                    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 &quot;Name&quot; $w2 &quot;Selected&quot; &quot;Options&quot;]
+            puts [format $formatStr $w1 &quot;====&quot; $w2 &quot;========&quot; &quot;=======&quot;]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) &quot; &quot;]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error &quot;An unknown command '$command' was specified.&quot;
+            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 &quot;$errorInfo&quot;
+        ui_error &quot;$result&quot;
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg &quot;Please run `port -v selfupdate' for details.&quot;
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal &quot;port selfupdate failed: $result&quot;
+    }
+    
+    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 &quot;setrequested&quot;]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info &quot;Setting requested flag for $portname to $val&quot;
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist &quot;yes&quot;] || ([prefix_unwritable] &amp;&amp; ![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 &quot;port:$portname&quot; [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 &amp;&amp; $status != 2 &amp;&amp; $status != 3 &amp;&amp; ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 &amp;&amp; $status != 2 &amp;&amp; $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] &amp;&amp; ${macports::revupgrade_autorun} &amp;&amp; ![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 &quot;Version: &quot;
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline &quot;Platform: &quot;
+    }
+    puts &quot;${macports::os_platform} ${macports::os_major} ${macports::os_arch}&quot;
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 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] &gt; 0 } {
+            if {$action eq &quot;rdependents&quot;} {
+                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] &gt; 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice &quot;The following ports are dependent on ${portname}:&quot;
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos &gt;= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] &lt;= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] &amp;&amp; [string is true -strict $options(ports_rdependents_full)])} {
+                        puts &quot;${spaces}${cur_portname}&quot;
+                        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 &quot;$depport&quot;
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg &quot;$depport depends on $portname&quot;
+                    } else {
+                        ui_msg &quot;$depport depends on $portname (by [lindex $dep 1]:)&quot;
+                    }
+                }
+            }
+        } else {
+            ui_notice &quot;$portname has no dependents.&quot;
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator &quot;&quot;
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] &amp;&amp; [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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn &quot;port ${action} --index does not work with the 'current' pseudo-port&quot;
+            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 &quot;rdeps&quot; || [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 &quot;deps&quot;} {
+                    set label &quot;$labeldict($type) Dependencies&quot;
+                    lappend deps_output [wraplabel $label [join $deplist &quot;, &quot;] 0 [string repeat &quot; &quot; 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 &quot;deps&quot;} {
+            if {$ndeps == 0} {
+                ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+            } else {
+                ui_notice &quot;Full Name: $portname @${version}_${revision}${variants}&quot;
+                puts [join $deps_output &quot;\n&quot;]
+            }
+            set separator &quot;--\n&quot;
+            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 &quot;$::errorInfo&quot;
+                        break_softcontinue &quot;lookup of portname $depname failed: $result&quot; 1 status
+                    }
+                    if {[llength $result] &lt; 2} {
+                        break_softcontinue &quot;Port $depname not found&quot; 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)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug &quot;$::errorInfo&quot;
+                            break_softcontinue &quot;Unable to open port: $result&quot; 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] &gt; 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] &gt; 0} {
+            ui_notice &quot;The following ports are dependencies of $portname @${version}_${revision}${variants}:&quot;
+        } else {
+            ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos &gt;= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] &lt;= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] &amp;&amp; [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts &quot;${spaces}${cur_port}&quot;
+                } else {
+                    puts &quot;${spaces}${cur_portname}&quot;
+                }
+                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 &quot;--\n&quot;
+    }
+    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 &quot;$portname is not installed&quot;
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn &quot;no such port: $portname, skipping uninstall&quot;
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port uninstall failed: $result&quot; 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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port installed failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] &gt; 0 } {
+        ui_notice &quot;The following ports are currently installed:&quot;
+        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 &quot;&quot;
+            set nvariants &quot;&quot;
+            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 &quot;&quot;
+                }
+                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 &amp;&amp; $os_platform ne &quot;&quot; &amp;&amp; $os_major != 0 &amp;&amp; $os_major ne &quot;&quot;} {
+                    append extra &quot; platform='$os_platform $os_major'&quot;
+                }
+                if {$archs != 0 &amp;&amp; $archs ne &quot;&quot;} {
+                    append extra &quot; archs='$archs'&quot;
+                }
+            }
+            if { $iactive == 0 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}&quot;
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are installed.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+
+    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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port outdated failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] &gt; 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 &quot;${installed_version}_${installed_revision}&quot;
+
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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 &quot;$portname has no version field&quot;
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot;
+            if {$epoch_comp_result != 0 &amp;&amp; $installed_version != $latest_version} {
+                if {($comp_result &gt;= 0 &amp;&amp; $epoch_comp_result &lt; 0) || ($comp_result &lt;= 0 &amp;&amp; $epoch_comp_result &gt; 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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &quot;&quot;
+                if { $comp_result &gt; 0 } {
+                    set relation &quot;&gt;&quot;
+                    set flag &quot;!&quot;
+                } else {
+                    set relation &quot;&lt;&quot;
+                }
+                
+                # Emit information
+                if {$comp_result &lt; 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice &quot;The following installed ports are outdated:&quot;
+                    }
+                    incr num_outdated
+
+                    puts [format &quot;%-30s %-24s %1s&quot; $portname &quot;$installed_compound $relation $latest_compound [subst $reason]&quot; $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice &quot;No installed ports are outdated.&quot;
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are outdated.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+    
+    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 &quot;%12s $file&quot; [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] &gt; 0 } {
+                ui_notice &quot;Port $portname contains:&quot;
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice &quot;Port $portname does not contain any files or is not active.&quot;
+            }
+        } else {
+            ui_notice &quot;Port $portname is not installed.&quot;
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq &quot;K&quot; || $units eq &quot;Ki&quot;} {
+        return &quot;KiB&quot;
+    } elseif {$units eq &quot;k&quot;} {
+        return &quot;kB&quot;
+    } elseif {$units eq &quot;Mi&quot;} {
+        return &quot;MiB&quot;
+    } elseif {$units eq &quot;M&quot;} {
+        return &quot;MB&quot;
+    } elseif {$units eq &quot;Gi&quot;} {
+        return &quot;GiB&quot;
+    } elseif {$units eq &quot;G&quot;} {
+        return &quot;GB&quot;
+    } 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] &gt; 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne &quot;yes&quot;} {
+                    set msg &quot;[bytesize $space $units] $portname&quot;
+                    if { $portversion != {} } {
+                        append msg &quot; @$portversion&quot;
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr &quot;Port $portname does not contain any file or is not active.&quot;
+            }
+        } else {
+            puts stderr &quot;Port $portname is not installed.&quot;
+        }
+    }
+    if {[llength $portlist] &gt; 1 || ([info exists options(ports_space_total)] &amp;&amp; $options(ports_space_total) eq &quot;yes&quot;)} {
+        puts &quot;[bytesize $spaceall $units] total&quot;
+    }
+    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 &quot;&quot;} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] &amp;&amp; $options(ports_variants_index) eq &quot;yes&quot;)} {
+            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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;port variants --index does not work with 'current' pseudo-port&quot;
+            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 &quot;$portname has no variants&quot;
+        } 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 &quot;$portname has the variants:&quot;
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier &quot;   &quot;
+                # 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 &quot;  $variations($v)&quot;
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier &quot;($global_variations($v))&quot;
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier &quot;\[$variant(is_default)\]&quot;
+                    }
+                    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 &quot;$varmodifier$v&quot; [string trim $vdescription] 0 [string repeat &quot; &quot; [expr 5 + [string length $v]]]]
+                } else {
+                    puts &quot;$varmodifier$v&quot;
+                }
+                if {[info exists vconflicts]} {
+                    puts &quot;     * conflicts with [string trim $vconflicts]&quot;
+                }
+                if {[info exists vrequires]} {
+                    puts &quot;     * requires [string trim $vrequires]&quot;
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        ui_error &quot;You must specify a search pattern&quot;
+        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)] &amp;&amp; $options(ports_search_depends) eq &quot;yes&quot;} {
+        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 &quot;none&quot;
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne &quot;yes&quot; } {
+            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) &quot;yes&quot;
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) &quot;yes&quot;
+        set filters(description) &quot;yes&quot;
+    }
+
+    set separator &quot;&quot;
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq &quot;none&quot;} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first &quot;*&quot; $portname] == -1 &amp;&amp; [string first &quot;?&quot; $portname] == -1} {
+                set searchstring &quot;*$portname*&quot;
+            }
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for name $portname failed: $result&quot; 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 &quot;&quot;
+        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 &quot;Invalid port entry, missing portname&quot;
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing description&quot;
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing version&quot;
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        &amp;&amp; $options(ports_search_line) eq &quot;yes&quot;} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)&quot;
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)&quot;
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline &quot;$portinfo(name) @$portinfo(version)&quot;
+                    if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                        puts -nonewline &quot;_$portinfo(revision)&quot;
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                    }
+                    puts &quot;&quot;
+                    puts [wrap [join $portinfo(description)] 0 [string repeat &quot; &quot; 4]]
+                }
+            }
+
+            set joiner &quot;\n&quot;
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice &quot;No match for $portname found&quot;
+        } elseif {[llength $res] &gt; 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne &quot;yes&quot;)} {
+                ui_notice &quot;\nFound [llength $res] ports.&quot;
+            }
+        }
+
+        set separator &quot;--\n&quot;
+    }
+
+    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] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        add_to_portlist portlist [list name &quot;-all-&quot;]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq &quot;-all-&quot;} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;listing all ports failed: $result&quot; 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $search_string failed: $result&quot; 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir &quot;&quot;
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format &quot;%-30s @%-14s %s&quot; $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 &quot;$key=$value&quot;
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne &quot;&quot; } {
+                set ver_field &quot;@$composite_version&quot;
+            } else {
+                set ver_field &quot;&quot;
+            }
+            puts [format &quot;%-30s %s %s&quot; $portname $ver_field  [join $opts &quot; &quot;]]
+        } else {
+            puts &quot;$portname&quot;
+        }
+    }
+
+    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 &quot;&quot;} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://${portdir}&quot;;    # Rebuild url so it's fully qualified
+        set portfile &quot;${portdir}/Portfile&quot;
+        
+        # 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 &quot;10.5&quot;} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor &quot;&quot;
+                    set editor_var &quot;ports_${action}_editor&quot;
+                    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 &quot;&quot; } { set editor &quot;/usr/bin/vi&quot; }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec &gt;@stdout &lt;@stdin 2&gt;@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug &quot;$errorInfo&quot;
+                        break_softcontinue &quot;unable to invoke editor $editor: $result&quot; 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq &quot;10.5&quot;} {
+                        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] &quot;main.log&quot;]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error &quot;Log file not found for port in $portdir&quot;
+                    }
+                }
+
+                gohome {
+                    set homepage &quot;&quot;
+
+                    # 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 &quot;&quot; &amp;&amp; ![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 &quot;&quot; } {
+                        if {[catch {system &quot;${macports::autoconf::open_path} '$homepage'&quot;} result]} {
+                            global errorInfo
+                            ui_debug &quot;$errorInfo&quot;
+                            break_softcontinue &quot;unable to invoke browser using ${macports::autoconf::open_path}: $result&quot; 1 status
+                        }
+                    } else {
+                        ui_error [format &quot;No homepage for %s&quot; $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue &quot;Could not read $portfile&quot; 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 &quot;$errorInfo&quot;
+        ui_msg &quot;port sync failed: $result&quot;
+        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 &quot;install&quot; || $action eq &quot;archive&quot;) &amp;&amp; [prefix_unwritable] &amp;&amp; ![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 &quot;&quot;} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn &quot;Skipping $portname (not in the ports tree)&quot;
+                    continue
+                } else {
+                    break_softcontinue &quot;Port $portname not found&quot; 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 &quot;&quot; &amp;&amp; [array get variations] ne &quot;&quot;} {
+            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 &quot;install&quot;} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq &quot;archive&quot;} {
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to execute port: $result&quot; 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue &quot;Processing of port $portname failed&quot; 1 status
+        }
+    }
+    
+    if {$status == 0 &amp;&amp; $action eq &quot;install&quot; &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] &amp;&amp; ![info exists options(ports_install_no-rev-upgrade)] &amp;&amp; ${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 &lt; $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn &lt; $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 &quot;action&quot;.
+# 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 &quot;&quot;
+    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 &quot;&quot;
+    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 &quot;-&quot;} {
+            break
+        } elseif {[string index $arg 1] eq &quot;-&quot;} {
+            # 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 &quot;${action} does not accept --${key}&quot;
+                    } elseif {[llength $kopts] &gt; 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst &quot;--[lindex $e 0]&quot;
+                        }
+                        return -code error &quot;\&quot;port ${action} --${key}\&quot; is ambiguous: \n  port ${action} [join $errlst &quot;\n  port ${action} &quot;]&quot;
+                    }
+                    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] &amp;&amp; $kargc &gt; 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc &gt; 0} {
+                            return -code error &quot;--${key} expects [expr {$kargc + [llength $args]}] parameters!&quot;
+                        }
+                        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]) &amp;&amp; [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == &quot;;&quot; } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == &quot;#&quot; } {
+            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] &gt; 1} {
+                ui_error &quot;\&quot;port ${action}\&quot; is ambiguous: \n  port [join $actions &quot;\n  port &quot;]&quot;
+            } else {
+                ui_error &quot;Unrecognized action \&quot;port $action\&quot;&quot;
+            }
+            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 &quot;$errorInfo&quot;
+            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 &quot;$action does not accept string arguments&quot;
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] &amp;&amp; ![match &quot;;&quot;] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error &quot;Improper expression syntax while processing parameters&quot;
+                        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 &quot;${text}*&quot; false glob]} result]} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;search for portname $pattern failed: $result&quot;
+        }
+        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 &quot;[string tolower $text]*&quot;]
+    }
+
+    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 &quot;[string tolower $text]*&quot;]
+
+    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 &quot;&quot;
+    }
+
+    # 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 &quot;&quot;
+    while { $line eq &quot;&quot; } {
+
+        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 &lt; 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline &amp;&amp; $line ne &quot;&quot; } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in &quot;stdin&quot;]
+    set name &quot;port&quot;
+    set use_readline [expr {$isstdin &amp;&amp; [readline init $name]}]
+    set history_file [file normalize &quot;${macports::macports_user_dir}/history&quot;]
+
+    # Read readline history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin &amp;&amp; ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts &quot;MacPorts [macports::version]&quot;
+        puts &quot;Entering interactive mode... (\&quot;help\&quot; for help, \&quot;quit\&quot; to quit)&quot;
+    }
+
+    # 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 &quot;\[$shortdir\] &gt; &quot;
+        } else {
+            set prompt &quot;&quot;
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] &lt;= 0  } {
+            puts &quot;&quot;
+            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 &amp;&amp; ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts &quot;Goodbye&quot;
+    }
+
+    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 &quot;-&quot;} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal &quot;Failed to open command file; $result&quot;
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne &quot;stdin&quot;} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 &amp;&amp; ![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
+    #        &quot;yes&quot;, if the progress indicator should be shown, &quot;no&quot; otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq &quot;yes&quot;} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] &gt; $showTimeThreshold &amp;&amp;
+                ($total == 0 || [expr {double($cur) / double($total)}] &lt; $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot;, &quot;intermission&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        &quot;intermission&quot; and &quot;finish&quot;, the args are empty and unused. For
+    #        &quot;update&quot;, 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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        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 &quot;\r&quot;
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        contains a single argument &quot;ul&quot; or &quot;dl&quot; indicating whether this is
+    #        an up- or download. For &quot;update&quot;, contains the arguments
+    #        (&quot;ul&quot;|&quot;dl&quot;) $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 &quot;finish&quot;.
+    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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format &quot;        speed: %-13s&quot; &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format &quot; %-10s     speed: %-13s&quot; [bytesize $now {} &quot;%6.1f&quot;] &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            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 &quot;\r&quot;
+                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 &quot;&quot;} {suffix &quot;&quot;}} {
+        # 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 &quot;\033\[7m&quot;
+        for {set i 0} {$i &lt; $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 &quot; &quot;
+        }
+        # back to normal output
+        append progressbar &quot;\033\[0m&quot;
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger &lt; $barWidth} {
+        #            append progressbar &quot; &quot;
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar &quot;\u258f&quot;
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar &quot;\u258e&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar &quot;\u258c&quot;
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258b&quot;
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar &quot;\u258a&quot;
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar &quot;\u2589&quot;
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i &lt; $barWidth} {incr i} {
+            append progressbar &quot; &quot;
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format &quot; %[expr {$percentageWidth - 3}].1f %%&quot; $percentage]
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}&quot;
+        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 &quot;&quot;} {suffix &quot;&quot;}} {
+        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 &quot;&quot;
+        for {set i 0} {$i &lt; $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar &quot;\u2022&quot;
+            } else {
+                append progressbar &quot; &quot;
+            }
+        }
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${suffix}&quot;
+        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] &gt; 0} {
+            ui_notice &quot;---&gt;  Some of the ports you installed have notes:&quot;
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice &quot;  $name has the following notes:&quot;
+
+                # 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 &quot;\n&quot;] {
+                            set joiner &quot;&quot;
+                            set lines &quot;&quot;
+                            set newline &quot;    &quot;
+
+                            foreach word [split $line &quot; &quot;] {
+                                if {[string length $newline] + [string length $word] &gt;= $maxlen} {
+                                    lappend lines $newline
+                                    set newline &quot;    &quot;
+                                    set joiner &quot;&quot;
+                                }
+                                ::append newline $joiner $word
+                                set joiner &quot; &quot;
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines &quot;\n&quot;]
+                        }
+                    }
+                } 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] &amp;&amp; $cmdname eq &quot;portf&quot;} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options &quot;global&quot; ui_options global_options} result]} {
+    puts &quot;Error: $result&quot;
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    &amp;&amp; $portclient::progress::hasTermAnsiSend eq &quot;yes&quot;
+    &amp;&amp; (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne &quot;yes&quot;)} {
+    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 &amp;&amp; ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq &quot;selfupdate&quot; || [lookahead] eq &quot;sync&quot;} {
+    # 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 &quot;$errorInfo&quot;
+    fatal &quot;Failed to initialize MacPorts, $result&quot;
+}
+
+# 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] &gt; 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]) &amp;&amp; [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
</ins></span></pre></div>
<a id="branchesgsoc14cleanupsrcportportREMOTE23878"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/port/port.REMOTE.23878 (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,5355 @@
</span><ins>+#!/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@macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw &lt;rshaw@opendarwin.org&gt;
+# 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 &quot;AS IS&quot;
+# 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. &quot;yes&quot;, if the package is available, &quot;no&quot; 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 &quot;Usage: $cmdname$syntax&quot;
+        puts stderr &quot;\&quot;$cmdname help\&quot; or \&quot;man 1 port\&quot; for more information.&quot;
+    } else {
+        puts stderr &quot;$cmdname$syntax&quot;
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds &quot;&quot;
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen &gt; 65} {
+            set cmds &quot;$cmds,\n&quot;
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new &quot;$cmd&quot;
+        } else {
+            set new &quot;, $cmd&quot;
+        }
+        incr lineLen [string length $new]
+        set cmds &quot;$cmds$new&quot;
+    }
+
+    set cmdText &quot;Supported actions
+------------------
+$cmds
+&quot;
+
+    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 &quot;$cmdText$text&quot;
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error &quot;$argv0: $s&quot;
+    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 &gt; 0x40000000} {
+            set unit &quot;GiB&quot;
+        } elseif {$siz &gt; 0x100000} {
+            set unit &quot;MiB&quot;
+        } elseif {$siz &gt; 0x400} {
+            set unit &quot;KiB&quot;
+        } else {
+            set unit &quot;B&quot;
+        }
+    }
+    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 &quot;Unknown file size unit '$unit' specified&quot;
+            set unit &quot;B&quot;
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return &quot;$siz $unit&quot;
+}
+
+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 &quot;/usr/local&quot; &amp;&amp; ${macports::prefix} ne &quot;/usr&quot;} {
+        ui_error &quot;Follow http://guide.macports.org/#project.tickets to report a bug.&quot;
+    }
+}
+
+# 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 &quot;+&quot;} {
+            lappend pos $key
+        } elseif {$val eq &quot;-&quot;} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version &quot;&quot;
+    if {$version ne &quot;&quot; || $emptyVersionOkay} {
+        set pos_str &quot;&quot;
+        set neg_str &quot;&quot;
+
+        if {[llength $pos]} {
+            set pos_str &quot;+[join [lsort -ascii $pos] &quot;+&quot;]&quot;
+        }
+        if {[llength $neg]} {
+            set neg_str &quot;-[join [lsort -ascii $neg] &quot;-&quot;]&quot;
+        }
+
+        set composite_version &quot;$version$pos_str$neg_str&quot;
+    }
+
+    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 &quot;${field}s&quot;
+        }
+        category {
+            set field &quot;categories&quot;
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion &quot;&quot;}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] &gt; 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 &quot;The following versions of $portname are currently installed:&quot;
+        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 &quot;  $iname @${iversion}_${irevision}${ivariants}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants} (active)&quot;
+            }
+        }
+        return -code error &quot;Registry error: Please specify the full version as recorded in the port registry.&quot;
+    } 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=&gt;+-)
+    #   requested_variants array  (variant=&gt;+-)
+    #   options array   (key=&gt;value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) &quot;&quot; }
+    if {![info exists port(name)]}      { set port(name) &quot;&quot; }
+    if {![info exists port(version)]}   { set port(version) &quot;&quot; }
+    if {![info exists port(variants)]}  { set port(variants) &quot;&quot; }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) &quot;&quot; }
+    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 &quot;&quot; &amp;&amp; $port(name) eq &quot;&quot; } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq &quot;&quot;} {
+            ui_error &quot;A default port name could not be supplied.&quot;
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) &quot;$port(name)/[composite_version $port(version) $port(variants)]&quot;
+    
+    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 &quot;&quot;}} {
+    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 &quot;&quot;
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg &quot;Can't map the URL '$url' to a port description file (\&quot;${result}\&quot;).&quot;
+            ui_msg &quot;Please verify that the directory and portfile syntax are correct.&quot;
+        }
+    } 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 &quot;no&quot;} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 &amp;&amp; (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq &quot;no&quot;)} {
+        if {${is_upgrade} == &quot;yes&quot;} {
+            # $&gt; port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # &quot;upgrade&quot;, let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg &quot;Nothing to upgrade.&quot;
+            return 1
+        }
+        ui_error &quot;No ports matched the given expression&quot;
+        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 &quot;array unset portspec; array set portspec { $portspec }&quot;
+        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) &quot;_&quot;]
+    set bvr_ [split $b_(version) &quot;_&quot;]
+    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_ &lt; $br_} {
+        return -1
+    } elseif {$ar_ &gt; $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name@version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list &quot;name&quot; [lindex $a 0] &quot;version&quot; &quot;[lindex $a 1]_[lindex $a 2]&quot;]
+    array set b_ [list &quot;name&quot; [lindex $b 0] &quot;version&quot; &quot;[lindex $b 1]_[lindex $b 2]&quot;]
+    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 {\\&amp;}]
+    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)] &amp;&amp; [lindex $size 0] &gt; 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] &amp;&amp; [lindex $size 1] &gt; 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 &quot;&quot;} {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 &quot;\n&quot;] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;} {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 &quot; &quot;]
+    if {$indentfirstline == 0} {
+        set newline &quot;&quot;
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner &quot; &quot;
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] &gt;= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner &quot;&quot;
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 &amp;&amp; $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner &quot; &quot;
+    }
+    lappend lines $newline
+    return [join $lines &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;}} {
+    append label &quot;: [string repeat &quot; &quot; [expr {[string length $indent] - [string length &quot;$label: &quot;]}]]&quot;
+    return &quot;$label[wrap $string $maxlen $indent 0]&quot;
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first &quot;@&quot; $m] &lt; 0} {
+            if {[string first &quot;:&quot; $m] &gt;= 0} {
+                set m [regsub -- &quot;(.*):(.*)&quot; $m &quot;\\2@\\1&quot;] 
+            } else {
+                set m &quot;$m@macports.org&quot;
+            }
+        }
+        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 &quot;$errorInfo&quot;
+        fatal &quot;search for portname $pattern failed: $result&quot;
+    }
+    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 &quot;$errorInfo&quot;
+            fatal &quot;listing all ports failed: $result&quot;
+        }
+        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 &quot;&quot;} {
+        ui_msg &quot;To use the current port, you must be in a port's directory.&quot;
+        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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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} == &quot;yes&quot; || (${active} == &quot;yes&quot;) == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] &gt; 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  &quot;${installed_version}_${installed_revision}&quot;
+            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 &quot;$errorInfo&quot;
+                fatal &quot;lookup of portname $portname failed: $result&quot;
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &lt; 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 &quot;$::errorInfo&quot;
+            break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+        }
+
+        if {[llength $result] &lt; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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 &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq &quot;&quot;} {
+            add_to_portlist results [list name $iname version &quot;[lindex $i 1]_[lindex $i 2]&quot; 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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+                        return -code error &quot;lookup of portname $depname failed: $result&quot;
+                    }
+                    if {[llength $result] &lt; 2} {
+                        ui_error &quot;Port $depname not found&quot;
+                        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 &quot;$::errorInfo&quot;
+                        ui_error &quot;Unable to open port: $result&quot;
+                        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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;&quot;
+    set name &quot;&quot;
+    set version &quot;&quot;
+    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 &quot;)&quot;]} {
+                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 &quot;depends_lib&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_build&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_run&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_extract&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_fetch&quot;]
+
+            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 &quot;rdependentof&quot;]
+            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 &quot;rdepof&quot;]
+            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 &quot;&quot;} {
+                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 &quot;Can't open URL '$token' as a port&quot;
+                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 &quot;&quot;} } {
+    upvar $resname reslist
+    
+    set version &quot;&quot;
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne &quot;&quot;} { 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/          ==&gt; a/
+    #   a/, b/          ==&gt;
+    #   a/, a/1.0       ==&gt; a/1.0
+    #   a/1.0, a/       ==&gt; a/1.0
+    #   a/1.0, a/2.0    ==&gt;
+    #
+    #   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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 &quot;&quot;
+    set portversion &quot;&quot;
+    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 &quot;provides&quot;
+        # so we take a rather lenient view of what a &quot;portname&quot; is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder &quot;&quot;
+        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 &quot;*/*&quot; $portname]} {
+                set url &quot;file://$portname&quot;
+                set name [url_to_portname $url 1]
+                if { $name ne &quot;&quot; } {
+                    # 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 &quot;&quot;
+                    # 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 &quot;Insufficient privileges to write to MacPorts install prefix.&quot;
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder &quot;&quot;} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion &quot;&quot;
+    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 &quot;&quot; || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq &quot;&quot;} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime &amp;&amp; [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first &quot;/&quot; $opt]
+            if {$sepPos &gt;= 0} {
+                # Version terminated by &quot;/&quot; 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 &quot;+&quot;, or else is complete
+                set sepPos [string first &quot;+&quot; $opt]
+                if {$sepPos &gt;= 0} {
+                    # Version terminated by &quot;+&quot;
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt &quot;&quot;
+                }
+            }
+            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) &quot;\&quot;$val\&quot;&quot;
+                set opt &quot;&quot;
+                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 &amp;&amp; $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds &quot;&quot;
+        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 &quot; --$name&quot;
+
+                for {set i 1} {$i &lt;= $optc} {incr i} {
+                    append cmds &quot; &lt;arg$i&gt;&quot;
+                }
+            }
+        }
+        set args &quot;&quot;
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;arguments&gt;&quot;
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;portlist&gt;&quot;
+        }
+
+        set ret &quot;Usage: &quot;
+        set len [string length $action]
+        append ret [wrap &quot;$action$cmds$args&quot; 0 [string repeat &quot; &quot; [expr {8 + $len}]] 0]
+        append ret &quot;\n&quot;
+
+        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 &quot;No usage for topic $topic&quot;
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile &quot;$macports::prefix/var/macports/port-help.tcl&quot;
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr &quot;Error reading helpfile $helpfile: $err&quot;
+            return 1
+        }
+    } else {
+        puts stderr &quot;Unable to open help file $helpfile&quot;
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr &quot;No help for topic $topic&quot;
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error &quot;No usage for topic $topic&quot;
+            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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 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 &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] &quot;main.log&quot;]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue &quot;Could not open file $logfile: $result&quot; 1 status
+            }
+            set data [read $fp]
+            set data [split $data &quot;\n&quot;]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase &quot;\[a-z\]*&quot;
+            }
+
+            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 &quot;&quot;
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] &quot;|&quot;]
+                }
+            } else {
+                set prefix &quot;\[a-z\]*&quot;
+            }
+            foreach line $data {
+                set exp &quot;^:($prefix|any):($phase|any) (.*)$&quot;
+                if {[regexp $exp $line -&gt; lpriority lphase lmsg] == 1} {
+                    puts &quot;[macports::ui_prefix_default $lpriority]$lmsg&quot;
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue &quot;Log file for port $portname not found&quot; 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator &quot;&quot;
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] &amp;&amp; $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 &quot;&quot; || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;no PortIndex entry found for $portname&quot;
+            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 &quot;
+            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
+        &quot;
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     &quot;&quot;
+            variants    Variants
+            depends_fetch &quot;Fetch Dependencies&quot;
+            depends_extract &quot;Extract Dependencies&quot;
+            depends_build &quot;Build Dependencies&quot;
+            depends_run &quot;Runtime Dependencies&quot;
+            depends_lib &quot;Library Dependencies&quot;
+            description &quot;Brief Description&quot;
+            long_description &quot;Description&quot;
+            fullname    &quot;Full Name: &quot;
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   &quot;Conflicts with&quot;
+            replaced_by &quot;Replaced by&quot;
+            subports    &quot;Sub-ports&quot;
+        }
+
+        # 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)] &amp;&amp; $options(ports_info_depends) eq &quot;yes&quot;} {
+            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 &quot;\n&quot;
+        set subfield_sep &quot;, &quot;
+        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 &quot;\t&quot;
+            set subfield_sep &quot;,&quot;
+        }
+        
+        # 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 &amp;&amp; $opt eq &quot;skip_line&quot;} {
+                lappend fields &quot;&quot;
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq &quot;heading&quot;} {
+                set inf &quot;$portinfo(name) @$portinfo(version)&quot;
+                set ropt &quot;heading&quot;
+                if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                    append inf &quot;_$portinfo(revision)&quot;
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                }
+            } elseif {$opt eq &quot;fullname&quot;} {
+                set inf &quot;$portinfo(name) @&quot;
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt &quot;fullname&quot;
+            } 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 &quot;&quot;
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label &quot;&quot;
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label &quot;$opt: &quot;
+            }
+            
+            # Format the data
+            if { $ropt eq &quot;maintainers&quot; } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq &quot;variants&quot;} {
+                    # 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 &quot;&quot;
+                        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 &quot;($global_variations($v))&quot;
+                            # 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 &quot;\[$variant(is_default)]&quot;
+                            }
+                        }
+                        lappend inf &quot;$varmodifier$v&quot;
+                    }
+                } elseif {[string match &quot;depend*&quot; $ropt] 
+                          &amp;&amp; ![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 &quot;heading&quot; || $ropt eq &quot;fullname&quot;} {
+                    puts &quot;$label$field&quot;
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq &quot;&quot;} {
+                    continue
+                }
+                if {$label eq &quot;&quot;} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat &quot; &quot; $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 &quot; &quot; $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields &quot;$label$field&quot;
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print &amp;&amp; [llength $fields_tried]} {
+                puts -nonewline &quot;$portinfo(name) has no &quot;
+                puts [join $fields_tried &quot;, &quot;]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator &quot;--\n&quot;
+        }
+    }
+    
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port location failed: $result&quot; 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 &quot;Port $portname ${version}_${revision}${variants} is installed as an image in:&quot;
+        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 &quot;&quot;} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue &quot;The lookup of '$portname' failed: $result&quot; \
+                                1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;The port '$portname' was not found&quot; 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 &quot;The URL '$porturl' could not be&quot; \
+                                       &quot;opened: $result&quot;] 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 &quot;$portname has the following notes:&quot;
+            foreach note $portnotes {
+                puts [wrap $note 0 &quot;  &quot; 1]
+            }
+        } else {
+            puts &quot;$portname has no notes.&quot;
+        }
+    }
+    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 &quot;Please specify a filename to check which port provides that file.&quot;
+        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 &quot;link&quot;} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts &quot;$file is provided by: $port&quot;
+                } else {
+                    puts &quot;$file is not provided by a MacPorts port.&quot;
+                }
+            } else {
+                puts &quot;$file is a directory.&quot;
+            }
+        } else {
+            puts &quot;$file does not exist.&quot;
+        }
+    }
+    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)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port activate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping activate $portname (dry run)&quot;
+        }
+    }
+    
+    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)]
+            &amp;&amp; ![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 &quot;&quot; || $composite_version == &quot;${iversion}_${irevision}${ivariants}&quot;} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port deactivate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping deactivate $portname (dry run)&quot;
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug &quot;action_select \[$portlist] \[$opts]...&quot;
+
+    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] &lt; 1 &amp;&amp; [string map {ports_select_ &quot;&quot;} [lindex $commands 0]] != &quot;summary&quot;} {
+        ui_error &quot;port select \[--list|--set|--show|--summary] \&lt;group&gt; \[&lt;version&gt;]&quot;
+        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] &lt; 1 &amp;&amp; [llength $portlist] &gt; 1} {
+        set command set
+        ui_debug [concat &quot;Although no command was specified, more than &quot; \
+                         &quot;one argument was specified.  Defaulting to the &quot; \
+                         &quot;'set' command...&quot;]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] &lt; 1} {
+        set command list
+        ui_debug [concat &quot;No command was specified. Defaulting to the &quot; \
+                         &quot;'list' command...&quot;]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] &gt; 1} {
+        ui_error [concat &quot;Multiple commands were specified. Only one &quot; \
+                         &quot;command may be specified at a time.&quot;]
+        return 1
+    } else {
+        set command [string map {ports_select_ &quot;&quot;} [lindex $commands 0]]
+        ui_debug &quot;The '$command' command was specified.&quot;
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'list' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn &quot;Unable to get active selected version: $selected_version&quot;
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error &quot;The 'list' command failed: $versions&quot;
+                return 1
+            }
+
+            ui_notice &quot;Available versions for $group:&quot;
+            foreach v $versions {
+                ui_notice -nonewline &quot;\t&quot;
+                if {$selected_version == $v} {
+                    ui_msg &quot;$v (active)&quot;
+                } else {
+                    ui_msg &quot;$v&quot;
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] &lt; 2} {
+                ui_error [concat &quot;The 'set' command expects two &quot; \
+                                 &quot;arguments: &lt;group&gt;, &lt;version&gt;&quot;]
+                return 1
+            } elseif {[llength $portlist] &gt; 2} {
+                ui_warn [concat &quot;The 'set' command only expects two &quot; \
+                                &quot;arguments. Extra arguments will be &quot; \
+                                &quot;ignored.&quot;]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline &quot;Selecting '$version' for '$group' &quot;
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg &quot;failed: $result&quot;
+                return 1
+            }
+            ui_msg &quot;succeeded. '$version' is now active.&quot;
+            return 0
+        }
+        show {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'show' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error &quot;The 'show' command failed: $selected_version&quot;
+                return 1
+            }
+            puts [concat &quot;The currently selected version for '$group' is &quot; \
+                         &quot;'$selected_version'.&quot;]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] &gt; 0} {
+                ui_warn [concat &quot;The 'summary' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error &quot;The 'summary' command failed: $portgroups&quot;
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr &quot;%-*s  %-*s  %s&quot;
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn &quot;The list of options for the select group $pg could not be obtained: $versions&quot;
+                    continue
+                }
+                # remove &quot;none&quot;, sort the list, append none at the end
+                set noneidx [lsearch -exact $versions &quot;none&quot;]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions &quot;none&quot;
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn &quot;The currently selected option for the select group $pg could not be obtained: $selected_version&quot;
+                    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 &quot;Name&quot; $w2 &quot;Selected&quot; &quot;Options&quot;]
+            puts [format $formatStr $w1 &quot;====&quot; $w2 &quot;========&quot; &quot;=======&quot;]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) &quot; &quot;]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error &quot;An unknown command '$command' was specified.&quot;
+            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 &quot;$errorInfo&quot;
+        ui_error &quot;$result&quot;
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg &quot;Please run `port -v selfupdate' for details.&quot;
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal &quot;port selfupdate failed: $result&quot;
+    }
+    
+    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 &quot;setrequested&quot;]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info &quot;Setting requested flag for $portname to $val&quot;
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist &quot;yes&quot;] || ([prefix_unwritable] &amp;&amp; ![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 &quot;port:$portname&quot; [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 &amp;&amp; $status != 2 &amp;&amp; $status != 3 &amp;&amp; ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 &amp;&amp; $status != 2 &amp;&amp; $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] &amp;&amp; ${macports::revupgrade_autorun} &amp;&amp; ![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 &quot;Version: &quot;
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline &quot;Platform: &quot;
+    }
+    puts &quot;${macports::os_platform} ${macports::os_major} ${macports::os_arch}&quot;
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 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] &gt; 0 } {
+            if {$action eq &quot;rdependents&quot;} {
+                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] &gt; 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice &quot;The following ports are dependent on ${portname}:&quot;
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos &gt;= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] &lt;= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] &amp;&amp; [string is true -strict $options(ports_rdependents_full)])} {
+                        puts &quot;${spaces}${cur_portname}&quot;
+                        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 &quot;$depport&quot;
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg &quot;$depport depends on $portname&quot;
+                    } else {
+                        ui_msg &quot;$depport depends on $portname (by [lindex $dep 1]:)&quot;
+                    }
+                }
+            }
+        } else {
+            ui_notice &quot;$portname has no dependents.&quot;
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator &quot;&quot;
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] &amp;&amp; [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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn &quot;port ${action} --index does not work with the 'current' pseudo-port&quot;
+            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 &quot;rdeps&quot; || [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 &quot;deps&quot;} {
+                    set label &quot;$labeldict($type) Dependencies&quot;
+                    lappend deps_output [wraplabel $label [join $deplist &quot;, &quot;] 0 [string repeat &quot; &quot; 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 &quot;deps&quot;} {
+            if {$ndeps == 0} {
+                ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+            } else {
+                ui_notice &quot;Full Name: $portname @${version}_${revision}${variants}&quot;
+                puts [join $deps_output &quot;\n&quot;]
+            }
+            set separator &quot;--\n&quot;
+            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 &quot;$::errorInfo&quot;
+                        break_softcontinue &quot;lookup of portname $depname failed: $result&quot; 1 status
+                    }
+                    if {[llength $result] &lt; 2} {
+                        break_softcontinue &quot;Port $depname not found&quot; 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)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug &quot;$::errorInfo&quot;
+                            break_softcontinue &quot;Unable to open port: $result&quot; 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] &gt; 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] &gt; 0} {
+            ui_notice &quot;The following ports are dependencies of $portname @${version}_${revision}${variants}:&quot;
+        } else {
+            ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos &gt;= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] &lt;= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] &amp;&amp; [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts &quot;${spaces}${cur_port}&quot;
+                } else {
+                    puts &quot;${spaces}${cur_portname}&quot;
+                }
+                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 &quot;--\n&quot;
+    }
+    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 &quot;$portname is not installed&quot;
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn &quot;no such port: $portname, skipping uninstall&quot;
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port uninstall failed: $result&quot; 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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port installed failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] &gt; 0 } {
+        ui_notice &quot;The following ports are currently installed:&quot;
+        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 &quot;&quot;
+            set nvariants &quot;&quot;
+            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 &quot;&quot;
+                }
+                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 &amp;&amp; $os_platform ne &quot;&quot; &amp;&amp; $os_major != 0 &amp;&amp; $os_major ne &quot;&quot;} {
+                    append extra &quot; platform='$os_platform $os_major'&quot;
+                }
+                if {$archs != 0 &amp;&amp; $archs ne &quot;&quot;} {
+                    append extra &quot; archs='$archs'&quot;
+                }
+            }
+            if { $iactive == 0 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}&quot;
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are installed.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+
+    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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port outdated failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] &gt; 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 &quot;${installed_version}_${installed_revision}&quot;
+
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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 &quot;$portname has no version field&quot;
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot;
+            if {$epoch_comp_result != 0 &amp;&amp; $installed_version != $latest_version} {
+                if {($comp_result &gt;= 0 &amp;&amp; $epoch_comp_result &lt; 0) || ($comp_result &lt;= 0 &amp;&amp; $epoch_comp_result &gt; 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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &quot;&quot;
+                if { $comp_result &gt; 0 } {
+                    set relation &quot;&gt;&quot;
+                    set flag &quot;!&quot;
+                } else {
+                    set relation &quot;&lt;&quot;
+                }
+                
+                # Emit information
+                if {$comp_result &lt; 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice &quot;The following installed ports are outdated:&quot;
+                    }
+                    incr num_outdated
+
+                    puts [format &quot;%-30s %-24s %1s&quot; $portname &quot;$installed_compound $relation $latest_compound [subst $reason]&quot; $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice &quot;No installed ports are outdated.&quot;
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are outdated.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+    
+    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 &quot;%12s $file&quot; [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] &gt; 0 } {
+                ui_notice &quot;Port $portname contains:&quot;
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice &quot;Port $portname does not contain any files or is not active.&quot;
+            }
+        } else {
+            ui_notice &quot;Port $portname is not installed.&quot;
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq &quot;K&quot; || $units eq &quot;Ki&quot;} {
+        return &quot;KiB&quot;
+    } elseif {$units eq &quot;k&quot;} {
+        return &quot;kB&quot;
+    } elseif {$units eq &quot;Mi&quot;} {
+        return &quot;MiB&quot;
+    } elseif {$units eq &quot;M&quot;} {
+        return &quot;MB&quot;
+    } elseif {$units eq &quot;Gi&quot;} {
+        return &quot;GiB&quot;
+    } elseif {$units eq &quot;G&quot;} {
+        return &quot;GB&quot;
+    } 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] &gt; 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne &quot;yes&quot;} {
+                    set msg &quot;[bytesize $space $units] $portname&quot;
+                    if { $portversion != {} } {
+                        append msg &quot; @$portversion&quot;
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr &quot;Port $portname does not contain any file or is not active.&quot;
+            }
+        } else {
+            puts stderr &quot;Port $portname is not installed.&quot;
+        }
+    }
+    if {[llength $portlist] &gt; 1 || ([info exists options(ports_space_total)] &amp;&amp; $options(ports_space_total) eq &quot;yes&quot;)} {
+        puts &quot;[bytesize $spaceall $units] total&quot;
+    }
+    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 &quot;&quot;} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] &amp;&amp; $options(ports_variants_index) eq &quot;yes&quot;)} {
+            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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;port variants --index does not work with 'current' pseudo-port&quot;
+            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 &quot;$portname has no variants&quot;
+        } 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 &quot;$portname has the variants:&quot;
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier &quot;   &quot;
+                # 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 &quot;  $variations($v)&quot;
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier &quot;($global_variations($v))&quot;
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier &quot;\[$variant(is_default)\]&quot;
+                    }
+                    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 &quot;$varmodifier$v&quot; [string trim $vdescription] 0 [string repeat &quot; &quot; [expr 5 + [string length $v]]]]
+                } else {
+                    puts &quot;$varmodifier$v&quot;
+                }
+                if {[info exists vconflicts]} {
+                    puts &quot;     * conflicts with [string trim $vconflicts]&quot;
+                }
+                if {[info exists vrequires]} {
+                    puts &quot;     * requires [string trim $vrequires]&quot;
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        ui_error &quot;You must specify a search pattern&quot;
+        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)] &amp;&amp; $options(ports_search_depends) eq &quot;yes&quot;} {
+        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 &quot;none&quot;
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne &quot;yes&quot; } {
+            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) &quot;yes&quot;
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) &quot;yes&quot;
+        set filters(description) &quot;yes&quot;
+    }
+
+    set separator &quot;&quot;
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq &quot;none&quot;} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first &quot;*&quot; $portname] == -1 &amp;&amp; [string first &quot;?&quot; $portname] == -1} {
+                set searchstring &quot;*$portname*&quot;
+            }
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for name $portname failed: $result&quot; 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 &quot;&quot;
+        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 &quot;Invalid port entry, missing portname&quot;
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing description&quot;
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing version&quot;
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        &amp;&amp; $options(ports_search_line) eq &quot;yes&quot;} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)&quot;
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)&quot;
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline &quot;$portinfo(name) @$portinfo(version)&quot;
+                    if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                        puts -nonewline &quot;_$portinfo(revision)&quot;
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                    }
+                    puts &quot;&quot;
+                    puts [wrap [join $portinfo(description)] 0 [string repeat &quot; &quot; 4]]
+                }
+            }
+
+            set joiner &quot;\n&quot;
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice &quot;No match for $portname found&quot;
+        } elseif {[llength $res] &gt; 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne &quot;yes&quot;)} {
+                ui_notice &quot;\nFound [llength $res] ports.&quot;
+            }
+        }
+
+        set separator &quot;--\n&quot;
+    }
+
+    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] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        add_to_portlist portlist [list name &quot;-all-&quot;]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq &quot;-all-&quot;} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;listing all ports failed: $result&quot; 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $search_string failed: $result&quot; 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir &quot;&quot;
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format &quot;%-30s @%-14s %s&quot; $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 &quot;$key=$value&quot;
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne &quot;&quot; } {
+                set ver_field &quot;@$composite_version&quot;
+            } else {
+                set ver_field &quot;&quot;
+            }
+            puts [format &quot;%-30s %s %s&quot; $portname $ver_field  [join $opts &quot; &quot;]]
+        } else {
+            puts &quot;$portname&quot;
+        }
+    }
+
+    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 &quot;&quot;} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://${portdir}&quot;;    # Rebuild url so it's fully qualified
+        set portfile &quot;${portdir}/Portfile&quot;
+        
+        # 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 &quot;10.5&quot;} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor &quot;&quot;
+                    set editor_var &quot;ports_${action}_editor&quot;
+                    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 &quot;&quot; } { set editor &quot;/usr/bin/vi&quot; }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec &gt;@stdout &lt;@stdin 2&gt;@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug &quot;$errorInfo&quot;
+                        break_softcontinue &quot;unable to invoke editor $editor: $result&quot; 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq &quot;10.5&quot;} {
+                        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] &quot;main.log&quot;]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error &quot;Log file not found for port in $portdir&quot;
+                    }
+                }
+
+                gohome {
+                    set homepage &quot;&quot;
+
+                    # 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 &quot;&quot; &amp;&amp; ![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 &quot;&quot; } {
+                        if {[catch {system &quot;${macports::autoconf::open_path} '$homepage'&quot;} result]} {
+                            global errorInfo
+                            ui_debug &quot;$errorInfo&quot;
+                            break_softcontinue &quot;unable to invoke browser using ${macports::autoconf::open_path}: $result&quot; 1 status
+                        }
+                    } else {
+                        ui_error [format &quot;No homepage for %s&quot; $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue &quot;Could not read $portfile&quot; 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 &quot;$errorInfo&quot;
+        ui_msg &quot;port sync failed: $result&quot;
+        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 &quot;install&quot; || $action eq &quot;archive&quot;) &amp;&amp; [prefix_unwritable] &amp;&amp; ![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 &quot;&quot;} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn &quot;Skipping $portname (not in the ports tree)&quot;
+                    continue
+                } else {
+                    break_softcontinue &quot;Port $portname not found&quot; 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 &quot;&quot; &amp;&amp; [array get variations] ne &quot;&quot;} {
+            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 &quot;install&quot;} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq &quot;archive&quot;} {
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to execute port: $result&quot; 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue &quot;Processing of port $portname failed&quot; 1 status
+        }
+    }
+    
+    if {$status == 0 &amp;&amp; $action eq &quot;install&quot; &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] &amp;&amp; ![info exists options(ports_install_no-rev-upgrade)] &amp;&amp; ${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 &lt; $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn &lt; $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 &quot;action&quot;.
+# 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 &quot;&quot;
+    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 &quot;&quot;
+    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 &quot;-&quot;} {
+            break
+        } elseif {[string index $arg 1] eq &quot;-&quot;} {
+            # 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 &quot;${action} does not accept --${key}&quot;
+                    } elseif {[llength $kopts] &gt; 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst &quot;--[lindex $e 0]&quot;
+                        }
+                        return -code error &quot;\&quot;port ${action} --${key}\&quot; is ambiguous: \n  port ${action} [join $errlst &quot;\n  port ${action} &quot;]&quot;
+                    }
+                    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] &amp;&amp; $kargc &gt; 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc &gt; 0} {
+                            return -code error &quot;--${key} expects [expr {$kargc + [llength $args]}] parameters!&quot;
+                        }
+                        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]) &amp;&amp; [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == &quot;;&quot; } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == &quot;#&quot; } {
+            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] &gt; 1} {
+                ui_error &quot;\&quot;port ${action}\&quot; is ambiguous: \n  port [join $actions &quot;\n  port &quot;]&quot;
+            } else {
+                ui_error &quot;Unrecognized action \&quot;port $action\&quot;&quot;
+            }
+            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 &quot;$errorInfo&quot;
+            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 &quot;$action does not accept string arguments&quot;
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] &amp;&amp; ![match &quot;;&quot;] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error &quot;Improper expression syntax while processing parameters&quot;
+                        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 &quot;${text}*&quot; false glob]} result]} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;search for portname $pattern failed: $result&quot;
+        }
+        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 &quot;[string tolower $text]*&quot;]
+    }
+
+    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 &quot;[string tolower $text]*&quot;]
+
+    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 &quot;&quot;
+    }
+
+    # 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 &quot;&quot;
+    while { $line eq &quot;&quot; } {
+
+        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 &lt; 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline &amp;&amp; $line ne &quot;&quot; } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in &quot;stdin&quot;]
+    set name &quot;port&quot;
+    set use_readline [expr {$isstdin &amp;&amp; [readline init $name]}]
+    set history_file [file normalize &quot;${macports::macports_user_dir}/history&quot;]
+
+    # Read readline history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin &amp;&amp; ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts &quot;MacPorts [macports::version]&quot;
+        puts &quot;Entering interactive mode... (\&quot;help\&quot; for help, \&quot;quit\&quot; to quit)&quot;
+    }
+
+    # 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 &quot;\[$shortdir\] &gt; &quot;
+        } else {
+            set prompt &quot;&quot;
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] &lt;= 0  } {
+            puts &quot;&quot;
+            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 &amp;&amp; ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts &quot;Goodbye&quot;
+    }
+
+    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 &quot;-&quot;} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal &quot;Failed to open command file; $result&quot;
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne &quot;stdin&quot;} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 &amp;&amp; ![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
+    #        &quot;yes&quot;, if the progress indicator should be shown, &quot;no&quot; otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq &quot;yes&quot;} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] &gt; $showTimeThreshold &amp;&amp;
+                ($total == 0 || [expr {double($cur) / double($total)}] &lt; $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot;, &quot;intermission&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        &quot;intermission&quot; and &quot;finish&quot;, the args are empty and unused. For
+    #        &quot;update&quot;, 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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        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 &quot;\r&quot;
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        contains a single argument &quot;ul&quot; or &quot;dl&quot; indicating whether this is
+    #        an up- or download. For &quot;update&quot;, contains the arguments
+    #        (&quot;ul&quot;|&quot;dl&quot;) $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 &quot;finish&quot;.
+    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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format &quot;        speed: %-13s&quot; &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format &quot; %-10s     speed: %-13s&quot; [bytesize $now {} &quot;%6.1f&quot;] &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            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 &quot;\r&quot;
+                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 &quot;&quot;} {suffix &quot;&quot;}} {
+        # 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 &quot;\033\[7m&quot;
+        for {set i 0} {$i &lt; $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 &quot; &quot;
+        }
+        # back to normal output
+        append progressbar &quot;\033\[0m&quot;
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger &lt; $barWidth} {
+        #            append progressbar &quot; &quot;
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar &quot;\u258f&quot;
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar &quot;\u258e&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar &quot;\u258c&quot;
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258b&quot;
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar &quot;\u258a&quot;
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar &quot;\u2589&quot;
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i &lt; $barWidth} {incr i} {
+            append progressbar &quot; &quot;
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format &quot; %[expr {$percentageWidth - 3}].1f %%&quot; $percentage]
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}&quot;
+        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 &quot;&quot;} {suffix &quot;&quot;}} {
+        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 &quot;&quot;
+        for {set i 0} {$i &lt; $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar &quot;\u2022&quot;
+            } else {
+                append progressbar &quot; &quot;
+            }
+        }
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${suffix}&quot;
+        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] &gt; 0} {
+            ui_notice &quot;---&gt;  Some of the ports you installed have notes:&quot;
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice &quot;  $name has the following notes:&quot;
+
+                # 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 &quot;\n&quot;] {
+                            set joiner &quot;&quot;
+                            set lines &quot;&quot;
+                            set newline &quot;    &quot;
+
+                            foreach word [split $line &quot; &quot;] {
+                                if {[string length $newline] + [string length $word] &gt;= $maxlen} {
+                                    lappend lines $newline
+                                    set newline &quot;    &quot;
+                                    set joiner &quot;&quot;
+                                }
+                                ::append newline $joiner $word
+                                set joiner &quot; &quot;
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines &quot;\n&quot;]
+                        }
+                    }
+                } 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] &amp;&amp; $cmdname eq &quot;portf&quot;} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options &quot;global&quot; ui_options global_options} result]} {
+    puts &quot;Error: $result&quot;
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    &amp;&amp; $portclient::progress::hasTermAnsiSend eq &quot;yes&quot;
+    &amp;&amp; (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne &quot;yes&quot;)} {
+    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 &amp;&amp; ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq &quot;selfupdate&quot; || [lookahead] eq &quot;sync&quot;} {
+    # 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 &quot;$errorInfo&quot;
+    fatal &quot;Failed to initialize MacPorts, $result&quot;
+}
+
+# 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] &gt; 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]) &amp;&amp; [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
</ins></span></pre></div>
<a id="branchesgsoc14cleanupsrcportportorig"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/port/port.orig (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,5362 @@
</span><ins>+#!/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@macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw &lt;rshaw@opendarwin.org&gt;
+# 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 &quot;AS IS&quot;
+# 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. &quot;yes&quot;, if the package is available, &quot;no&quot; 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 &quot;Usage: $cmdname$syntax&quot;
+        puts stderr &quot;\&quot;$cmdname help\&quot; or \&quot;man 1 port\&quot; for more information.&quot;
+    } else {
+        puts stderr &quot;$cmdname$syntax&quot;
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds &quot;&quot;
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen &gt; 65} {
+            set cmds &quot;$cmds,\n&quot;
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new &quot;$cmd&quot;
+        } else {
+            set new &quot;, $cmd&quot;
+        }
+        incr lineLen [string length $new]
+        set cmds &quot;$cmds$new&quot;
+    }
+
+    set cmdText &quot;Supported actions
+------------------
+$cmds
+&quot;
+
+    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 &quot;$cmdText$text&quot;
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error &quot;$argv0: $s&quot;
+    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 &gt; 0x40000000} {
+            set unit &quot;GiB&quot;
+        } elseif {$siz &gt; 0x100000} {
+            set unit &quot;MiB&quot;
+        } elseif {$siz &gt; 0x400} {
+            set unit &quot;KiB&quot;
+        } else {
+            set unit &quot;B&quot;
+        }
+    }
+    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 &quot;Unknown file size unit '$unit' specified&quot;
+            set unit &quot;B&quot;
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return &quot;$siz $unit&quot;
+}
+
+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 &quot;/usr/local&quot; &amp;&amp; ${macports::prefix} ne &quot;/usr&quot;} {
+        ui_error &quot;Follow http://guide.macports.org/#project.tickets to report a bug.&quot;
+    }
+}
+
+# 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 &quot;+&quot;} {
+            lappend pos $key
+        } elseif {$val eq &quot;-&quot;} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version &quot;&quot;
+    if {$version ne &quot;&quot; || $emptyVersionOkay} {
+        set pos_str &quot;&quot;
+        set neg_str &quot;&quot;
+
+        if {[llength $pos]} {
+            set pos_str &quot;+[join [lsort -ascii $pos] &quot;+&quot;]&quot;
+        }
+        if {[llength $neg]} {
+            set neg_str &quot;-[join [lsort -ascii $neg] &quot;-&quot;]&quot;
+        }
+
+        set composite_version &quot;$version$pos_str$neg_str&quot;
+    }
+
+    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 &quot;${field}s&quot;
+        }
+        category {
+            set field &quot;categories&quot;
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion &quot;&quot;}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] &gt; 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 &quot;The following versions of $portname are currently installed:&quot;
+        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 &quot;  $iname @${iversion}_${irevision}${ivariants}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants} (active)&quot;
+            }
+        }
+        return -code error &quot;Registry error: Please specify the full version as recorded in the port registry.&quot;
+    } 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=&gt;+-)
+    #   requested_variants array  (variant=&gt;+-)
+    #   options array   (key=&gt;value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) &quot;&quot; }
+    if {![info exists port(name)]}      { set port(name) &quot;&quot; }
+    if {![info exists port(version)]}   { set port(version) &quot;&quot; }
+    if {![info exists port(variants)]}  { set port(variants) &quot;&quot; }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) &quot;&quot; }
+    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 &quot;&quot; &amp;&amp; $port(name) eq &quot;&quot; } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq &quot;&quot;} {
+            ui_error &quot;A default port name could not be supplied.&quot;
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) &quot;$port(name)/[composite_version $port(version) $port(variants)]&quot;
+    
+    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 &quot;&quot;}} {
+    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 &quot;&quot;
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg &quot;Can't map the URL '$url' to a port description file (\&quot;${result}\&quot;).&quot;
+            ui_msg &quot;Please verify that the directory and portfile syntax are correct.&quot;
+        }
+    } 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 &quot;no&quot;} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 &amp;&amp; (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq &quot;no&quot;)} {
+        if {${is_upgrade} == &quot;yes&quot;} {
+            # $&gt; port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # &quot;upgrade&quot;, let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg &quot;Nothing to upgrade.&quot;
+            return 1
+        }
+        ui_error &quot;No ports matched the given expression&quot;
+        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 &quot;array unset portspec; array set portspec { $portspec }&quot;
+        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) &quot;_&quot;]
+    set bvr_ [split $b_(version) &quot;_&quot;]
+    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_ &lt; $br_} {
+        return -1
+    } elseif {$ar_ &gt; $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name@version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list &quot;name&quot; [lindex $a 0] &quot;version&quot; &quot;[lindex $a 1]_[lindex $a 2]&quot;]
+    array set b_ [list &quot;name&quot; [lindex $b 0] &quot;version&quot; &quot;[lindex $b 1]_[lindex $b 2]&quot;]
+    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 {\\&amp;}]
+    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)] &amp;&amp; [lindex $size 0] &gt; 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] &amp;&amp; [lindex $size 1] &gt; 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 &quot;&quot;} {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 &quot;\n&quot;] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;} {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 &quot; &quot;]
+    if {$indentfirstline == 0} {
+        set newline &quot;&quot;
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner &quot; &quot;
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] &gt;= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner &quot;&quot;
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 &amp;&amp; $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner &quot; &quot;
+    }
+    lappend lines $newline
+    return [join $lines &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;}} {
+    append label &quot;: [string repeat &quot; &quot; [expr {[string length $indent] - [string length &quot;$label: &quot;]}]]&quot;
+    return &quot;$label[wrap $string $maxlen $indent 0]&quot;
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first &quot;@&quot; $m] &lt; 0} {
+            if {[string first &quot;:&quot; $m] &gt;= 0} {
+                set m [regsub -- &quot;(.*):(.*)&quot; $m &quot;\\2@\\1&quot;] 
+            } else {
+                set m &quot;$m@macports.org&quot;
+            }
+        }
+        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 &quot;$errorInfo&quot;
+        fatal &quot;search for portname $pattern failed: $result&quot;
+    }
+    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 &quot;$errorInfo&quot;
+            fatal &quot;listing all ports failed: $result&quot;
+        }
+        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 &quot;&quot;} {
+        ui_msg &quot;To use the current port, you must be in a port's directory.&quot;
+        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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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} == &quot;yes&quot; || (${active} == &quot;yes&quot;) == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] &gt; 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  &quot;${installed_version}_${installed_revision}&quot;
+            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 &quot;$errorInfo&quot;
+                fatal &quot;lookup of portname $portname failed: $result&quot;
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &lt; 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 &quot;$::errorInfo&quot;
+            break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+        }
+
+        if {[llength $result] &lt; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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 &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq &quot;&quot;} {
+            add_to_portlist results [list name $iname version &quot;[lindex $i 1]_[lindex $i 2]&quot; 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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+                        return -code error &quot;lookup of portname $depname failed: $result&quot;
+                    }
+                    if {[llength $result] &lt; 2} {
+                        ui_error &quot;Port $depname not found&quot;
+                        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 &quot;$::errorInfo&quot;
+                        ui_error &quot;Unable to open port: $result&quot;
+                        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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;&quot;
+    set name &quot;&quot;
+    set version &quot;&quot;
+    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 &quot;)&quot;]} {
+                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 &quot;depends_lib&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_build&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_run&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_extract&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_fetch&quot;]
+
+            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 &quot;rdependentof&quot;]
+            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 &quot;rdepof&quot;]
+            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 &quot;&quot;} {
+                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 &quot;Can't open URL '$token' as a port&quot;
+                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 &quot;&quot;} } {
+    upvar $resname reslist
+    
+    set version &quot;&quot;
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne &quot;&quot;} { 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/          ==&gt; a/
+    #   a/, b/          ==&gt;
+    #   a/, a/1.0       ==&gt; a/1.0
+    #   a/1.0, a/       ==&gt; a/1.0
+    #   a/1.0, a/2.0    ==&gt;
+    #
+    #   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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 &quot;&quot;
+    set portversion &quot;&quot;
+    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 &quot;provides&quot;
+        # so we take a rather lenient view of what a &quot;portname&quot; is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder &quot;&quot;
+        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 &quot;*/*&quot; $portname]} {
+                set url &quot;file://$portname&quot;
+                set name [url_to_portname $url 1]
+                if { $name ne &quot;&quot; } {
+                    # 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 &quot;&quot;
+                    # 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 &quot;Insufficient privileges to write to MacPorts install prefix.&quot;
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder &quot;&quot;} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion &quot;&quot;
+    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 &quot;&quot; || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq &quot;&quot;} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime &amp;&amp; [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first &quot;/&quot; $opt]
+            if {$sepPos &gt;= 0} {
+                # Version terminated by &quot;/&quot; 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 &quot;+&quot;, or else is complete
+                set sepPos [string first &quot;+&quot; $opt]
+                if {$sepPos &gt;= 0} {
+                    # Version terminated by &quot;+&quot;
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt &quot;&quot;
+                }
+            }
+            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) &quot;\&quot;$val\&quot;&quot;
+                set opt &quot;&quot;
+                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 &amp;&amp; $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds &quot;&quot;
+        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 &quot; --$name&quot;
+
+                for {set i 1} {$i &lt;= $optc} {incr i} {
+                    append cmds &quot; &lt;arg$i&gt;&quot;
+                }
+            }
+        }
+        set args &quot;&quot;
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;arguments&gt;&quot;
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;portlist&gt;&quot;
+        }
+
+        set ret &quot;Usage: &quot;
+        set len [string length $action]
+        append ret [wrap &quot;$action$cmds$args&quot; 0 [string repeat &quot; &quot; [expr {8 + $len}]] 0]
+        append ret &quot;\n&quot;
+
+        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 &quot;No usage for topic $topic&quot;
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile &quot;$macports::prefix/var/macports/port-help.tcl&quot;
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr &quot;Error reading helpfile $helpfile: $err&quot;
+            return 1
+        }
+    } else {
+        puts stderr &quot;Unable to open help file $helpfile&quot;
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr &quot;No help for topic $topic&quot;
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error &quot;No usage for topic $topic&quot;
+            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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 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 &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] &quot;main.log&quot;]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue &quot;Could not open file $logfile: $result&quot; 1 status
+            }
+            set data [read $fp]
+            set data [split $data &quot;\n&quot;]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase &quot;\[a-z\]*&quot;
+            }
+
+            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 &quot;&quot;
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] &quot;|&quot;]
+                }
+            } else {
+                set prefix &quot;\[a-z\]*&quot;
+            }
+            foreach line $data {
+                set exp &quot;^:($prefix|any):($phase|any) (.*)$&quot;
+                if {[regexp $exp $line -&gt; lpriority lphase lmsg] == 1} {
+                    puts &quot;[macports::ui_prefix_default $lpriority]$lmsg&quot;
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue &quot;Log file for port $portname not found&quot; 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator &quot;&quot;
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] &amp;&amp; $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 &quot;&quot; || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;no PortIndex entry found for $portname&quot;
+            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 &quot;
+            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
+        &quot;
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     &quot;&quot;
+            variants    Variants
+            depends_fetch &quot;Fetch Dependencies&quot;
+            depends_extract &quot;Extract Dependencies&quot;
+            depends_build &quot;Build Dependencies&quot;
+            depends_run &quot;Runtime Dependencies&quot;
+            depends_lib &quot;Library Dependencies&quot;
+            description &quot;Brief Description&quot;
+            long_description &quot;Description&quot;
+            fullname    &quot;Full Name: &quot;
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   &quot;Conflicts with&quot;
+            replaced_by &quot;Replaced by&quot;
+            subports    &quot;Sub-ports&quot;
+        }
+
+        # 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)] &amp;&amp; $options(ports_info_depends) eq &quot;yes&quot;} {
+            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 &quot;\n&quot;
+        set subfield_sep &quot;, &quot;
+        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 &quot;\t&quot;
+            set subfield_sep &quot;,&quot;
+        }
+        
+        # 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 &amp;&amp; $opt eq &quot;skip_line&quot;} {
+                lappend fields &quot;&quot;
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq &quot;heading&quot;} {
+                set inf &quot;$portinfo(name) @$portinfo(version)&quot;
+                set ropt &quot;heading&quot;
+                if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                    append inf &quot;_$portinfo(revision)&quot;
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                }
+            } elseif {$opt eq &quot;fullname&quot;} {
+                set inf &quot;$portinfo(name) @&quot;
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt &quot;fullname&quot;
+            } 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 &quot;&quot;
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label &quot;&quot;
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label &quot;$opt: &quot;
+            }
+            
+            # Format the data
+            if { $ropt eq &quot;maintainers&quot; } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq &quot;variants&quot;} {
+                    # 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 &quot;&quot;
+                        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 &quot;($global_variations($v))&quot;
+                            # 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 &quot;\[$variant(is_default)]&quot;
+                            }
+                        }
+                        lappend inf &quot;$varmodifier$v&quot;
+                    }
+                } elseif {[string match &quot;depend*&quot; $ropt] 
+                          &amp;&amp; ![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 &quot;heading&quot; || $ropt eq &quot;fullname&quot;} {
+                    puts &quot;$label$field&quot;
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq &quot;&quot;} {
+                    continue
+                }
+                if {$label eq &quot;&quot;} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat &quot; &quot; $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 &quot; &quot; $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields &quot;$label$field&quot;
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print &amp;&amp; [llength $fields_tried]} {
+                puts -nonewline &quot;$portinfo(name) has no &quot;
+                puts [join $fields_tried &quot;, &quot;]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator &quot;--\n&quot;
+        }
+    }
+    
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port location failed: $result&quot; 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 &quot;Port $portname ${version}_${revision}${variants} is installed as an image in:&quot;
+        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 &quot;&quot;} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue &quot;The lookup of '$portname' failed: $result&quot; \
+                                1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;The port '$portname' was not found&quot; 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 &quot;The URL '$porturl' could not be&quot; \
+                                       &quot;opened: $result&quot;] 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 &quot;$portname has the following notes:&quot;
+            foreach note $portnotes {
+                puts [wrap $note 0 &quot;  &quot; 1]
+            }
+        } else {
+            puts &quot;$portname has no notes.&quot;
+        }
+    }
+    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 &quot;Please specify a filename to check which port provides that file.&quot;
+        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 &quot;link&quot;} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts &quot;$file is provided by: $port&quot;
+                } else {
+                    puts &quot;$file is not provided by a MacPorts port.&quot;
+                }
+            } else {
+                puts &quot;$file is a directory.&quot;
+            }
+        } else {
+            puts &quot;$file does not exist.&quot;
+        }
+    }
+    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)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port activate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping activate $portname (dry run)&quot;
+        }
+    }
+    
+    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)]
+            &amp;&amp; ![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 &quot;&quot; || $composite_version == &quot;${iversion}_${irevision}${ivariants}&quot;} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port deactivate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping deactivate $portname (dry run)&quot;
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug &quot;action_select \[$portlist] \[$opts]...&quot;
+
+    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] &lt; 1 &amp;&amp; [string map {ports_select_ &quot;&quot;} [lindex $commands 0]] != &quot;summary&quot;} {
+        ui_error &quot;port select \[--list|--set|--show|--summary] \&lt;group&gt; \[&lt;version&gt;]&quot;
+        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] &lt; 1 &amp;&amp; [llength $portlist] &gt; 1} {
+        set command set
+        ui_debug [concat &quot;Although no command was specified, more than &quot; \
+                         &quot;one argument was specified.  Defaulting to the &quot; \
+                         &quot;'set' command...&quot;]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] &lt; 1} {
+        set command list
+        ui_debug [concat &quot;No command was specified. Defaulting to the &quot; \
+                         &quot;'list' command...&quot;]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] &gt; 1} {
+        ui_error [concat &quot;Multiple commands were specified. Only one &quot; \
+                         &quot;command may be specified at a time.&quot;]
+        return 1
+    } else {
+        set command [string map {ports_select_ &quot;&quot;} [lindex $commands 0]]
+        ui_debug &quot;The '$command' command was specified.&quot;
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'list' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn &quot;Unable to get active selected version: $selected_version&quot;
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error &quot;The 'list' command failed: $versions&quot;
+                return 1
+            }
+
+            ui_notice &quot;Available versions for $group:&quot;
+            foreach v $versions {
+                ui_notice -nonewline &quot;\t&quot;
+                if {$selected_version == $v} {
+                    ui_msg &quot;$v (active)&quot;
+                } else {
+                    ui_msg &quot;$v&quot;
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] &lt; 2} {
+                ui_error [concat &quot;The 'set' command expects two &quot; \
+                                 &quot;arguments: &lt;group&gt;, &lt;version&gt;&quot;]
+                return 1
+            } elseif {[llength $portlist] &gt; 2} {
+                ui_warn [concat &quot;The 'set' command only expects two &quot; \
+                                &quot;arguments. Extra arguments will be &quot; \
+                                &quot;ignored.&quot;]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline &quot;Selecting '$version' for '$group' &quot;
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg &quot;failed: $result&quot;
+                return 1
+            }
+            ui_msg &quot;succeeded. '$version' is now active.&quot;
+            return 0
+        }
+        show {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'show' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error &quot;The 'show' command failed: $selected_version&quot;
+                return 1
+            }
+            puts [concat &quot;The currently selected version for '$group' is &quot; \
+                         &quot;'$selected_version'.&quot;]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] &gt; 0} {
+                ui_warn [concat &quot;The 'summary' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error &quot;The 'summary' command failed: $portgroups&quot;
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr &quot;%-*s  %-*s  %s&quot;
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn &quot;The list of options for the select group $pg could not be obtained: $versions&quot;
+                    continue
+                }
+                # remove &quot;none&quot;, sort the list, append none at the end
+                set noneidx [lsearch -exact $versions &quot;none&quot;]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions &quot;none&quot;
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn &quot;The currently selected option for the select group $pg could not be obtained: $selected_version&quot;
+                    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 &quot;Name&quot; $w2 &quot;Selected&quot; &quot;Options&quot;]
+            puts [format $formatStr $w1 &quot;====&quot; $w2 &quot;========&quot; &quot;=======&quot;]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) &quot; &quot;]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error &quot;An unknown command '$command' was specified.&quot;
+            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 &quot;$errorInfo&quot;
+        ui_error &quot;$result&quot;
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg &quot;Please run `port -v selfupdate' for details.&quot;
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal &quot;port selfupdate failed: $result&quot;
+    }
+    
+    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 &quot;setrequested&quot;]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info &quot;Setting requested flag for $portname to $val&quot;
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist &quot;yes&quot;] || ([prefix_unwritable] &amp;&amp; ![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 &quot;port:$portname&quot; [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 &amp;&amp; $status != 2 &amp;&amp; $status != 3 &amp;&amp; ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 &amp;&amp; $status != 2 &amp;&amp; $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] &amp;&amp; ${macports::revupgrade_autorun} &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
+    macports::doctor_main
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::doctor_main $opts
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; svn
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; 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 &quot;Version: &quot;
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline &quot;Platform: &quot;
+    }
+    puts &quot;${macports::os_platform} ${macports::os_major} ${macports::os_arch}&quot;
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 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] &gt; 0 } {
+            if {$action eq &quot;rdependents&quot;} {
+                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] &gt; 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice &quot;The following ports are dependent on ${portname}:&quot;
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos &gt;= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] &lt;= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] &amp;&amp; [string is true -strict $options(ports_rdependents_full)])} {
+                        puts &quot;${spaces}${cur_portname}&quot;
+                        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 &quot;$depport&quot;
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg &quot;$depport depends on $portname&quot;
+                    } else {
+                        ui_msg &quot;$depport depends on $portname (by [lindex $dep 1]:)&quot;
+                    }
+                }
+            }
+        } else {
+            ui_notice &quot;$portname has no dependents.&quot;
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator &quot;&quot;
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] &amp;&amp; [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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn &quot;port ${action} --index does not work with the 'current' pseudo-port&quot;
+            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 &quot;rdeps&quot; || [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 &quot;deps&quot;} {
+                    set label &quot;$labeldict($type) Dependencies&quot;
+                    lappend deps_output [wraplabel $label [join $deplist &quot;, &quot;] 0 [string repeat &quot; &quot; 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 &quot;deps&quot;} {
+            if {$ndeps == 0} {
+                ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+            } else {
+                ui_notice &quot;Full Name: $portname @${version}_${revision}${variants}&quot;
+                puts [join $deps_output &quot;\n&quot;]
+            }
+            set separator &quot;--\n&quot;
+            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 &quot;$::errorInfo&quot;
+                        break_softcontinue &quot;lookup of portname $depname failed: $result&quot; 1 status
+                    }
+                    if {[llength $result] &lt; 2} {
+                        break_softcontinue &quot;Port $depname not found&quot; 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)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug &quot;$::errorInfo&quot;
+                            break_softcontinue &quot;Unable to open port: $result&quot; 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] &gt; 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] &gt; 0} {
+            ui_notice &quot;The following ports are dependencies of $portname @${version}_${revision}${variants}:&quot;
+        } else {
+            ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos &gt;= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] &lt;= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] &amp;&amp; [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts &quot;${spaces}${cur_port}&quot;
+                } else {
+                    puts &quot;${spaces}${cur_portname}&quot;
+                }
+                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 &quot;--\n&quot;
+    }
+    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 &quot;$portname is not installed&quot;
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn &quot;no such port: $portname, skipping uninstall&quot;
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port uninstall failed: $result&quot; 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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port installed failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] &gt; 0 } {
+        ui_notice &quot;The following ports are currently installed:&quot;
+        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 &quot;&quot;
+            set nvariants &quot;&quot;
+            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 &quot;&quot;
+                }
+                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 &amp;&amp; $os_platform ne &quot;&quot; &amp;&amp; $os_major != 0 &amp;&amp; $os_major ne &quot;&quot;} {
+                    append extra &quot; platform='$os_platform $os_major'&quot;
+                }
+                if {$archs != 0 &amp;&amp; $archs ne &quot;&quot;} {
+                    append extra &quot; archs='$archs'&quot;
+                }
+            }
+            if { $iactive == 0 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}&quot;
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are installed.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+
+    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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port outdated failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] &gt; 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 &quot;${installed_version}_${installed_revision}&quot;
+
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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 &quot;$portname has no version field&quot;
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot;
+            if {$epoch_comp_result != 0 &amp;&amp; $installed_version != $latest_version} {
+                if {($comp_result &gt;= 0 &amp;&amp; $epoch_comp_result &lt; 0) || ($comp_result &lt;= 0 &amp;&amp; $epoch_comp_result &gt; 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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &quot;&quot;
+                if { $comp_result &gt; 0 } {
+                    set relation &quot;&gt;&quot;
+                    set flag &quot;!&quot;
+                } else {
+                    set relation &quot;&lt;&quot;
+                }
+                
+                # Emit information
+                if {$comp_result &lt; 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice &quot;The following installed ports are outdated:&quot;
+                    }
+                    incr num_outdated
+
+                    puts [format &quot;%-30s %-24s %1s&quot; $portname &quot;$installed_compound $relation $latest_compound [subst $reason]&quot; $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice &quot;No installed ports are outdated.&quot;
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are outdated.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+    
+    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 &quot;%12s $file&quot; [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] &gt; 0 } {
+                ui_notice &quot;Port $portname contains:&quot;
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice &quot;Port $portname does not contain any files or is not active.&quot;
+            }
+        } else {
+            ui_notice &quot;Port $portname is not installed.&quot;
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq &quot;K&quot; || $units eq &quot;Ki&quot;} {
+        return &quot;KiB&quot;
+    } elseif {$units eq &quot;k&quot;} {
+        return &quot;kB&quot;
+    } elseif {$units eq &quot;Mi&quot;} {
+        return &quot;MiB&quot;
+    } elseif {$units eq &quot;M&quot;} {
+        return &quot;MB&quot;
+    } elseif {$units eq &quot;Gi&quot;} {
+        return &quot;GiB&quot;
+    } elseif {$units eq &quot;G&quot;} {
+        return &quot;GB&quot;
+    } 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] &gt; 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne &quot;yes&quot;} {
+                    set msg &quot;[bytesize $space $units] $portname&quot;
+                    if { $portversion != {} } {
+                        append msg &quot; @$portversion&quot;
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr &quot;Port $portname does not contain any file or is not active.&quot;
+            }
+        } else {
+            puts stderr &quot;Port $portname is not installed.&quot;
+        }
+    }
+    if {[llength $portlist] &gt; 1 || ([info exists options(ports_space_total)] &amp;&amp; $options(ports_space_total) eq &quot;yes&quot;)} {
+        puts &quot;[bytesize $spaceall $units] total&quot;
+    }
+    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 &quot;&quot;} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] &amp;&amp; $options(ports_variants_index) eq &quot;yes&quot;)} {
+            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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;port variants --index does not work with 'current' pseudo-port&quot;
+            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 &quot;$portname has no variants&quot;
+        } 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 &quot;$portname has the variants:&quot;
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier &quot;   &quot;
+                # 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 &quot;  $variations($v)&quot;
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier &quot;($global_variations($v))&quot;
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier &quot;\[$variant(is_default)\]&quot;
+                    }
+                    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 &quot;$varmodifier$v&quot; [string trim $vdescription] 0 [string repeat &quot; &quot; [expr 5 + [string length $v]]]]
+                } else {
+                    puts &quot;$varmodifier$v&quot;
+                }
+                if {[info exists vconflicts]} {
+                    puts &quot;     * conflicts with [string trim $vconflicts]&quot;
+                }
+                if {[info exists vrequires]} {
+                    puts &quot;     * requires [string trim $vrequires]&quot;
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        ui_error &quot;You must specify a search pattern&quot;
+        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)] &amp;&amp; $options(ports_search_depends) eq &quot;yes&quot;} {
+        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 &quot;none&quot;
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne &quot;yes&quot; } {
+            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) &quot;yes&quot;
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) &quot;yes&quot;
+        set filters(description) &quot;yes&quot;
+    }
+
+    set separator &quot;&quot;
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq &quot;none&quot;} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first &quot;*&quot; $portname] == -1 &amp;&amp; [string first &quot;?&quot; $portname] == -1} {
+                set searchstring &quot;*$portname*&quot;
+            }
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for name $portname failed: $result&quot; 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 &quot;&quot;
+        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 &quot;Invalid port entry, missing portname&quot;
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing description&quot;
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing version&quot;
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        &amp;&amp; $options(ports_search_line) eq &quot;yes&quot;} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)&quot;
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)&quot;
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline &quot;$portinfo(name) @$portinfo(version)&quot;
+                    if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                        puts -nonewline &quot;_$portinfo(revision)&quot;
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                    }
+                    puts &quot;&quot;
+                    puts [wrap [join $portinfo(description)] 0 [string repeat &quot; &quot; 4]]
+                }
+            }
+
+            set joiner &quot;\n&quot;
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice &quot;No match for $portname found&quot;
+        } elseif {[llength $res] &gt; 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne &quot;yes&quot;)} {
+                ui_notice &quot;\nFound [llength $res] ports.&quot;
+            }
+        }
+
+        set separator &quot;--\n&quot;
+    }
+
+    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] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        add_to_portlist portlist [list name &quot;-all-&quot;]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq &quot;-all-&quot;} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;listing all ports failed: $result&quot; 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $search_string failed: $result&quot; 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir &quot;&quot;
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format &quot;%-30s @%-14s %s&quot; $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 &quot;$key=$value&quot;
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne &quot;&quot; } {
+                set ver_field &quot;@$composite_version&quot;
+            } else {
+                set ver_field &quot;&quot;
+            }
+            puts [format &quot;%-30s %s %s&quot; $portname $ver_field  [join $opts &quot; &quot;]]
+        } else {
+            puts &quot;$portname&quot;
+        }
+    }
+
+    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 &quot;&quot;} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://${portdir}&quot;;    # Rebuild url so it's fully qualified
+        set portfile &quot;${portdir}/Portfile&quot;
+        
+        # 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 &quot;10.5&quot;} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor &quot;&quot;
+                    set editor_var &quot;ports_${action}_editor&quot;
+                    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 &quot;&quot; } { set editor &quot;/usr/bin/vi&quot; }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec &gt;@stdout &lt;@stdin 2&gt;@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug &quot;$errorInfo&quot;
+                        break_softcontinue &quot;unable to invoke editor $editor: $result&quot; 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq &quot;10.5&quot;} {
+                        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] &quot;main.log&quot;]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error &quot;Log file not found for port in $portdir&quot;
+                    }
+                }
+
+                gohome {
+                    set homepage &quot;&quot;
+
+                    # 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 &quot;&quot; &amp;&amp; ![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 &quot;&quot; } {
+                        if {[catch {system &quot;${macports::autoconf::open_path} '$homepage'&quot;} result]} {
+                            global errorInfo
+                            ui_debug &quot;$errorInfo&quot;
+                            break_softcontinue &quot;unable to invoke browser using ${macports::autoconf::open_path}: $result&quot; 1 status
+                        }
+                    } else {
+                        ui_error [format &quot;No homepage for %s&quot; $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue &quot;Could not read $portfile&quot; 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 &quot;$errorInfo&quot;
+        ui_msg &quot;port sync failed: $result&quot;
+        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 &quot;install&quot; || $action eq &quot;archive&quot;) &amp;&amp; [prefix_unwritable] &amp;&amp; ![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 &quot;&quot;} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn &quot;Skipping $portname (not in the ports tree)&quot;
+                    continue
+                } else {
+                    break_softcontinue &quot;Port $portname not found&quot; 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 &quot;&quot; &amp;&amp; [array get variations] ne &quot;&quot;} {
+            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 &quot;install&quot;} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq &quot;archive&quot;} {
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to execute port: $result&quot; 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue &quot;Processing of port $portname failed&quot; 1 status
+        }
+    }
+    
+    if {$status == 0 &amp;&amp; $action eq &quot;install&quot; &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] &amp;&amp; ![info exists options(ports_install_no-rev-upgrade)] &amp;&amp; ${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 &lt; $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn &lt; $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 &quot;action&quot;.
+# 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 &quot;&quot;
+    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 &quot;&quot;
+    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 &quot;-&quot;} {
+            break
+        } elseif {[string index $arg 1] eq &quot;-&quot;} {
+            # 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 &quot;${action} does not accept --${key}&quot;
+                    } elseif {[llength $kopts] &gt; 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst &quot;--[lindex $e 0]&quot;
+                        }
+                        return -code error &quot;\&quot;port ${action} --${key}\&quot; is ambiguous: \n  port ${action} [join $errlst &quot;\n  port ${action} &quot;]&quot;
+                    }
+                    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] &amp;&amp; $kargc &gt; 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc &gt; 0} {
+                            return -code error &quot;--${key} expects [expr {$kargc + [llength $args]}] parameters!&quot;
+                        }
+                        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]) &amp;&amp; [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == &quot;;&quot; } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == &quot;#&quot; } {
+            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] &gt; 1} {
+                ui_error &quot;\&quot;port ${action}\&quot; is ambiguous: \n  port [join $actions &quot;\n  port &quot;]&quot;
+            } else {
+                ui_error &quot;Unrecognized action \&quot;port $action\&quot;&quot;
+            }
+            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 &quot;$errorInfo&quot;
+            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 &quot;$action does not accept string arguments&quot;
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] &amp;&amp; ![match &quot;;&quot;] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error &quot;Improper expression syntax while processing parameters&quot;
+                        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 &quot;${text}*&quot; false glob]} result]} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;search for portname $pattern failed: $result&quot;
+        }
+        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 &quot;[string tolower $text]*&quot;]
+    }
+
+    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 &quot;[string tolower $text]*&quot;]
+
+    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 &quot;&quot;
+    }
+
+    # 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 &quot;&quot;
+    while { $line eq &quot;&quot; } {
+
+        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 &lt; 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline &amp;&amp; $line ne &quot;&quot; } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in &quot;stdin&quot;]
+    set name &quot;port&quot;
+    set use_readline [expr {$isstdin &amp;&amp; [readline init $name]}]
+    set history_file [file normalize &quot;${macports::macports_user_dir}/history&quot;]
+
+    # Read readline history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin &amp;&amp; ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts &quot;MacPorts [macports::version]&quot;
+        puts &quot;Entering interactive mode... (\&quot;help\&quot; for help, \&quot;quit\&quot; to quit)&quot;
+    }
+
+    # 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 &quot;\[$shortdir\] &gt; &quot;
+        } else {
+            set prompt &quot;&quot;
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] &lt;= 0  } {
+            puts &quot;&quot;
+            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 &amp;&amp; ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts &quot;Goodbye&quot;
+    }
+
+    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 &quot;-&quot;} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal &quot;Failed to open command file; $result&quot;
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne &quot;stdin&quot;} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 &amp;&amp; ![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
+    #        &quot;yes&quot;, if the progress indicator should be shown, &quot;no&quot; otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq &quot;yes&quot;} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] &gt; $showTimeThreshold &amp;&amp;
+                ($total == 0 || [expr {double($cur) / double($total)}] &lt; $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot;, &quot;intermission&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        &quot;intermission&quot; and &quot;finish&quot;, the args are empty and unused. For
+    #        &quot;update&quot;, 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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        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 &quot;\r&quot;
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        contains a single argument &quot;ul&quot; or &quot;dl&quot; indicating whether this is
+    #        an up- or download. For &quot;update&quot;, contains the arguments
+    #        (&quot;ul&quot;|&quot;dl&quot;) $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 &quot;finish&quot;.
+    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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format &quot;        speed: %-13s&quot; &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format &quot; %-10s     speed: %-13s&quot; [bytesize $now {} &quot;%6.1f&quot;] &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            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 &quot;\r&quot;
+                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 &quot;&quot;} {suffix &quot;&quot;}} {
+        # 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 &quot;\033\[7m&quot;
+        for {set i 0} {$i &lt; $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 &quot; &quot;
+        }
+        # back to normal output
+        append progressbar &quot;\033\[0m&quot;
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger &lt; $barWidth} {
+        #            append progressbar &quot; &quot;
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar &quot;\u258f&quot;
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar &quot;\u258e&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar &quot;\u258c&quot;
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258b&quot;
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar &quot;\u258a&quot;
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar &quot;\u2589&quot;
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i &lt; $barWidth} {incr i} {
+            append progressbar &quot; &quot;
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format &quot; %[expr {$percentageWidth - 3}].1f %%&quot; $percentage]
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}&quot;
+        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 &quot;&quot;} {suffix &quot;&quot;}} {
+        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 &quot;&quot;
+        for {set i 0} {$i &lt; $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar &quot;\u2022&quot;
+            } else {
+                append progressbar &quot; &quot;
+            }
+        }
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${suffix}&quot;
+        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] &gt; 0} {
+            ui_notice &quot;---&gt;  Some of the ports you installed have notes:&quot;
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice &quot;  $name has the following notes:&quot;
+
+                # 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 &quot;\n&quot;] {
+                            set joiner &quot;&quot;
+                            set lines &quot;&quot;
+                            set newline &quot;    &quot;
+
+                            foreach word [split $line &quot; &quot;] {
+                                if {[string length $newline] + [string length $word] &gt;= $maxlen} {
+                                    lappend lines $newline
+                                    set newline &quot;    &quot;
+                                    set joiner &quot;&quot;
+                                }
+                                ::append newline $joiner $word
+                                set joiner &quot; &quot;
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines &quot;\n&quot;]
+                        }
+                    }
+                } 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] &amp;&amp; $cmdname eq &quot;portf&quot;} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options &quot;global&quot; ui_options global_options} result]} {
+    puts &quot;Error: $result&quot;
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    &amp;&amp; $portclient::progress::hasTermAnsiSend eq &quot;yes&quot;
+    &amp;&amp; (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne &quot;yes&quot;)} {
+    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 &amp;&amp; ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq &quot;selfupdate&quot; || [lookahead] eq &quot;sync&quot;} {
+    # 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 &quot;$errorInfo&quot;
+    fatal &quot;Failed to initialize MacPorts, $result&quot;
+}
+
+# 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] &gt; 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]) &amp;&amp; [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
</ins></span></pre></div>
<a id="branchesgsoc14cleanupsrcportporttclorig"></a>
<div class="addfile"><h4>Added: branches/gsoc14-cleanup/src/port/port.tcl.orig (0 => 123747)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,5361 @@
</span><ins>+# -*- 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@macports.org $
+#
+# Copyright (c) 2004-2014 The MacPorts Project
+# Copyright (c) 2004 Robert Shaw &lt;rshaw@opendarwin.org&gt;
+# 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 &quot;AS IS&quot;
+# 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. &quot;yes&quot;, if the package is available, &quot;no&quot; 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 &quot;Usage: $cmdname$syntax&quot;
+        puts stderr &quot;\&quot;$cmdname help\&quot; or \&quot;man 1 port\&quot; for more information.&quot;
+    } else {
+        puts stderr &quot;$cmdname$syntax&quot;
+    }
+}
+
+proc print_help {args} {
+    global action_array
+
+    print_usage 0
+
+    # Generate and format the command list from the action_array
+    set cmds &quot;&quot;
+    set lineLen 0
+    foreach cmd [lsort [array names action_array]] {
+        if {$lineLen &gt; 65} {
+            set cmds &quot;$cmds,\n&quot;
+            set lineLen 0
+        }
+        if {$lineLen == 0} {
+            set new &quot;$cmd&quot;
+        } else {
+            set new &quot;, $cmd&quot;
+        }
+        incr lineLen [string length $new]
+        set cmds &quot;$cmds$new&quot;
+    }
+
+    set cmdText &quot;Supported actions
+------------------
+$cmds
+&quot;
+
+    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 &quot;$cmdText$text&quot;
+}
+
+
+# Produce error message and exit
+proc fatal s {
+    global argv0
+    ui_error &quot;$argv0: $s&quot;
+    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 &gt; 0x40000000} {
+            set unit &quot;GiB&quot;
+        } elseif {$siz &gt; 0x100000} {
+            set unit &quot;MiB&quot;
+        } elseif {$siz &gt; 0x400} {
+            set unit &quot;KiB&quot;
+        } else {
+            set unit &quot;B&quot;
+        }
+    }
+    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 &quot;Unknown file size unit '$unit' specified&quot;
+            set unit &quot;B&quot;
+        }
+    }
+    if {[expr {round($siz)}] != $siz} {
+        set siz [format $format $siz]
+    }
+    return &quot;$siz $unit&quot;
+}
+
+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 &quot;/usr/local&quot; &amp;&amp; ${macports::prefix} ne &quot;/usr&quot;} {
+        ui_error &quot;Follow http://guide.macports.org/#project.tickets to report a bug.&quot;
+    }
+}
+
+# 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 &quot;+&quot;} {
+            lappend pos $key
+        } elseif {$val eq &quot;-&quot;} {
+            lappend neg $key
+        }
+    }
+
+    # If there is no version, we have nothing to do
+    set composite_version &quot;&quot;
+    if {$version ne &quot;&quot; || $emptyVersionOkay} {
+        set pos_str &quot;&quot;
+        set neg_str &quot;&quot;
+
+        if {[llength $pos]} {
+            set pos_str &quot;+[join [lsort -ascii $pos] &quot;+&quot;]&quot;
+        }
+        if {[llength $neg]} {
+            set neg_str &quot;-[join [lsort -ascii $neg] &quot;-&quot;]&quot;
+        }
+
+        set composite_version &quot;$version$pos_str$neg_str&quot;
+    }
+
+    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 &quot;${field}s&quot;
+        }
+        category {
+            set field &quot;categories&quot;
+        }
+    }
+
+    return $field
+}
+
+
+proc registry_installed {portname {portversion &quot;&quot;}} {
+    set ilist [registry::installed $portname $portversion]
+    if { [llength $ilist] &gt; 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 &quot;The following versions of $portname are currently installed:&quot;
+        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 &quot;  $iname @${iversion}_${irevision}${ivariants}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants} (active)&quot;
+            }
+        }
+        return -code error &quot;Registry error: Please specify the full version as recorded in the port registry.&quot;
+    } 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=&gt;+-)
+    #   requested_variants array  (variant=&gt;+-)
+    #   options array   (key=&gt;value)
+    #   fullname        (name/version_revision+-variants)
+
+    array set port $portentry
+    if {![info exists port(url)]}       { set port(url) &quot;&quot; }
+    if {![info exists port(name)]}      { set port(name) &quot;&quot; }
+    if {![info exists port(version)]}   { set port(version) &quot;&quot; }
+    if {![info exists port(variants)]}  { set port(variants) &quot;&quot; }
+    if {![info exists port(requested_variants)]}  { set port(requested_variants) &quot;&quot; }
+    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 &quot;&quot; &amp;&amp; $port(name) eq &quot;&quot; } {
+        set url file://.
+        set portname [url_to_portname $url]
+        set port(url) $url
+        set port(name) $portname
+        if {$portname eq &quot;&quot;} {
+            ui_error &quot;A default port name could not be supplied.&quot;
+        }
+    }
+
+    # Form the fully discriminated portname: portname/version_revison+-variants
+    set port(fullname) &quot;$port(name)/[composite_version $port(version) $port(variants)]&quot;
+    
+    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 &quot;&quot;}} {
+    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 &quot;&quot;
+    if {[catch {set ctx [mportopen $url]} result]} {
+        if {!$quiet} {
+            ui_msg &quot;Can't map the URL '$url' to a port description file (\&quot;${result}\&quot;).&quot;
+            ui_msg &quot;Please verify that the directory and portfile syntax are correct.&quot;
+        }
+    } 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 &quot;no&quot;} } {
+    global private_options
+    upvar $nameportlist portlist
+
+    if {[llength $portlist] == 0 &amp;&amp; (![info exists private_options(ports_no_args)] || $private_options(ports_no_args) eq &quot;no&quot;)} {
+        if {${is_upgrade} == &quot;yes&quot;} {
+            # $&gt; port upgrade outdated
+            # Error: No ports matched the given expression
+            # is not very user friendly - if we're in the special case of
+            # &quot;upgrade&quot;, let's print a message that's a little easier to
+            # understand and less alarming.
+            ui_msg &quot;Nothing to upgrade.&quot;
+            return 1
+        }
+        ui_error &quot;No ports matched the given expression&quot;
+        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 &quot;array unset portspec; array set portspec { $portspec }&quot;
+        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) &quot;_&quot;]
+    set bvr_ [split $b_(version) &quot;_&quot;]
+    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_ &lt; $br_} {
+        return -1
+    } elseif {$ar_ &gt; $br_} {
+        return 1
+    } else {
+        return 0
+    }
+}
+
+# Sort two ports in NVR (name@version_revision) order
+proc portlist_sort { list } {
+    return [lsort -command portlist_compare $list]
+}
+
+proc portlist_compareint { a b } {
+    array set a_ [list &quot;name&quot; [lindex $a 0] &quot;version&quot; &quot;[lindex $a 1]_[lindex $a 2]&quot;]
+    array set b_ [list &quot;name&quot; [lindex $b 0] &quot;version&quot; &quot;[lindex $b 1]_[lindex $b 2]&quot;]
+    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 {\\&amp;}]
+    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)] &amp;&amp; [lindex $size 0] &gt; 0} {
+                set env(LINES) [lindex $size 0]
+            }
+
+            if {![info exists env(COLUMNS)] &amp;&amp; [lindex $size 1] &gt; 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 &quot;&quot;} {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 &quot;\n&quot;] {
+        lappend splitstring [wrapline $line $maxlen $indent $indentline]
+        set indentline 1
+    }
+    return [join $splitstring &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;} {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 &quot; &quot;]
+    if {$indentfirstline == 0} {
+        set newline &quot;&quot;
+        set maxlen [expr {$maxlen - [string length $indent]}]
+    } else {
+        set newline $indent
+    }
+    append newline [lindex $string 0]
+    set joiner &quot; &quot;
+    set first 1
+    foreach word [lrange $string 1 end] {
+        if {[string length $newline]+[string length $word] &gt;= $maxlen} {
+            lappend lines $newline
+            set newline $indent
+            set joiner &quot;&quot;
+            # If indentfirstline is set to 0, reset maxlen to its
+            # original length after appending the first line to lines.
+            if {$first == 1 &amp;&amp; $indentfirstline == 0} {
+                set maxlen [expr {$maxlen + [string length $indent]}]
+            }
+            set first 0
+        }
+        append newline $joiner $word
+        set joiner &quot; &quot;
+    }
+    lappend lines $newline
+    return [join $lines &quot;\n&quot;]
+}
+
+##
+# 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 &quot;&quot;}} {
+    append label &quot;: [string repeat &quot; &quot; [expr {[string length $indent] - [string length &quot;$label: &quot;]}]]&quot;
+    return &quot;$label[wrap $string $maxlen $indent 0]&quot;
+}
+
+proc unobscure_maintainers { list } {
+    set result {}
+    foreach m $list {
+        if {[string first &quot;@&quot; $m] &lt; 0} {
+            if {[string first &quot;:&quot; $m] &gt;= 0} {
+                set m [regsub -- &quot;(.*):(.*)&quot; $m &quot;\\2@\\1&quot;] 
+            } else {
+                set m &quot;$m@macports.org&quot;
+            }
+        }
+        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 &quot;$errorInfo&quot;
+        fatal &quot;search for portname $pattern failed: $result&quot;
+    }
+    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 &quot;$errorInfo&quot;
+            fatal &quot;listing all ports failed: $result&quot;
+        }
+        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 &quot;&quot;} {
+        ui_msg &quot;To use the current port, you must be in a port's directory.&quot;
+        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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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} == &quot;yes&quot; || (${active} == &quot;yes&quot;) == (${iactive} != 0) } {
+            add_to_portlist results [list name $iname version &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    # Now process the list, keeping only those ports that are outdated
+    set results {}
+    if { [llength $ilist] &gt; 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  &quot;${installed_version}_${installed_revision}&quot;
+            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 &quot;$errorInfo&quot;
+                fatal &quot;lookup of portname $portname failed: $result&quot;
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts stderr &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound     &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &lt; 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 &quot;$::errorInfo&quot;
+            break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+        }
+
+        if {[llength $result] &lt; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+
+    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 &quot;${iversion}_${irevision}&quot; 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 &quot;Registry error: No ports registered as installed.&quot;} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;port installed failed: $result&quot;
+        }
+    }
+    registry::open_dep_map
+    set results {}
+    foreach i $ilist {
+        set iname [lindex $i 0]
+        if {[registry::list_dependents $iname] eq &quot;&quot;} {
+            add_to_portlist results [list name $iname version &quot;[lindex $i 1]_[lindex $i 2]&quot; 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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+                        return -code error &quot;lookup of portname $depname failed: $result&quot;
+                    }
+                    if {[llength $result] &lt; 2} {
+                        ui_error &quot;Port $depname not found&quot;
+                        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 &quot;$::errorInfo&quot;
+                        ui_error &quot;Unable to open port: $result&quot;
+                        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] &gt; 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 &quot;$::errorInfo&quot;
+        return -code error &quot;lookup of portname $portname failed: $result&quot;
+    }
+    if {[llength $result] &lt; 2} {
+        return -code error &quot;Port $portname not found&quot;
+    }
+    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 &quot;$::errorInfo&quot;
+        return -code error &quot;Unable to open port: $result&quot;
+    }
+    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 &quot;&quot;
+    set name &quot;&quot;
+    set version &quot;&quot;
+    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 &quot;)&quot;]} {
+                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 &quot;depends_lib&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_build&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_run&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_extract&quot;]
+            add_multiple_ports reslist [get_matching_ports $pat no regexp &quot;depends_fetch&quot;]
+
+            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 &quot;rdependentof&quot;]
+            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 &quot;rdepof&quot;]
+            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 &quot;&quot;} {
+                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 &quot;Can't open URL '$token' as a port&quot;
+                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 &quot;&quot;} } {
+    upvar $resname reslist
+    
+    set version &quot;&quot;
+    array unset variants
+    array unset options
+    parsePortSpec version variants options $remainder
+    
+    array unset overrides
+    if {$version ne &quot;&quot;} { 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/          ==&gt; a/
+    #   a/, b/          ==&gt;
+    #   a/, a/1.0       ==&gt; a/1.0
+    #   a/1.0, a/       ==&gt; a/1.0
+    #   a/1.0, a/2.0    ==&gt;
+    #
+    #   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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 { &quot;$port(name)/&quot; == $port(fullname) }]
+        if {$simpleform} {
+            set pat &quot;^${safefullname}&quot;
+        } else {
+            set safename [regex_pat_sanitize $port(name)]
+            set pat &quot;^${safefullname}$|^${safename}/$&quot;
+        }
+        
+        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 &quot;&quot;
+    set portversion &quot;&quot;
+    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 &quot;provides&quot;
+        # so we take a rather lenient view of what a &quot;portname&quot; is. We allow
+        # anything that doesn't look like either a version, a variant, or an option
+        set token [lookahead]
+
+        set remainder &quot;&quot;
+        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 &quot;*/*&quot; $portname]} {
+                set url &quot;file://$portname&quot;
+                set name [url_to_portname $url 1]
+                if { $name ne &quot;&quot; } {
+                    # 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 &quot;&quot;
+                    # 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 &quot;Insufficient privileges to write to MacPorts install prefix.&quot;
+        return 1
+    }
+}
+
+    
+proc parsePortSpec { vername varname optname {remainder &quot;&quot;} } {
+    upvar $vername portversion
+    upvar $varname portvariants
+    upvar $optname portoptions
+    
+    global global_options
+    
+    set portversion &quot;&quot;
+    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 &quot;&quot; || [moreargs]} {set firstTime 0} {
+    
+        # Refresh opt as needed
+        if {$opt eq &quot;&quot;} {
+            if {$adv} advance
+            set opt [lookahead]
+            set adv 1
+            set consumed 0
+        }
+        
+        # Version must be first, if it's there at all
+        if {$firstTime &amp;&amp; [string match {@*} $opt]} {
+            # Parse the version
+            
+            # Strip the @
+            set opt [string range $opt 1 end]
+            
+            # Handle the version
+            set sepPos [string first &quot;/&quot; $opt]
+            if {$sepPos &gt;= 0} {
+                # Version terminated by &quot;/&quot; 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 &quot;+&quot;, or else is complete
+                set sepPos [string first &quot;+&quot; $opt]
+                if {$sepPos &gt;= 0} {
+                    # Version terminated by &quot;+&quot;
+                    set portversion [string range $opt 0 [expr {$sepPos - 1}]]
+                    set opt [string range $opt $sepPos end]
+                } else {
+                    # Unterminated version
+                    set portversion $opt
+                    set opt &quot;&quot;
+                }
+            }
+            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) &quot;\&quot;$val\&quot;&quot;
+                set opt &quot;&quot;
+                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 &amp;&amp; $adv } advance
+                break
+            }
+        }
+    }
+}
+
+
+##########################################
+# Action Handlers
+##########################################
+
+proc action_get_usage { action } {
+    global action_array cmd_opts_array
+
+    if {[info exists action_array($action)]} {
+        set cmds &quot;&quot;
+        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 &quot; --$name&quot;
+
+                for {set i 1} {$i &lt;= $optc} {incr i} {
+                    append cmds &quot; &lt;arg$i&gt;&quot;
+                }
+            }
+        }
+        set args &quot;&quot;
+        set needed [action_needs_portlist $action]
+        if {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;arguments&gt;&quot;
+        } elseif {[ACTION_ARGS_STRINGS] == $needed} {
+            set args &quot; &lt;portlist&gt;&quot;
+        }
+
+        set ret &quot;Usage: &quot;
+        set len [string length $action]
+        append ret [wrap &quot;$action$cmds$args&quot; 0 [string repeat &quot; &quot; [expr {8 + $len}]] 0]
+        append ret &quot;\n&quot;
+
+        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 &quot;No usage for topic $topic&quot;
+            return 1
+        }
+    }
+    return 0
+}
+
+
+proc action_help { action portlist opts } {
+    set helpfile &quot;$macports::prefix/var/macports/port-help.tcl&quot;
+
+    if {[llength $portlist] == 0} {
+        print_help
+        return 0
+    }
+
+    if {[file exists $helpfile]} {
+        if {[catch {source $helpfile} err]} {
+            puts stderr &quot;Error reading helpfile $helpfile: $err&quot;
+            return 1
+        }
+    } else {
+        puts stderr &quot;Unable to open help file $helpfile&quot;
+        return 1
+    }
+
+    foreach topic $portlist {
+        if {![info exists porthelp($topic)]} {
+            puts stderr &quot;No help for topic $topic&quot;
+            return 1
+        }
+
+        set usage [action_get_usage $topic]
+        if {$usage != -1} {
+           puts -nonewline stderr $usage
+        } else {
+            ui_error &quot;No usage for topic $topic&quot;
+            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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 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 &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+            set portname $portinfo(name)
+        }
+        set portpath [macports::getportdir $porturl]
+        set logfile [file join [macports::getportlogpath $portpath $portname] &quot;main.log&quot;]
+        if {[file exists $logfile]} {
+            if {[catch {set fp [open $logfile r]} result]} {
+                break_softcontinue &quot;Could not open file $logfile: $result&quot; 1 status
+            }
+            set data [read $fp]
+            set data [split $data &quot;\n&quot;]
+
+            if {[info exists global_options(ports_log_phase)]} {
+                set phase $global_options(ports_log_phase);
+            } else {
+                set phase &quot;\[a-z\]*&quot;
+            }
+
+            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 &quot;&quot;
+                } else {
+                    set prefix [join [lrange ${macports::ui_priorities} 0 $index] &quot;|&quot;]
+                }
+            } else {
+                set prefix &quot;\[a-z\]*&quot;
+            }
+            foreach line $data {
+                set exp &quot;^:($prefix|any):($phase|any) (.*)$&quot;
+                if {[regexp $exp $line -&gt; lpriority lphase lmsg] == 1} {
+                    puts &quot;[macports::ui_prefix_default $lpriority]$lmsg&quot;
+                }
+            }
+
+            close $fp
+        } else {
+            break_softcontinue &quot;Log file for port $portname not found&quot; 1 status
+        }
+    }
+    return 0
+}
+
+
+proc action_info { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+
+    set separator &quot;&quot;
+    foreachport $portlist {
+        set index_only 0
+        if {[info exists options(ports_info_index)] &amp;&amp; $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 &quot;&quot; || $index_only} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;no PortIndex entry found for $portname&quot;
+            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 &quot;
+            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
+        &quot;
+
+        # Label map for pretty printing
+        array set pretty_label {
+            heading     &quot;&quot;
+            variants    Variants
+            depends_fetch &quot;Fetch Dependencies&quot;
+            depends_extract &quot;Extract Dependencies&quot;
+            depends_build &quot;Build Dependencies&quot;
+            depends_run &quot;Runtime Dependencies&quot;
+            depends_lib &quot;Library Dependencies&quot;
+            description &quot;Brief Description&quot;
+            long_description &quot;Description&quot;
+            fullname    &quot;Full Name: &quot;
+            homepage    Homepage
+            platforms   Platforms
+            maintainers Maintainers
+            license     License
+            conflicts   &quot;Conflicts with&quot;
+            replaced_by &quot;Replaced by&quot;
+            subports    &quot;Sub-ports&quot;
+        }
+
+        # 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)] &amp;&amp; $options(ports_info_depends) eq &quot;yes&quot;} {
+            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 &quot;\n&quot;
+        set subfield_sep &quot;, &quot;
+        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 &quot;\t&quot;
+            set subfield_sep &quot;,&quot;
+        }
+        
+        # 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 &amp;&amp; $opt eq &quot;skip_line&quot;} {
+                lappend fields &quot;&quot;
+                continue
+            }
+            # Artificial field names to reproduce prettyprinted summary
+            if {$opt eq &quot;heading&quot;} {
+                set inf &quot;$portinfo(name) @$portinfo(version)&quot;
+                set ropt &quot;heading&quot;
+                if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                    append inf &quot;_$portinfo(revision)&quot;
+                }
+                if {[info exists portinfo(categories)]} {
+                    append inf &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                }
+            } elseif {$opt eq &quot;fullname&quot;} {
+                set inf &quot;$portinfo(name) @&quot;
+                append inf [composite_version $portinfo(version) $portinfo(active_variants)]
+                set ropt &quot;fullname&quot;
+            } 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 &quot;&quot;
+                } else {
+                    set inf [join $portinfo($ropt)]
+                }
+            }
+
+            # Calculate field label
+            set label &quot;&quot;
+            if {$pretty_print} {
+                if {[info exists pretty_label($ropt)]} {
+                    set label $pretty_label($ropt)
+                } else {
+                    set label $opt
+                }
+            } elseif {$show_label} {
+                set label &quot;$opt: &quot;
+            }
+            
+            # Format the data
+            if { $ropt eq &quot;maintainers&quot; } {
+                set inf [unobscure_maintainers $inf]
+            }
+            #     ... special formatting for certain fields when prettyprinting
+            if {$pretty_print} {
+                if {$ropt eq &quot;variants&quot;} {
+                    # 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 &quot;&quot;
+                        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 &quot;($global_variations($v))&quot;
+                            # 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 &quot;\[$variant(is_default)]&quot;
+                            }
+                        }
+                        lappend inf &quot;$varmodifier$v&quot;
+                    }
+                } elseif {[string match &quot;depend*&quot; $ropt] 
+                          &amp;&amp; ![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 &quot;heading&quot; || $ropt eq &quot;fullname&quot;} {
+                    puts &quot;$label$field&quot;
+                    continue
+                }
+            }
+            lappend fields_tried $label
+            if {$pretty_print} {
+                if {$field eq &quot;&quot;} {
+                    continue
+                }
+                if {$label eq &quot;&quot;} {
+                    set wrap_len 0
+                    if {[info exists pretty_wrap($ropt)]} {
+                        set wrap_len $pretty_wrap($ropt)
+                    }
+                    lappend fields [wrap $field 0 [string repeat &quot; &quot; $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 &quot; &quot; $wrap_len]]
+                }
+
+            } else { # Not pretty print
+                lappend fields &quot;$label$field&quot;
+            }
+        }
+
+        # Now output all that information:
+        if {[llength $fields]} {
+            puts [join $fields $field_sep]
+        } else {
+            if {$pretty_print &amp;&amp; [llength $fields_tried]} {
+                puts -nonewline &quot;$portinfo(name) has no &quot;
+                puts [join $fields_tried &quot;, &quot;]
+            }
+        }
+        if {![info exists noseparator]} {
+            set separator &quot;--\n&quot;
+        }
+    }
+    
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port location failed: $result&quot; 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 &quot;Port $portname ${version}_${revision}${variants} is installed as an image in:&quot;
+        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 &quot;&quot;} {
+            # Look up the port.
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug $::errorInfo
+                break_softcontinue &quot;The lookup of '$portname' failed: $result&quot; \
+                                1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;The port '$portname' was not found&quot; 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 &quot;The URL '$porturl' could not be&quot; \
+                                       &quot;opened: $result&quot;] 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 &quot;$portname has the following notes:&quot;
+            foreach note $portnotes {
+                puts [wrap $note 0 &quot;  &quot; 1]
+            }
+        } else {
+            puts &quot;$portname has no notes.&quot;
+        }
+    }
+    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 &quot;Please specify a filename to check which port provides that file.&quot;
+        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 &quot;link&quot;} {
+                set port [registry::file_registered $file]
+                if { $port != 0 } {
+                    puts &quot;$file is provided by: $port&quot;
+                } else {
+                    puts &quot;$file is not provided by a MacPorts port.&quot;
+                }
+            } else {
+                puts &quot;$file is a directory.&quot;
+            }
+        } else {
+            puts &quot;$file does not exist.&quot;
+        }
+    }
+    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)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port activate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping activate $portname (dry run)&quot;
+        }
+    }
+    
+    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)]
+            &amp;&amp; ![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 &quot;&quot; || $composite_version == &quot;${iversion}_${irevision}${ivariants}&quot;} {
+                set regref [registry::entry open $portname $iversion $irevision $ivariants [lindex $i 5]]
+                if {[$regref installtype] eq &quot;image&quot; &amp;&amp; [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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;port deactivate failed: $result&quot; 1 status
+            }
+        } else {
+            ui_msg &quot;Skipping deactivate $portname (dry run)&quot;
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_select { action portlist opts } {
+    ui_debug &quot;action_select \[$portlist] \[$opts]...&quot;
+
+    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] &lt; 1 &amp;&amp; [string map {ports_select_ &quot;&quot;} [lindex $commands 0]] != &quot;summary&quot;} {
+        ui_error &quot;port select \[--list|--set|--show|--summary] \&lt;group&gt; \[&lt;version&gt;]&quot;
+        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] &lt; 1 &amp;&amp; [llength $portlist] &gt; 1} {
+        set command set
+        ui_debug [concat &quot;Although no command was specified, more than &quot; \
+                         &quot;one argument was specified.  Defaulting to the &quot; \
+                         &quot;'set' command...&quot;]
+    # If no command (--set, --show, --list) is specified *and* less than two
+    # argument are specified, default to the list command.
+    } elseif {[llength $commands] &lt; 1} {
+        set command list
+        ui_debug [concat &quot;No command was specified. Defaulting to the &quot; \
+                         &quot;'list' command...&quot;]
+    # Only allow one command to be specified at a time.
+    } elseif {[llength $commands] &gt; 1} {
+        ui_error [concat &quot;Multiple commands were specified. Only one &quot; \
+                         &quot;command may be specified at a time.&quot;]
+        return 1
+    } else {
+        set command [string map {ports_select_ &quot;&quot;} [lindex $commands 0]]
+        ui_debug &quot;The '$command' command was specified.&quot;
+    }
+
+    switch -- $command {
+        list {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'list' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect show $group} selected_version]} {
+                global errorInfo
+                ui_debug $errorInfo
+                ui_warn &quot;Unable to get active selected version: $selected_version&quot;
+            }
+
+            # On error mportselect returns with the code 'error'.
+            if {[catch {mportselect $command $group} versions]} {
+                ui_error &quot;The 'list' command failed: $versions&quot;
+                return 1
+            }
+
+            ui_notice &quot;Available versions for $group:&quot;
+            foreach v $versions {
+                ui_notice -nonewline &quot;\t&quot;
+                if {$selected_version == $v} {
+                    ui_msg &quot;$v (active)&quot;
+                } else {
+                    ui_msg &quot;$v&quot;
+                }
+            }
+            return 0
+        }
+        set {
+            if {[llength $portlist] &lt; 2} {
+                ui_error [concat &quot;The 'set' command expects two &quot; \
+                                 &quot;arguments: &lt;group&gt;, &lt;version&gt;&quot;]
+                return 1
+            } elseif {[llength $portlist] &gt; 2} {
+                ui_warn [concat &quot;The 'set' command only expects two &quot; \
+                                &quot;arguments. Extra arguments will be &quot; \
+                                &quot;ignored.&quot;]
+            }
+            set version [lindex $portlist 1]
+
+            ui_msg -nonewline &quot;Selecting '$version' for '$group' &quot;
+            if {[catch {mportselect $command $group $version} result]} {
+                ui_msg &quot;failed: $result&quot;
+                return 1
+            }
+            ui_msg &quot;succeeded. '$version' is now active.&quot;
+            return 0
+        }
+        show {
+            if {[llength $portlist] &gt; 1} {
+                ui_warn [concat &quot;The 'show' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command $group} selected_version]} {
+                ui_error &quot;The 'show' command failed: $selected_version&quot;
+                return 1
+            }
+            puts [concat &quot;The currently selected version for '$group' is &quot; \
+                         &quot;'$selected_version'.&quot;]
+            return 0
+        }
+        summary {
+            if {[llength $portlist] &gt; 0} {
+                ui_warn [concat &quot;The 'summary' command does not expect any &quot; \
+                                &quot;arguments. Extra arguments will be ignored.&quot;]
+            }
+
+            if {[catch {mportselect $command} portgroups]} {
+                ui_error &quot;The 'summary' command failed: $portgroups&quot;
+                return 1
+            }
+
+            set w1 4
+            set w2 8
+            set formatStr &quot;%-*s  %-*s  %s&quot;
+
+            set groups [list]
+            foreach pg $portgroups {
+                array set groupdesc {}
+                set groupdesc(name) [string trim $pg]
+
+                if {[catch {mportselect list $pg} versions]} {
+                    ui_warn &quot;The list of options for the select group $pg could not be obtained: $versions&quot;
+                    continue
+                }
+                # remove &quot;none&quot;, sort the list, append none at the end
+                set noneidx [lsearch -exact $versions &quot;none&quot;]
+                set versions [lsort [lreplace $versions $noneidx $noneidx]]
+                lappend versions &quot;none&quot;
+                set groupdesc(versions) $versions
+
+                if {[catch {mportselect show $pg} selected_version]} {
+                    ui_warn &quot;The currently selected option for the select group $pg could not be obtained: $selected_version&quot;
+                    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 &quot;Name&quot; $w2 &quot;Selected&quot; &quot;Options&quot;]
+            puts [format $formatStr $w1 &quot;====&quot; $w2 &quot;========&quot; &quot;=======&quot;]
+            foreach groupdesc $groups {
+                array set groupd $groupdesc
+                puts [format $formatStr $w1 $groupd(name) $w2 $groupd(selected) [join $groupd(versions) &quot; &quot;]]
+                array unset groupd
+            }
+            return 0
+        }
+        default {
+            ui_error &quot;An unknown command '$command' was specified.&quot;
+            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 &quot;$errorInfo&quot;
+        ui_error &quot;$result&quot;
+        if {![macports::ui_isset ports_verbose]} {
+            ui_msg &quot;Please run `port -v selfupdate' for details.&quot;
+        } else {
+            # Let's only print the ticket URL if the user has followed the
+            # advice we printed earlier.
+            print_tickets_url
+        }
+        fatal &quot;port selfupdate failed: $result&quot;
+    }
+    
+    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 &quot;setrequested&quot;]
+    foreachport $portlist {
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![catch {set ilist [registry::installed $portname $composite_version]} result]} {
+            ui_info &quot;Setting requested flag for $portname to $val&quot;
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 1 status
+        }
+    }
+    
+    return $status
+}
+
+
+proc action_upgrade { action portlist opts } {
+    if {[require_portlist portlist &quot;yes&quot;] || ([prefix_unwritable] &amp;&amp; ![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 &quot;port:$portname&quot; [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 &amp;&amp; $status != 2 &amp;&amp; $status != 3 &amp;&amp; ![macports::ui_isset ports_processall]} {
+                break
+            }
+        }
+    }
+    
+    if {$status != 0 &amp;&amp; $status != 2 &amp;&amp; $status != 3} {
+        print_tickets_url
+    } elseif {$status == 0} {
+        array set options $opts
+        if {![info exists options(ports_upgrade_no-rev-upgrade)] &amp;&amp; ${macports::revupgrade_autorun} &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+            set status [action_revupgrade $action $portlist $opts]
+        }
+    }
+
+    return $status
+}
+
+proc action_doctor { action portlist opts } {
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
+    macports::doctor_main
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+    macports::doctor_main $opts
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; svn
+    return 0
+}
+
+proc action_reclaim { action portlist opts } {
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
+=======
+    if {[prefix_unwritable]} {
+        return 1
+    }
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; 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 &quot;Version: &quot;
+    }
+    puts [macports::version]
+    return 0
+}
+
+
+proc action_platform { action portlist opts } {
+    if {![macports::ui_isset ports_quiet]} {
+        puts -nonewline &quot;Platform: &quot;
+    }
+    puts &quot;${macports::os_platform} ${macports::os_major} ${macports::os_arch}&quot;
+    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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;$result&quot; 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] &gt; 0 } {
+            if {$action eq &quot;rdependents&quot;} {
+                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] &gt; 0} {
+                        set deplist $newlist
+                    } else {
+                        break
+                    }
+                }
+                set portstack [list $toplist]
+                set pos_stack [list 0]
+                array unset seen
+                ui_notice &quot;The following ports are dependent on ${portname}:&quot;
+                while 1 {
+                    set cur_portlist [lindex $portstack end]
+                    set cur_pos [lindex $pos_stack end]
+                    if {$cur_pos &gt;= [llength $cur_portlist]} {
+                        set portstack [lreplace $portstack end end]
+                        set pos_stack [lreplace $pos_stack end end]
+                        if {[llength $portstack] &lt;= 0} {
+                            break
+                        } else {
+                            continue
+                        }
+                    }
+                    set cur_port [lindex $cur_portlist $cur_pos]
+                    set cur_portname [lindex $cur_port 2]
+                    set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+                    if {![info exists seen($cur_portname)] || ([info exists options(ports_rdependents_full)] &amp;&amp; [string is true -strict $options(ports_rdependents_full)])} {
+                        puts &quot;${spaces}${cur_portname}&quot;
+                        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 &quot;$depport&quot;
+                    } elseif {![macports::ui_isset ports_verbose]} {
+                        ui_msg &quot;$depport depends on $portname&quot;
+                    } else {
+                        ui_msg &quot;$depport depends on $portname (by [lindex $dep 1]:)&quot;
+                    }
+                }
+            }
+        } else {
+            ui_notice &quot;$portname has no dependents.&quot;
+        }
+    }
+    return $status
+}
+
+
+proc action_deps { action portlist opts } {
+    global global_variations
+    set status 0
+    if {[require_portlist portlist]} {
+        return 1
+    }
+    set separator &quot;&quot;
+
+    foreachport $portlist {
+        if {[info exists options(ports_${action}_no-build)] &amp;&amp; [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 &quot;&quot;} {
+        # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {mportlookup $portname} result]} {
+                ui_debug &quot;$::errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+            array set portinfo [lindex $result 1]
+            set porturl $portinfo(porturl)
+        } elseif {$porturl ne &quot;file://.&quot;} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Portdir $portdir not found&quot; 1 status
+            }
+            set matchindex [lsearch -exact -nocase $result $portname]
+            if {$matchindex != -1} {
+                array set portinfo [lindex $result [incr matchindex]]
+            } else {
+                ui_warn &quot;Portdir $portdir doesn't seem to belong to portname $portname&quot;
+                array set portinfo [lindex $result 1]
+            }
+        }
+
+        if {!([info exists options(ports_${action}_index)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+            # 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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+            }
+            array unset portinfo
+            array set portinfo [mportinfo $mport]
+            mportclose $mport
+        } elseif {![info exists portinfo]} {
+            ui_warn &quot;port ${action} --index does not work with the 'current' pseudo-port&quot;
+            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 &quot;rdeps&quot; || [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 &quot;deps&quot;} {
+                    set label &quot;$labeldict($type) Dependencies&quot;
+                    lappend deps_output [wraplabel $label [join $deplist &quot;, &quot;] 0 [string repeat &quot; &quot; 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 &quot;deps&quot;} {
+            if {$ndeps == 0} {
+                ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+            } else {
+                ui_notice &quot;Full Name: $portname @${version}_${revision}${variants}&quot;
+                puts [join $deps_output &quot;\n&quot;]
+            }
+            set separator &quot;--\n&quot;
+            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 &quot;$::errorInfo&quot;
+                        break_softcontinue &quot;lookup of portname $depname failed: $result&quot; 1 status
+                    }
+                    if {[llength $result] &lt; 2} {
+                        break_softcontinue &quot;Port $depname not found&quot; 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)] &amp;&amp; $options(ports_${action}_index) eq &quot;yes&quot;)} {
+                        if {[catch {set mport [mportopen $porturl [array get options] [array get merged_variations]]} result]} {
+                            ui_debug &quot;$::errorInfo&quot;
+                            break_softcontinue &quot;Unable to open port: $result&quot; 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] &gt; 0} {
+                set deplist $newlist
+            } else {
+                break
+            }
+        }
+        set portstack [list $toplist]
+        set pos_stack [list 0]
+        array unset seen
+        if {[llength $toplist] &gt; 0} {
+            ui_notice &quot;The following ports are dependencies of $portname @${version}_${revision}${variants}:&quot;
+        } else {
+            ui_notice &quot;$portname @${version}_${revision}${variants} has no dependencies.&quot;
+        }
+        while 1 {
+            set cur_portlist [lindex $portstack end]
+            set cur_pos [lindex $pos_stack end]
+            if {$cur_pos &gt;= [llength $cur_portlist]} {
+                set portstack [lreplace $portstack end end]
+                set pos_stack [lreplace $pos_stack end end]
+                if {[llength $portstack] &lt;= 0} {
+                    break
+                } else {
+                    continue
+                }
+            }
+            set cur_port [lindex $cur_portlist $cur_pos]
+            set cur_portname [lindex [split $cur_port :] end]
+            set spaces [string repeat &quot; &quot; [expr {[llength $pos_stack] * 2}]]
+            if {![info exists seen($cur_portname)] || ([info exists options(ports_${action}_full)] &amp;&amp; [string is true -strict $options(ports_${action}_full)])} {
+                if {[macports::ui_isset ports_verbose]} {
+                    puts &quot;${spaces}${cur_port}&quot;
+                } else {
+                    puts &quot;${spaces}${cur_portname}&quot;
+                }
+                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 &quot;--\n&quot;
+    }
+    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 &quot;$portname is not installed&quot;
+            if {[catch {set res [mportlookup $portname]} result] || [llength $res] == 0} {
+                ui_warn &quot;no such port: $portname, skipping uninstall&quot;
+            }
+            continue
+        }
+        set composite_version [composite_version $portversion [array get variations]]
+        if {![info exists options(ports_uninstall_no-exec)]
+            &amp;&amp; ![catch {set ilist [registry::installed $portname $composite_version]}]
+            &amp;&amp; [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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;port uninstall failed: $result&quot; 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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port installed failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+    if { [llength $ilist] &gt; 0 } {
+        ui_notice &quot;The following ports are currently installed:&quot;
+        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 &quot;&quot;
+            set nvariants &quot;&quot;
+            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 &quot;&quot;
+                }
+                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 &amp;&amp; $os_platform ne &quot;&quot; &amp;&amp; $os_major != 0 &amp;&amp; $os_major ne &quot;&quot;} {
+                    append extra &quot; platform='$os_platform $os_major'&quot;
+                }
+                if {$archs != 0 &amp;&amp; $archs ne &quot;&quot;} {
+                    append extra &quot; archs='$archs'&quot;
+                }
+            }
+            if { $iactive == 0 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants}${extra}&quot;
+            } elseif { $iactive == 1 } {
+                puts &quot;  $iname @${iversion}_${irevision}${ivariants}${nvariants} (active)${extra}&quot;
+            }
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are installed.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+
+    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 &quot;no&quot;)} {
+        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 &quot;* not registered as installed.&quot; $result]} {
+                    global errorInfo
+                    ui_debug &quot;$errorInfo&quot;
+                    break_softcontinue &quot;port outdated failed: $result&quot; 1 status
+                }
+            }
+        }
+    } else {
+        if { [catch {set ilist [registry::installed]} result] } {
+            if {$result ne &quot;Registry error: No ports registered as installed.&quot;} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                ui_error &quot;port installed failed: $result&quot;
+                set status 1
+            }
+        }
+    }
+
+    set num_outdated 0
+    if { [llength $ilist] &gt; 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 &quot;${installed_version}_${installed_revision}&quot;
+
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                if {[macports::ui_isset ports_debug]} {
+                    puts &quot;$portname ($installed_compound is installed; the port was not found in the port index)&quot;
+                }
+                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 &quot;$portname has no version field&quot;
+                continue
+            }
+            set latest_version $portinfo(version)
+            set latest_revision 0
+            if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} { 
+                set latest_revision $portinfo(revision)
+            }
+            set latest_compound &quot;${latest_version}_${latest_revision}&quot;
+            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 &quot;&quot;
+            if {$epoch_comp_result != 0 &amp;&amp; $installed_version != $latest_version} {
+                if {($comp_result &gt;= 0 &amp;&amp; $epoch_comp_result &lt; 0) || ($comp_result &lt;= 0 &amp;&amp; $epoch_comp_result &gt; 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 &quot;&quot; &amp;&amp; $os_platform_installed != 0
+                    &amp;&amp; $os_major_installed ne &quot;&quot; &amp;&amp; $os_major_installed != 0
+                    &amp;&amp; ($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 &quot;&quot;
+                if { $comp_result &gt; 0 } {
+                    set relation &quot;&gt;&quot;
+                    set flag &quot;!&quot;
+                } else {
+                    set relation &quot;&lt;&quot;
+                }
+                
+                # Emit information
+                if {$comp_result &lt; 0 || [macports::ui_isset ports_verbose]} {
+                
+                    if {$num_outdated == 0} {
+                        ui_notice &quot;The following installed ports are outdated:&quot;
+                    }
+                    incr num_outdated
+
+                    puts [format &quot;%-30s %-24s %1s&quot; $portname &quot;$installed_compound $relation $latest_compound [subst $reason]&quot; $flag]
+                }
+                
+            }
+        }
+        
+        if {$num_outdated == 0} {
+            ui_notice &quot;No installed ports are outdated.&quot;
+        }
+    } elseif { $restrictedList } {
+        ui_notice &quot;None of the specified ports are outdated.&quot;
+    } else {
+        ui_notice &quot;No ports are installed.&quot;
+    }
+    
+    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 &quot;%12s $file&quot; [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] &gt; 0 } {
+                ui_notice &quot;Port $portname contains:&quot;
+                foreach file $files {
+                    puts [subst $outstring]
+                }
+            } else {
+                ui_notice &quot;Port $portname does not contain any files or is not active.&quot;
+            }
+        } else {
+            ui_notice &quot;Port $portname is not installed.&quot;
+        }
+    }
+    registry::close_file_map
+
+    return 0
+}
+
+# expand abbreviations of size units
+proc complete_size_units {units} {
+    if {$units eq &quot;K&quot; || $units eq &quot;Ki&quot;} {
+        return &quot;KiB&quot;
+    } elseif {$units eq &quot;k&quot;} {
+        return &quot;kB&quot;
+    } elseif {$units eq &quot;Mi&quot;} {
+        return &quot;MiB&quot;
+    } elseif {$units eq &quot;M&quot;} {
+        return &quot;MB&quot;
+    } elseif {$units eq &quot;Gi&quot;} {
+        return &quot;GiB&quot;
+    } elseif {$units eq &quot;G&quot;} {
+        return &quot;GB&quot;
+    } 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] &gt; 0 } {
+                foreach file $files {
+                    catch {
+                        set space [expr {$space + [file size $file]}]
+                    }
+                }
+                if {![info exists options(ports_space_total)] || $options(ports_space_total) ne &quot;yes&quot;} {
+                    set msg &quot;[bytesize $space $units] $portname&quot;
+                    if { $portversion != {} } {
+                        append msg &quot; @$portversion&quot;
+                    }
+                    puts $msg
+                }
+                set spaceall [expr {$space + $spaceall}]
+            } else {
+                puts stderr &quot;Port $portname does not contain any file or is not active.&quot;
+            }
+        } else {
+            puts stderr &quot;Port $portname is not installed.&quot;
+        }
+    }
+    if {[llength $portlist] &gt; 1 || ([info exists options(ports_space_total)] &amp;&amp; $options(ports_space_total) eq &quot;yes&quot;)} {
+        puts &quot;[bytesize $spaceall $units] total&quot;
+    }
+    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 &quot;&quot;} {
+            # look up port
+            if {[catch {mportlookup $portname} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $result] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 1 status
+            }
+
+            array set portinfo [lindex $result 1]
+
+            set porturl $portinfo(porturl)
+            set portdir $portinfo(portdir)
+        }
+
+        if {!([info exists options(ports_variants_index)] &amp;&amp; $options(ports_variants_index) eq &quot;yes&quot;)} {
+            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 &quot;$::errorInfo&quot;
+                break_softcontinue &quot;Unable to open port: $result&quot; 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 &quot;port variants --index does not work with 'current' pseudo-port&quot;
+            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 &quot;$portname has no variants&quot;
+        } 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 &quot;$portname has the variants:&quot;
+            foreach v [lsort $portinfo(variants)] {
+                unset -nocomplain vconflicts vdescription vrequires
+                set varmodifier &quot;   &quot;
+                # 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 &quot;  $variations($v)&quot;
+                    } elseif {[info exists global_variations($v)]} {
+                        # selected by variants.conf, prefixed with (+)/(-)
+                        set varmodifier &quot;($global_variations($v))&quot;
+                    } elseif {[info exists variant(is_default)]} {
+                        set varmodifier &quot;\[$variant(is_default)\]&quot;
+                    }
+                    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 &quot;$varmodifier$v&quot; [string trim $vdescription] 0 [string repeat &quot; &quot; [expr 5 + [string length $v]]]]
+                } else {
+                    puts &quot;$varmodifier$v&quot;
+                }
+                if {[info exists vconflicts]} {
+                    puts &quot;     * conflicts with [string trim $vconflicts]&quot;
+                }
+                if {[info exists vrequires]} {
+                    puts &quot;     * requires [string trim $vrequires]&quot;
+                }
+            }
+        }
+    }
+
+    return $status
+}
+
+
+proc action_search { action portlist opts } {
+    global private_options global_options
+    set status 0
+    if {![llength $portlist] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        ui_error &quot;You must specify a search pattern&quot;
+        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)] &amp;&amp; $options(ports_search_depends) eq &quot;yes&quot;} {
+        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 &quot;none&quot;
+    set filter_case no
+    foreach { option } [array names options ports_search_*] {
+        set opt [string range $option 13 end]
+
+        if { $options($option) ne &quot;yes&quot; } {
+            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) &quot;yes&quot;
+    }
+    # Set default search filter if none was given
+    if { [array size filters] == 0 } {
+        set filters(name) &quot;yes&quot;
+        set filters(description) &quot;yes&quot;
+    }
+
+    set separator &quot;&quot;
+    foreach portname $portlist {
+        puts -nonewline $separator
+
+        set searchstring $portname
+        set matchstyle $filter_matchstyle
+        if {$matchstyle eq &quot;none&quot;} {
+            # Guess if the given string was a glob expression, if not do a substring search
+            if {[string first &quot;*&quot; $portname] == -1 &amp;&amp; [string first &quot;?&quot; $portname] == -1} {
+                set searchstring &quot;*$portname*&quot;
+            }
+            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 &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for name $portname failed: $result&quot; 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 &quot;&quot;
+        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 &quot;Invalid port entry, missing portname&quot;
+                continue
+            }
+            if {![info exists portinfo(description)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing description&quot;
+                continue
+            }
+            if {![info exists portinfo(version)]} {
+                puts stderr &quot;Invalid port entry for $portinfo(name), missing version&quot;
+                continue
+            }
+
+            if {[macports::ui_isset ports_quiet]} {
+                puts $portinfo(name)
+            } else {
+                if {[info exists options(ports_search_line)]
+                        &amp;&amp; $options(ports_search_line) eq &quot;yes&quot;} {
+                    # check for ports without category, e.g. replaced_by stubs
+                    if {[info exists portinfo(categories)]} {
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t$portinfo(categories)\t$portinfo(description)&quot;
+                    } else {
+                        # keep two consecutive tabs in order to provide consistent columns' content
+                        puts &quot;$portinfo(name)\t$portinfo(version)\t\t$portinfo(description)&quot;
+                    }
+                } else {
+                    puts -nonewline $joiner
+
+                    puts -nonewline &quot;$portinfo(name) @$portinfo(version)&quot;
+                    if {[info exists portinfo(revision)] &amp;&amp; $portinfo(revision) &gt; 0} {
+                        puts -nonewline &quot;_$portinfo(revision)&quot;
+                    }
+                    if {[info exists portinfo(categories)]} {
+                        puts -nonewline &quot; ([join $portinfo(categories) &quot;, &quot;])&quot;
+                    }
+                    puts &quot;&quot;
+                    puts [wrap [join $portinfo(description)] 0 [string repeat &quot; &quot; 4]]
+                }
+            }
+
+            set joiner &quot;\n&quot;
+            set portfound 1
+        }
+        if { !$portfound } {
+            ui_notice &quot;No match for $portname found&quot;
+        } elseif {[llength $res] &gt; 1} {
+            if {(![info exists global_options(ports_search_line)]
+                    || $global_options(ports_search_line) ne &quot;yes&quot;)} {
+                ui_notice &quot;\nFound [llength $res] ports.&quot;
+            }
+        }
+
+        set separator &quot;--\n&quot;
+    }
+
+    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] &amp;&amp; [info exists private_options(ports_no_args)] &amp;&amp; $private_options(ports_no_args) eq &quot;yes&quot;} {
+        add_to_portlist portlist [list name &quot;-all-&quot;]
+    }
+    
+    foreachport $portlist {
+        if {$portname eq &quot;-all-&quot;} {
+           if {[catch {set res [mportlistall]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;listing all ports failed: $result&quot; 1 status
+            }
+        } else {
+            set search_string [regex_pat_sanitize $portname]
+            if {[catch {set res [mportsearch ^$search_string\$ no]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;search for portname $search_string failed: $result&quot; 1 status
+            }
+        }
+
+        foreach {name array} $res {
+            array unset portinfo
+            array set portinfo $array
+            set outdir &quot;&quot;
+            if {[info exists portinfo(portdir)]} {
+                set outdir $portinfo(portdir)
+            }
+            puts [format &quot;%-30s @%-14s %s&quot; $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 &quot;$key=$value&quot;
+                }
+            }
+
+            set composite_version [composite_version $portversion [array get variations] 1]
+            if { $composite_version ne &quot;&quot; } {
+                set ver_field &quot;@$composite_version&quot;
+            } else {
+                set ver_field &quot;&quot;
+            }
+            puts [format &quot;%-30s %s %s&quot; $portname $ver_field  [join $opts &quot; &quot;]]
+        } else {
+            puts &quot;$portname&quot;
+        }
+    }
+
+    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 &quot;&quot;} {
+        
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                break_softcontinue &quot;Port $portname not found&quot; 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 &quot;file://${portdir}&quot;;    # Rebuild url so it's fully qualified
+        set portfile &quot;${portdir}/Portfile&quot;
+        
+        # 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 &quot;10.5&quot;} {
+                        unsetenv *
+                    }
+                    array set env [array get boot_env]
+                    
+                    # Find an editor to edit the portfile
+                    set editor &quot;&quot;
+                    set editor_var &quot;ports_${action}_editor&quot;
+                    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 &quot;&quot; } { set editor &quot;/usr/bin/vi&quot; }
+                    
+                    # Invoke the editor
+                    if {[catch {eval exec &gt;@stdout &lt;@stdin 2&gt;@stderr $editor {$portfile}} result]} {
+                        global errorInfo
+                        ui_debug &quot;$errorInfo&quot;
+                        break_softcontinue &quot;unable to invoke editor $editor: $result&quot; 1 status
+                    }
+                    
+                    # Restore internal MacPorts environment
+                    array unset env *
+                    if {${macports::macosx_version} eq &quot;10.5&quot;} {
+                        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] &quot;main.log&quot;]
+                    if {[file isfile $logfile]} {
+                        puts $logfile
+                    } else {
+                        ui_error &quot;Log file not found for port in $portdir&quot;
+                    }
+                }
+
+                gohome {
+                    set homepage &quot;&quot;
+
+                    # 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 &quot;&quot; &amp;&amp; ![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 &quot;&quot; } {
+                        if {[catch {system &quot;${macports::autoconf::open_path} '$homepage'&quot;} result]} {
+                            global errorInfo
+                            ui_debug &quot;$errorInfo&quot;
+                            break_softcontinue &quot;unable to invoke browser using ${macports::autoconf::open_path}: $result&quot; 1 status
+                        }
+                    } else {
+                        ui_error [format &quot;No homepage for %s&quot; $portname]
+                    }
+                }
+            }
+        } else {
+            break_softcontinue &quot;Could not read $portfile&quot; 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 &quot;$errorInfo&quot;
+        ui_msg &quot;port sync failed: $result&quot;
+        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 &quot;install&quot; || $action eq &quot;archive&quot;) &amp;&amp; [prefix_unwritable] &amp;&amp; ![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 &quot;&quot;} {
+            # Verify the portname, getting portinfo to map to a porturl
+            if {[catch {set res [mportlookup $portname]} result]} {
+                global errorInfo
+                ui_debug &quot;$errorInfo&quot;
+                break_softcontinue &quot;lookup of portname $portname failed: $result&quot; 1 status
+            }
+            if {[llength $res] &lt; 2} {
+                # don't error for ports that are installed but not in the tree
+                if {[registry::entry_exists_for_name $portname]} {
+                    ui_warn &quot;Skipping $portname (not in the ports tree)&quot;
+                    continue
+                } else {
+                    break_softcontinue &quot;Port $portname not found&quot; 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 &quot;&quot; &amp;&amp; [array get variations] ne &quot;&quot;} {
+            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 &quot;install&quot;} {
+            if {![info exists options(ports_install_unrequested)]} {
+                set options(ports_requested) 1
+            }
+            # we actually activate as well
+            set target activate
+        } elseif {$action eq &quot;archive&quot;} {
+            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 &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to open port: $result&quot; 1 status
+        }
+        if {[catch {set result [mportexec $workername $target]} result]} {
+            global errorInfo
+            mportclose $workername
+            ui_debug &quot;$errorInfo&quot;
+            break_softcontinue &quot;Unable to execute port: $result&quot; 1 status
+        }
+
+        mportclose $workername
+        
+        # Process any error that wasn't thrown and handled already
+        if {$result} {
+            print_tickets_url
+            break_softcontinue &quot;Processing of port $portname failed&quot; 1 status
+        }
+    }
+    
+    if {$status == 0 &amp;&amp; $action eq &quot;install&quot; &amp;&amp; ![macports::global_option_isset ports_dryrun]} {
+        array set options $opts
+        if {![info exists options(ports_nodeps)] &amp;&amp; ![info exists options(ports_install_no-rev-upgrade)] &amp;&amp; ${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 &lt; $cmd_argc}]
+}
+
+
+proc lookahead {} {
+    global cmd_argn cmd_argc cmd_argv
+    if {$cmd_argn &lt; $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 &quot;action&quot;.
+# 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 &quot;&quot;
+    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 &quot;&quot;
+    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 &quot;-&quot;} {
+            break
+        } elseif {[string index $arg 1] eq &quot;-&quot;} {
+            # 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 &quot;${action} does not accept --${key}&quot;
+                    } elseif {[llength $kopts] &gt; 1} {
+                        set errlst {}
+                        foreach e $kopts {
+                            lappend errlst &quot;--[lindex $e 0]&quot;
+                        }
+                        return -code error &quot;\&quot;port ${action} --${key}\&quot; is ambiguous: \n  port ${action} [join $errlst &quot;\n  port ${action} &quot;]&quot;
+                    }
+                    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] &amp;&amp; $kargc &gt; 0} {
+                            advance
+                            lappend args [lookahead]
+                            set kargc [expr {$kargc - 1}]
+                        }
+                        if {$kargc &gt; 0} {
+                            return -code error &quot;--${key} expects [expr {$kargc + [llength $args]}] parameters!&quot;
+                        }
+                        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]) &amp;&amp; [moreargs]} {
+        set action [lookahead]
+        advance
+        
+        # Handle command separator
+        if { $action == &quot;;&quot; } {
+            continue
+        }
+        
+        # Handle a comment
+        if { [string index $action 0] == &quot;#&quot; } {
+            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] &gt; 1} {
+                ui_error &quot;\&quot;port ${action}\&quot; is ambiguous: \n  port [join $actions &quot;\n  port &quot;]&quot;
+            } else {
+                ui_error &quot;Unrecognized action \&quot;port $action\&quot;&quot;
+            }
+            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 &quot;$errorInfo&quot;
+            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 &quot;$action does not accept string arguments&quot;
+                    set action_status 1
+                    break
+                } elseif {[ACTION_ARGS_STRINGS] == $expand} {
+                    while { [moreargs] &amp;&amp; ![match &quot;;&quot;] } {
+                        lappend portlist [lookahead]
+                        advance
+                    }
+                } elseif {[ACTION_ARGS_PORTS] == $expand} {
+                    # Parse port specifications into portlist
+                    if {![portExpr portlist]} {
+                        ui_error &quot;Improper expression syntax while processing parameters&quot;
+                        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 &quot;${text}*&quot; false glob]} result]} {
+            global errorInfo
+            ui_debug &quot;$errorInfo&quot;
+            fatal &quot;search for portname $pattern failed: $result&quot;
+        }
+        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 &quot;[string tolower $text]*&quot;]
+    }
+
+    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 &quot;[string tolower $text]*&quot;]
+
+    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 &quot;&quot;
+    }
+
+    # 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 &quot;&quot;
+    while { $line eq &quot;&quot; } {
+
+        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 &lt; 0 } {
+            return -1
+        }
+        
+        set line [string trim $line]
+
+        if { $use_readline &amp;&amp; $line ne &quot;&quot; } {
+            rl_history add $line
+        }
+    }
+    
+    return [llength $line]
+}
+
+
+proc process_command_file { in } {
+    global current_portdir
+
+    # Initialize readline
+    set isstdin [string match $in &quot;stdin&quot;]
+    set name &quot;port&quot;
+    set use_readline [expr {$isstdin &amp;&amp; [readline init $name]}]
+    set history_file [file normalize &quot;${macports::macports_user_dir}/history&quot;]
+
+    # Read readline history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history read $history_file
+        rl_history stifle 100
+    }
+
+    # Be noisy, if appropriate
+    set noisy [expr $isstdin &amp;&amp; ![macports::ui_isset ports_quiet]]
+    if { $noisy } {
+        puts &quot;MacPorts [macports::version]&quot;
+        puts &quot;Entering interactive mode... (\&quot;help\&quot; for help, \&quot;quit\&quot; to quit)&quot;
+    }
+
+    # 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 &quot;\[$shortdir\] &gt; &quot;
+        } else {
+            set prompt &quot;&quot;
+        }
+
+        # Get a command line
+        if { [get_next_cmdline $in stdout $use_readline $prompt line] &lt;= 0  } {
+            puts &quot;&quot;
+            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 &amp;&amp; ![file isdirectory $macports::macports_user_dir]} {
+        file mkdir $macports::macports_user_dir
+    }
+    # Save readine history
+    if {$use_readline &amp;&amp; [file isdirectory $macports::macports_user_dir]} {
+        rl_history write $history_file
+    }
+
+    # Say goodbye
+    if { $noisy } {
+        puts &quot;Goodbye&quot;
+    }
+
+    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 &quot;-&quot;} {
+            set in stdin
+        } else {
+            if {[catch {set in [open $file]} result]} {
+                fatal &quot;Failed to open command file; $result&quot;
+            }
+        }
+
+        set exit_status [process_command_file $in]
+
+        if {$in ne &quot;stdin&quot;} {
+            close $in
+        }
+
+        # Exit on first failure unless -p was given
+        if {$exit_status != 0 &amp;&amp; ![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
+    #        &quot;yes&quot;, if the progress indicator should be shown, &quot;no&quot; otherwise.
+    proc showProgress {cur total} {
+        variable show
+        variable startTime
+        variable showTimeThreshold
+        variable showPercentageThreshold
+
+        if {$show eq &quot;yes&quot;} {
+            return yes
+        } else {
+            if {[expr {[clock milliseconds] - $startTime}] &gt; $showTimeThreshold &amp;&amp;
+                ($total == 0 || [expr {double($cur) / double($total)}] &lt; $showPercentageThreshold)} {
+                set show yes
+            }
+            return $show
+        }
+    }
+
+    ##
+    # Progress callback for generic operations executed by macports 1.0.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot;, &quot;intermission&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        &quot;intermission&quot; and &quot;finish&quot;, the args are empty and unused. For
+    #        &quot;update&quot;, 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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        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 &quot;\r&quot;
+                flush stdout
+            }
+        }
+
+        return 0
+    }
+
+    ##
+    # Progress callback for downloads executed by macports 1.0.
+    #
+    # This is essentially a cURL progress callback.
+    #
+    # @param action
+    #        One of &quot;start&quot;, &quot;update&quot; or &quot;finish&quot;, 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 &quot;start&quot;,
+    #        contains a single argument &quot;ul&quot; or &quot;dl&quot; indicating whether this is
+    #        an up- or download. For &quot;update&quot;, contains the arguments
+    #        (&quot;ul&quot;|&quot;dl&quot;) $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 &quot;finish&quot;.
+    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 &quot;yes&quot;} {
+                        set barPrefix &quot;      &quot;
+                        set barPrefixLen [string length $barPrefix]
+                        if {$total != 0} {
+                            set barSuffix [format &quot;        speed: %-13s&quot; &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            set barSuffixLen [string length $barSuffix]
+
+                            set barLen [expr {min($maxWidth, $env(COLUMNS) - $barPrefixLen - $barSuffixLen)}]
+                            progressbar $now $total $barLen $barPrefix $barSuffix
+                        } else {
+                            set barSuffix [format &quot; %-10s     speed: %-13s&quot; [bytesize $now {} &quot;%6.1f&quot;] &quot;[bytesize $speed {} &quot;%.1f&quot;]/s&quot;]
+                            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 &quot;\r&quot;
+                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 &quot;&quot;} {suffix &quot;&quot;}} {
+        # 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 &quot;\033\[7m&quot;
+        for {set i 0} {$i &lt; $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 &quot; &quot;
+        }
+        # back to normal output
+        append progressbar &quot;\033\[0m&quot;
+
+        #switch $barRemainder {
+        #    0 {
+        #        if {$barInteger &lt; $barWidth} {
+        #            append progressbar &quot; &quot;
+        #        }
+        #    }
+        #    1 {
+        #        # U+258F LEFT ONE EIGHTH BLOCK
+        #        append progressbar &quot;\u258f&quot;
+        #    }
+        #    2 {
+        #        # U+258E LEFT ONE QUARTER BLOCK
+        #        append progressbar &quot;\u258e&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    3 {
+        #        # U+258D LEFT THREE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258d&quot;
+        #    }
+        #    4 {
+        #        # U+258C LEFT HALF BLOCK
+        #        append progressbar &quot;\u258c&quot;
+        #    }
+        #    5 {
+        #        # U+258B LEFT FIVE EIGHTHS BLOCK
+        #        append progressbar &quot;\u258b&quot;
+        #    }
+        #    6 {
+        #        # U+258A LEFT THREE QUARTERS BLOCK
+        #        append progressbar &quot;\u258a&quot;
+        #    }
+        #    7 {
+        #        # U+2589 LEFT SEVEN EIGHTHS BLOCK
+        #        append progressbar &quot;\u2589&quot;
+        #    }
+        #}
+
+        # Fill the progress bar with spaces
+        for {set i $barInteger} {$i &lt; $barWidth} {incr i} {
+            append progressbar &quot; &quot;
+        }
+
+        # Format the percentage using the space that has been reserved for it
+        set percentagesuffix [format &quot; %[expr {$percentageWidth - 3}].1f %%&quot; $percentage]
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${percentagesuffix}${suffix}&quot;
+        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 &quot;&quot;} {suffix &quot;&quot;}} {
+        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 &quot;&quot;
+        for {set i 0} {$i &lt; $barWidth} {incr i} {
+            if {[expr {$i % $numStates}] == $unprogressState} {
+                # U+2022 BULLET
+                append progressbar &quot;\u2022&quot;
+            } else {
+                append progressbar &quot; &quot;
+            }
+        }
+
+        puts -nonewline &quot;\r${prefix}\[${progressbar}\]${suffix}&quot;
+        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] &gt; 0} {
+            ui_notice &quot;---&gt;  Some of the ports you installed have notes:&quot;
+            foreach {name notes} [array get notificationsToPrint] {
+                ui_notice &quot;  $name has the following notes:&quot;
+
+                # 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 &quot;\n&quot;] {
+                            set joiner &quot;&quot;
+                            set lines &quot;&quot;
+                            set newline &quot;    &quot;
+
+                            foreach word [split $line &quot; &quot;] {
+                                if {[string length $newline] + [string length $word] &gt;= $maxlen} {
+                                    lappend lines $newline
+                                    set newline &quot;    &quot;
+                                    set joiner &quot;&quot;
+                                }
+                                ::append newline $joiner $word
+                                set joiner &quot; &quot;
+                            }
+                            if {$newline ne {}} {
+                                lappend lines $newline
+                            }
+                            ui_notice [join $lines &quot;\n&quot;]
+                        }
+                    }
+                } 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] &amp;&amp; $cmdname eq &quot;portf&quot;} {
+    lappend ui_options(ports_commandfiles) [lookahead]
+    advance
+}
+
+# Parse global options that will affect all subsequent commands
+if {[catch {parse_options &quot;global&quot; ui_options global_options} result]} {
+    puts &quot;Error: $result&quot;
+    print_usage
+    exit 1
+}
+
+if {[isatty stdout]
+    &amp;&amp; $portclient::progress::hasTermAnsiSend eq &quot;yes&quot;
+    &amp;&amp; (![info exists ui_options(ports_quiet)] || $ui_options(ports_quiet) ne &quot;yes&quot;)} {
+    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 &amp;&amp; ![info exists ui_options(ports_commandfiles)] } {
+    lappend ui_options(ports_commandfiles) -
+} elseif {[lookahead] eq &quot;selfupdate&quot; || [lookahead] eq &quot;sync&quot;} {
+    # 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 &quot;$errorInfo&quot;
+    fatal &quot;Failed to initialize MacPorts, $result&quot;
+}
+
+# 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] &gt; 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]) &amp;&amp; [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
</ins></span></pre>
</div>
</div>

</body>
</html>