Added rantest and cqtool to repo
[clearscm.git] / cqtool / cqtool.pl
diff --git a/cqtool/cqtool.pl b/cqtool/cqtool.pl
new file mode 100755 (executable)
index 0000000..3c85914
--- /dev/null
@@ -0,0 +1,780 @@
+#!/usr/bin/env /opt/rational/clearquest/bin/cqperl\r
+##############################################################################\r
+#\r
+# Name: cqtool\r
+#\r
+# Description: cqtool is an interface to Clearquest to perform some simple\r
+#              actions to the RANCQ database. It is used primarily by ucmwb\r
+#              but it also supports a command line interface.\r
+#\r
+#              The following commands are supported:\r
+#\r
+#              activate <wor> <project> <est_hours> <startdate> <enddate>:\r
+#                      Activate WOR\r
+#              assign <wor> <assignee> <project> <planned_hours> <startdate>:\r
+#                      Assign the WOR\r
+#              clone <wor>:\r
+#                      Clones a WOR\r
+#              comment <wor> <comment>\r
+#                      Add a comment to the Notes_Entry field for the WOR\r
+#              complete <wor> <actual_hours>:\r
+#                      Complete WOR\r
+#              createhd:\r
+#                      Create a new Help Desk Ticket\r
+#              createwor:\r
+#                      Create a new WOR\r
+#              effort <wor> <hours>:\r
+#                      Update the WOR's actual hours\r
+#              exit|quit:\r
+#                      Exits cqtool\r
+#              help:\r
+#                      This display\r
+#              link <parent wor> <child wor>:\r
+#                      Link a parent WOR to a child WOR\r
+#              resolve <wor>:\r
+#                      Resolve WOR\r
+#              set <wor> <field> <value>\r
+#                      Set <field> to <value> for the <wor>\r
+#              usage:\r
+#                      Displays command line usage\r
+#              version:\r
+#                      Displays version of cqtool\r
+#\r
+#              Many of these commands simply perform actions on a wor. Two\r
+#              of these commands, createwor and createhd have Perl/Tk GUI\r
+#              interfaces.\r
+#\r
+# Command line usage:\r
+#\r
+# Usage: cqtool\t[-usage|help] [-verbose] [-debug]\r
+#      [-userid <user>] [-password <password>] [<command>]\r
+#\r
+# Where:\r
+#\r
+#   -usage|help:       Display usage\r
+#   -verbose:          Turn on verbose mode\r
+#   -debug:            Turn on debug mode\r
+#   -userid:           User ID to log into Clearquest database as\r
+#   -password:         Password to use\r
+#   <command>          If specified then cqtool executes <command> and\r
+#                      exits\r
+#\r
+# Environment:         cqtool supports the following environment variables\r
+#                      that are used mostly for tesing purposes\r
+#\r
+#      CQ_DBSET:       Clearquest DBSET to open (e.g. XTST3 for testing -\r
+#                      default RANCQ)  \r
+#      CQ_USER:        User name to log into the $CQ_DBSET database with\r
+#      CQ_PASSWORD:    Password to use to log into the $CQ_DBSET with.\r
+#\r
+# Author: Andrew@DeFaria.com\r
+#\r
+# (c) Copyright 2007, General Dynamics, all rights reserved\r
+#\r
+##############################################################################\r
+use strict;\r
+use warnings;\r
+\r
+use CQPerlExt;\r
+use FindBin;\r
+use Getopt::Long;\r
+use Term::ANSIColor qw (:constants);\r
+\r
+use lib ("$FindBin::Bin", "$FindBin::Bin/../lib");\r
+\r
+use SCCM::Misc;\r
+use Display;\r
+use CQTool;\r
+use CreateWORUI;\r
+use CreateHelpDeskUI;\r
+use Logger;\r
+\r
+my $VERSION            = BOLD GREEN . "1.1" . RESET;\r
+my $PROMPT             = BOLD YELLOW . ">>" . RESET;\r
+my $UCMWB_PROMPT       = ">>";\r
+my $DESC               = BOLD RED . "$FindBin::Script" .\r
+                         RESET      " Version " .\r
+                         $VERSION .\r
+                         CYAN ": Program to talk to Clearquest" .\r
+                         RESET;\r
+\r
+# Globals\r
+my $_userid    = $ENV{CQ_USER}  ? $ENV{CQ_USER} : $ENV{USER};\r
+my $_password  = $ENV{CQ_PASSWORD};\r
+my $_db_name   = $ENV{CQ_DBSET} ? $ENV{CQ_DBSET} : "RANCQ";\r
+my $_ucmwb;\r
+\r
+my $_log;\r
+\r
+if (get_debug) {\r
+  $_log = new Logger (\r
+    path => "/tmp",\r
+    append => 1,\r
+  );\r
+} # if\r
+\r
+my %_commands = (\r
+  activate     => \&activate,\r
+  assign       => \&assign,\r
+  clone                => \&clone,\r
+  comment      => \&comment,\r
+  complete     => \&complete,\r
+  createhd     => \&createHelpDesk,\r
+  createwor    => \&createWOR,\r
+  effort       => \&effort,\r
+  exit         => \&shutdown,\r
+  help         => \&help,\r
+  link         => \&linkParentWor2ChildWor,\r
+  quit         => \&shutdown,\r
+  resolve      => \&resolve,\r
+  set          => \&set,\r
+  usage                => \&usage,\r
+  version      => \&announce,\r
+);\r
+\r
+##############################################################################\r
+# Forwards\r
+##############################################################################\r
+sub commandLoop (@);\r
+\r
+##############################################################################\r
+# Main\r
+##############################################################################\r
+MAIN: {\r
+  GetOptions (\r
+    "usage"            => sub { usage () },\r
+    "verbose"          => sub { set_verbose () },\r
+    "debug"            => sub { set_debug () },\r
+    "userid=s"         => \$_userid,\r
+    "password=s"       => \$_password,\r
+    "database=s"       => \$_db_name,\r
+    "ucmwb"            => \$_ucmwb,\r
+  ) || usage ();\r
+\r
+  exit (commandLoop(@ARGV));\r
+} # MAIN\r
+\r
+##############################################################################\r
+# Subroutines\r
+##############################################################################\r
+\r
+#-----------------------------------------------------------------------------\r
+# shutdown (): Ends program\r
+#-----------------------------------------------------------------------------\r
+sub shutdown () {\r
+  exit (0);\r
+} # exit\r
+\r
+#-----------------------------------------------------------------------------\r
+# help (): Displays help\r
+#-----------------------------------------------------------------------------\r
+sub help () {\r
+  display ($DESC);\r
+  display <<END;\r
+\r
+Valid commands are:\r
+\r
+activate <wor> <project> <est_hours> <startdate> <enddate>:\r
+       Activate WOR\r
+assign <wor> <assignee> <project> <planned_hours> <startdate>:\r
+       Assign the WOR\r
+clone <wor>:\r
+       Clones a WOR\r
+comment <wor> <comment>\r
+       Add a comment to the Notes_Entry field for the WOR\r
+complete <wor> <actual_hours>:\r
+       Complete WOR\r
+createhd:\r
+       Create a new Help Desk Ticket\r
+createwor:\r
+       Create a new WOR\r
+effort <wor> <hours>:\r
+       Update the WOR's actual hours\r
+exit|quit:\r
+       Exits $FindBin::Script\r
+help:\r
+       This display\r
+link <parent wor> <child wor>:\r
+       Link a parent WOR to a child WOR\r
+resolve <wor>:\r
+       Resolve WOR\r
+set <wor> <field> <value>\r
+       Set <field> to <value> for the <wor>\r
+usage:\r
+       Displays command line usage\r
+version:\r
+       Displays version of $FindBin::Script\r
+END\r
+} # help\r
+\r
+#-----------------------------------------------------------------------------\r
+# announce (): Announce ourselves\r
+#-----------------------------------------------------------------------------\r
+sub announce () {\r
+  display ($DESC);\r
+} # Announce\r
+\r
+#-----------------------------------------------------------------------------\r
+# dberror ($): Handle errors when talking to Clearquest. Note we need to reset\r
+#             the database connection if an error happens.\r
+#-----------------------------------------------------------------------------\r
+sub dberror ($) {\r
+  my ($msg) = @_;\r
+\r
+  # Need to not only report the error but to reopen the\r
+  # database. Something gets corruppted if we don't!\r
+  error ($msg);\r
+\r
+  closeDB ();\r
+\r
+  openDB ($_userid, $_password, $_db_name);\r
+} # DBError\r
+\r
+#-----------------------------------------------------------------------------\r
+# getEntity ($$): Get an entity from Clearquest\r
+#-----------------------------------------------------------------------------\r
+sub getEntity ($$) {\r
+  my ($recordname, $wor) = @_;\r
+\r
+  my $entity;\r
+\r
+  eval {\r
+    $entity = $CQTool::session->GetEntity ($recordname, $wor);\r
+  };\r
+\r
+  if ($@) {\r
+    chomp $@;\r
+    dberror ($@);\r
+    return undef;\r
+  } else {\r
+    return $entity;\r
+  } # if\r
+} # getEntity\r
+\r
+#-----------------------------------------------------------------------------\r
+# set ($$$): Set $field to $value for $wor\r
+#-----------------------------------------------------------------------------\r
+sub set ($$@) {\r
+  my ($wor, $field, $value) = @_;\r
+\r
+  if (!$wor or $wor eq "") {\r
+    error ("WOR is required");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$field or $field eq "") {\r
+    error ("Field is required");\r
+    return 1;\r
+  } # if\r
+\r
+  my $entity   = getEntity ("WOR", $wor);\r
+\r
+  return 1 if !$entity;\r
+\r
+  $session->EditEntity ($entity, "modify");\r
+\r
+  $_log->msg ("Modifying $field to \"$value\"") if get_debug;\r
+  eval {\r
+    $entity->SetFieldValue ($field, $value);\r
+  };\r
+\r
+  if ($@) {\r
+    dberror ("$field set failed for WOR $wor:\n$@");\r
+    return 2;\r
+  } # if\r
+\r
+  my $status = $entity->Validate ();\r
+\r
+  if ($status ne "") {\r
+    $entity->Revert ();\r
+    error ("$field validate failed for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+  $status = $entity->Commit ();\r
+\r
+  if ($status ne "") {\r
+    error ("$field update failed during Submit for $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+   return 0;\r
+} # set\r
+\r
+#-----------------------------------------------------------------------------\r
+# clone ($): Clone a WOR\r
+#-----------------------------------------------------------------------------\r
+sub clone ($) {\r
+  my ($wor) = @_;\r
+\r
+  if (!$wor) {\r
+    error ("WOR not specified!");\r
+    return 1;\r
+  } # if\r
+\r
+  $entity = getEntity ("WOR", $wor);\r
+\r
+  return 1 if !$entity;\r
+\r
+  # Check state\r
+  my $state = $entity->GetFieldValue ("state")->GetValue ();\r
+\r
+  if ($state ne "Closed") {\r
+    error ("WOR $wor not closed - Unable to clone!");\r
+    return 1;\r
+  } # if\r
+\r
+  verbose ("Cloning WOR $wor...");\r
+\r
+  my $result = 0;\r
+\r
+  eval {\r
+    # Currently Clone doesn't return a proper result but eventually...\r
+    $result = $CQTool::session->FireRecordScriptAlias ($entity, "Clone");\r
+  };\r
+\r
+  if ($@) {\r
+    chomp $@;\r
+    dberror ($@);\r
+    return 1;\r
+  } # if\r
+\r
+  return $result;\r
+} # clone\r
+\r
+#-----------------------------------------------------------------------------\r
+# effort ($$): Update actual hours for a WOR\r
+#-----------------------------------------------------------------------------\r
+sub effort ($$) {\r
+  my ($wor, $actualHrs) = @_;\r
+\r
+  return set $wor, "ActualEffort", $actualHrs;\r
+} # effort\r
+\r
+#-----------------------------------------------------------------------------\r
+# comment (): Update the Notes_Entry comment field for a WOR\r
+#-----------------------------------------------------------------------------\r
+sub comment ($) {\r
+  my ($wor) = @_;\r
+\r
+  if (!$wor) {\r
+    error "WOR not defined in call to comment!";\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$_ucmwb) {\r
+    display ("Enter comments below. When finished, enter \".\" on a line by itself or hit ^D:");\r
+  } else {\r
+    # We still need to prompt for the comments however signal UCMWB\r
+    # that command is ready for more input.\r
+    display_nolf ($UCMWB_PROMPT);\r
+  } # if\r
+\r
+  my $comments;\r
+\r
+  while (<STDIN>) {\r
+    last if $_ eq ".\n";\r
+    $comments .= $_;\r
+  } # while\r
+\r
+  chomp $comments;\r
+\r
+  $_log->msg ("Comments:\n$comments") if get_debug;\r
+\r
+  return set $wor, "Note_Entry", $comments;\r
+} # Comment\r
+\r
+#-----------------------------------------------------------------------------\r
+# linkParentWor2ChildWor ($$): Link a child WOR to a parent WOR\r
+#-----------------------------------------------------------------------------\r
+sub linkParentWor2ChildWor ($$) {\r
+  my ($parentWor, $childWor) = @_;\r
+\r
+  my $status;\r
+\r
+  verbose ("Linking $parentWor -> $childWor...");\r
+\r
+  my $childentity      = getEntity ("WOR", $childWor);\r
+  my $parententity     = getEntity ("WOR", $parentWor);\r
+\r
+  return 1 unless $childentity and $parententity;\r
+\r
+  $session->EditEntity ($parententity, "modify");\r
+\r
+  $parententity->AddFieldValue ("wor_children", $childWor);\r
+\r
+  $status = $parententity->Validate ();\r
+\r
+  if ($status ne "") {\r
+    $parententity->Revert ();\r
+    error ("Validation failed while attempting to add child WOR $childWor to parent WOR $parentWor:\n$status");\r
+    return 1;\r
+  } # if\r
+\r
+  eval {\r
+    $status = $parententity->Commit ();\r
+  };\r
+\r
+  $status = $@ if $@;\r
+\r
+  if ($status ne "") {\r
+    (error "Commit failed while trying to add child WOR $childWor to parent WOR $parentWor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+  debug "Modifying child $childWor...";\r
+  $session->EditEntity ($childentity, "modify");\r
+\r
+  $childentity->SetFieldValue ("wor_parent", $parentWor);\r
+\r
+  $status = $childentity->Validate ();\r
+\r
+  if ($status ne "") {\r
+    $childentity->Revert ();\r
+    error "Validation failed while attempting to add parent WOR $parentWor to child WOR $childWor:\n$status";\r
+    return 1;\r
+  } # if\r
+\r
+  eval {\r
+    $status = $childentity->Commit ();\r
+  };\r
+\r
+  $status = $@ if $@;\r
+\r
+  if ($status ne "") {\r
+    error "Commit failed while trying to add parent WOR $parentWor to child WOR $childWor:\n$status";\r
+    return 2;\r
+  } # if\r
+\r
+  return 0;\r
+} # linkParentWor2ChildWor\r
+\r
+#-----------------------------------------------------------------------------\r
+# assign ($$$$): Assign a WOR\r
+#-----------------------------------------------------------------------------\r
+sub assign ($$$$$) {\r
+  my ($wor, $assignee, $project, $plannedHrs, $startDate) = @_;\r
+\r
+  if (!$wor or $wor eq "") {\r
+    error ("WOR is required");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$assignee or $assignee eq "") {\r
+    error ("Assignee must be specified");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$project or $project eq "") {\r
+    error ("UCM Project is required");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$startDate or $startDate eq "") {\r
+    error ("Planned Start Date is required");\r
+    return 1;\r
+  } # if\r
+\r
+  my $entity   = getEntity ("WOR", $wor);\r
+\r
+  return 1 if !$entity;\r
+\r
+  my $state    = $entity->GetFieldValue ("state")->GetValue ();\r
+\r
+  if ($state ne "Submitted") {\r
+    error ("WOR $wor is not in Submitted state!\nState: $state");\r
+    return 2;\r
+  } # if\r
+\r
+  $session->EditEntity ($entity, "assign");\r
+\r
+  $entity->SetFieldValue ("ucm_project",       $project)       if $project     ne "";\r
+  $entity->SetFieldValue ("PlannedStart",      $startDate)     if $startDate   ne "";\r
+  $entity->SetFieldValue ("PlannedEffort",     $plannedHrs)    if $plannedHrs  ne "";\r
+  $entity->SetFieldValue ("Owner",             $assignee)      if $assignee    ne "";\r
+\r
+  my $status = $entity->Validate ();\r
+\r
+  if ($status ne "") {\r
+    $entity->Revert ();\r
+    error ("Assign failed for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+  $status = $entity->Commit ();\r
+\r
+  if ($status ne "") {\r
+    error ("Assign failed during Submit for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+  return 0;\r
+} # assign\r
+\r
+#-----------------------------------------------------------------------------\r
+# activate (): Activate a WOR\r
+#-----------------------------------------------------------------------------\r
+sub activate ($$$$$) {\r
+  my ($wor, $project, $estHrs, $startDate, $endDate) = @_;\r
+\r
+  if (!$wor or $wor eq "") {\r
+    error ("WOR is required");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$project or $project eq "") {\r
+    error ("UCM Project is required");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$startDate or $startDate eq "") {\r
+    error ("Planned Start Date is required");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$endDate or $endDate eq "") {\r
+    error ("Planned End Date is required");\r
+    return 1;\r
+  } # if\r
+\r
+  my $entity   = getEntity ("WOR", $wor);\r
+\r
+  return 1 if !$entity;\r
+\r
+  my $state    = $entity->GetFieldValue ("state")->GetValue ();\r
+\r
+  if ($state ne "Assessing") {\r
+    error ("WOR $wor is not in Assessing state!\nstate: $state");\r
+    return 2;\r
+  } # if\r
+\r
+  $session->EditEntity ($entity, "activate");\r
+\r
+  $entity->SetFieldValue ("ucm_project",       $project)       if $project ne "";\r
+  $entity->SetFieldValue ("EstimatedEffort",   $estHrs)        if $estHrs ne "";\r
+  $entity->SetFieldValue ("PlannedStart",      $startDate)     if $startDate ne "";\r
+  $entity->SetFieldValue ("PlannedEnd",                $endDate)       if $endDate ne "";\r
+\r
+  my $status = $entity->Validate ();\r
+\r
+  if ($status ne "") {\r
+    $entity->Revert ();\r
+    error ("Activate failed for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+  $status = $entity->Commit ();\r
+\r
+  if ($status ne "") {\r
+    error ("Activate failed during Submit for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+   return 0;\r
+} # activate\r
+\r
+#-----------------------------------------------------------------------------\r
+# resolve ($): Resolve a WOR\r
+#-----------------------------------------------------------------------------\r
+sub resolve ($) {\r
+  my ($wor) = @_;\r
+\r
+  if (!$wor or $wor eq "") {\r
+    error ("WOR is required");\r
+    return 1;\r
+  } # if\r
+\r
+  my $entity   = getEntity ("WOR", $wor);\r
+\r
+  return 1 if !$entity;\r
+\r
+  my $state    = $entity->GetFieldValue ("state")->GetValue ();\r
+\r
+  if ($state ne "Working") {\r
+    error ("WOR $wor is not in Working state!\nState: $state");\r
+    return 2;\r
+  } # if\r
+\r
+  $session->EditEntity ($entity, "resolve");\r
+\r
+  my $status = $entity->Validate ();\r
+\r
+  if ($status ne "") {\r
+    $entity->Revert ();\r
+    error ("Resolve failed for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+  $status = $entity->Commit ();\r
+\r
+  if ($status ne "") {\r
+    error ("Resolve failed during Submit for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+   return 0;\r
+} # resolve\r
+\r
+#-----------------------------------------------------------------------------\r
+# complete ($$): Complete a WOR\r
+#-----------------------------------------------------------------------------\r
+sub complete ($$) {\r
+  my ($wor, $actualHrs) = @_;\r
+\r
+  if (!$wor or $wor eq "") {\r
+    error ("WOR is required");\r
+    return 1;\r
+  } # if\r
+\r
+  if (!$wor or $wor eq "") {\r
+    error ("Actual Hours are required");\r
+    return 1;\r
+  } # if\r
+\r
+  my $entity   = getEntity ("WOR", $wor);\r
+\r
+  return 1 if !$entity;\r
+\r
+  my $state    = $entity->GetFieldValue ("state")->GetValue ();\r
+\r
+  if ($state ne "Verifying") {\r
+    error ("WOR $wor is not in Verifying state!\nState:$state");\r
+    return 2;\r
+  } # if\r
+\r
+  $session->EditEntity ($entity, "complete");\r
+  $entity->SetFieldValue ("ActualEffort", $actualHrs) if $actualHrs ne "";\r
+\r
+  my $status = $entity->Validate ();\r
+\r
+  if ($status ne "") {\r
+    $entity->Revert ();\r
+    error ("Complete failed for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+  $status = $entity->Commit ();\r
+\r
+  if ($status ne "") {\r
+    error ("Complete failed during Submit for WOR $wor:\n$status");\r
+    return 2;\r
+  } # if\r
+\r
+   return 0;\r
+} # Complete\r
+\r
+#-----------------------------------------------------------------------------\r
+# executeCommand (@): Executes a cqtool command\r
+#-----------------------------------------------------------------------------\r
+sub executeCommand (@) {\r
+  my (@args) = @_;\r
+\r
+  my $cmd = lc shift @args;\r
+\r
+  return if $cmd eq "";\r
+\r
+  if ($_commands{$cmd}) {\r
+    if (!$CQTool::session) {\r
+      if ( # Commands that do not require a database connection\r
+         !($cmd eq "exit"      or\r
+           $cmd eq "quit"      or\r
+           $cmd eq "help"      or\r
+           $cmd eq "usage"     or\r
+           $cmd eq "verbose")) {\r
+       verbose "Opening $_db_name as $_userid...";\r
+\r
+       if (!$_password) {\r
+         display_nolf ("${_userid}'s password:");\r
+         `stty -echo`;\r
+         $_password = <STDIN>;\r
+         chomp $_password;\r
+         display ("");\r
+         `stty echo`;\r
+       } # if\r
+\r
+       openDB ($_userid, $_password, $_db_name);\r
+      } # if\r
+    } # if\r
+\r
+    # Treat args: Args that are enclosed in quotes must be\r
+    # combined. For simplicity's sake we will only support matched\r
+    # pairs of double quotes. Anything else results in undefined\r
+    # behavior.\r
+    my (@new_args);\r
+\r
+    foreach (@args) {\r
+      # Quoted argument starting\r
+      if (/^\"(.*)\"$/s) {\r
+       push @new_args, $1;\r
+      } else {\r
+       push @new_args, $_;\r
+      } # if\r
+    } # foreach\r
+\r
+    $_log->msg ("$cmd (" . join (",", @new_args) . ")") if get_debug;\r
+\r
+    return $_commands{$cmd} (@new_args);\r
+  } else {\r
+    error ("Unknown command \"$cmd\" (try help)");\r
+    return 1;\r
+  } # if\r
+} # executeCommand\r
+\r
+#-----------------------------------------------------------------------------\r
+# commandLoop (@): This is the interactive command loop\r
+#-----------------------------------------------------------------------------\r
+sub commandLoop (@) {\r
+  my (@args) = @_;\r
+\r
+  # For single, command line, commands...\r
+  return executeCommand (@args) if @args;\r
+\r
+  announce if !$_ucmwb;\r
+\r
+  while () {\r
+    if (!$_ucmwb) {\r
+      display_nolf ($PROMPT . RESET . UNDERLINE);\r
+    } else {\r
+      display_nolf ($UCMWB_PROMPT);\r
+    } # if\r
+\r
+    # Read command into $_\r
+    $_ = <STDIN>;\r
+    chomp;\r
+\r
+    # If we are not being called by ucmwb, display RESET to stop the\r
+    # UNDERLINE we were using. This keeps the output from being\r
+    # underlined. In ucmwb mode we are not using any of the terminal\r
+    # sequences.\r
+    display_nolf (RESET) if !$_ucmwb;\r
+\r
+    # If the user hit Control-d then a ^D is displayed but we remain\r
+    # on the same line. So output a carriage return and exit 0.\r
+    if (!$_) {\r
+      display ("");\r
+      exit 0;\r
+    } # if\r
+\r
+    # Special handling for set command since we want to take\r
+    # everything after <field> to be a value, and we may get long\r
+    # values that are space separated and space significant\r
+    # (e.g. description?)\r
+    if (/^\s*(\w+)\s+(\w+)\s+(\w+)\s+(.*)/) {\r
+      if (lc $1 eq "set") {\r
+       my $cmd         = $1;\r
+       my $wor         = $2;\r
+       my $field       = $3;\r
+       my $value       = $4;\r
+\r
+       # Change "\n"'s back to \n's\r
+       $value =~ s/\\n/\n/g;\r
+\r
+       executeCommand ($cmd, $wor, $field, "\"$value\"");\r
+      } else {\r
+       executeCommand (split);\r
+      } # if\r
+    } else {\r
+      executeCommand (split);\r
+    } # if\r
+  } # while\r
+} # commandLoop\r