Added rantest and cqtool to repo
[clearscm.git] / cqtool / cqtool.pl
1 #!/usr/bin/env /opt/rational/clearquest/bin/cqperl\r
2 ##############################################################################\r
3 #\r
4 # Name: cqtool\r
5 #\r
6 # Description:  cqtool is an interface to Clearquest to perform some simple\r
7 #               actions to the RANCQ database. It is used primarily by ucmwb\r
8 #               but it also supports a command line interface.\r
9 #\r
10 #               The following commands are supported:\r
11 #\r
12 #               activate <wor> <project> <est_hours> <startdate> <enddate>:\r
13 #                       Activate WOR\r
14 #               assign <wor> <assignee> <project> <planned_hours> <startdate>:\r
15 #                       Assign the WOR\r
16 #               clone <wor>:\r
17 #                       Clones a WOR\r
18 #               comment <wor> <comment>\r
19 #                       Add a comment to the Notes_Entry field for the WOR\r
20 #               complete <wor> <actual_hours>:\r
21 #                       Complete WOR\r
22 #               createhd:\r
23 #                       Create a new Help Desk Ticket\r
24 #               createwor:\r
25 #                       Create a new WOR\r
26 #               effort <wor> <hours>:\r
27 #                       Update the WOR's actual hours\r
28 #               exit|quit:\r
29 #                       Exits cqtool\r
30 #               help:\r
31 #                       This display\r
32 #               link <parent wor> <child wor>:\r
33 #                       Link a parent WOR to a child WOR\r
34 #               resolve <wor>:\r
35 #                       Resolve WOR\r
36 #               set <wor> <field> <value>\r
37 #                       Set <field> to <value> for the <wor>\r
38 #               usage:\r
39 #                       Displays command line usage\r
40 #               version:\r
41 #                       Displays version of cqtool\r
42 #\r
43 #               Many of these commands simply perform actions on a wor. Two\r
44 #               of these commands, createwor and createhd have Perl/Tk GUI\r
45 #               interfaces.\r
46 #\r
47 # Command line usage:\r
48 #\r
49 # Usage: cqtool\t[-usage|help] [-verbose] [-debug]\r
50 #       [-userid <user>] [-password <password>] [<command>]\r
51 #\r
52 # Where:\r
53 #\r
54 #   -usage|help:        Display usage\r
55 #   -verbose:           Turn on verbose mode\r
56 #   -debug:             Turn on debug mode\r
57 #   -userid:            User ID to log into Clearquest database as\r
58 #   -password:          Password to use\r
59 #   <command>           If specified then cqtool executes <command> and\r
60 #                       exits\r
61 #\r
62 # Environment:          cqtool supports the following environment variables\r
63 #                       that are used mostly for tesing purposes\r
64 #\r
65 #       CQ_DBSET:       Clearquest DBSET to open (e.g. XTST3 for testing -\r
66 #                       default RANCQ)  \r
67 #       CQ_USER:        User name to log into the $CQ_DBSET database with\r
68 #       CQ_PASSWORD:    Password to use to log into the $CQ_DBSET with.\r
69 #\r
70 # Author: Andrew@DeFaria.com\r
71 #\r
72 # (c) Copyright 2007, General Dynamics, all rights reserved\r
73 #\r
74 ##############################################################################\r
75 use strict;\r
76 use warnings;\r
77 \r
78 use CQPerlExt;\r
79 use FindBin;\r
80 use Getopt::Long;\r
81 use Term::ANSIColor qw (:constants);\r
82 \r
83 use lib ("$FindBin::Bin", "$FindBin::Bin/../lib");\r
84 \r
85 use SCCM::Misc;\r
86 use Display;\r
87 use CQTool;\r
88 use CreateWORUI;\r
89 use CreateHelpDeskUI;\r
90 use Logger;\r
91 \r
92 my $VERSION             = BOLD GREEN . "1.1" . RESET;\r
93 my $PROMPT              = BOLD YELLOW . ">>" . RESET;\r
94 my $UCMWB_PROMPT        = ">>";\r
95 my $DESC                = BOLD RED . "$FindBin::Script" .\r
96                           RESET      " Version " .\r
97                           $VERSION .\r
98                           CYAN ": Program to talk to Clearquest" .\r
99                           RESET;\r
100 \r
101 # Globals\r
102 my $_userid     = $ENV{CQ_USER}  ? $ENV{CQ_USER} : $ENV{USER};\r
103 my $_password   = $ENV{CQ_PASSWORD};\r
104 my $_db_name    = $ENV{CQ_DBSET} ? $ENV{CQ_DBSET} : "RANCQ";\r
105 my $_ucmwb;\r
106 \r
107 my $_log;\r
108 \r
109 if (get_debug) {\r
110   $_log = new Logger (\r
111     path => "/tmp",\r
112     append => 1,\r
113   );\r
114 } # if\r
115 \r
116 my %_commands = (\r
117   activate      => \&activate,\r
118   assign        => \&assign,\r
119   clone         => \&clone,\r
120   comment       => \&comment,\r
121   complete      => \&complete,\r
122   createhd      => \&createHelpDesk,\r
123   createwor     => \&createWOR,\r
124   effort        => \&effort,\r
125   exit          => \&shutdown,\r
126   help          => \&help,\r
127   link          => \&linkParentWor2ChildWor,\r
128   quit          => \&shutdown,\r
129   resolve       => \&resolve,\r
130   set           => \&set,\r
131   usage         => \&usage,\r
132   version       => \&announce,\r
133 );\r
134 \r
135 ##############################################################################\r
136 # Forwards\r
137 ##############################################################################\r
138 sub commandLoop (@);\r
139 \r
140 ##############################################################################\r
141 # Main\r
142 ##############################################################################\r
143 MAIN: {\r
144   GetOptions (\r
145     "usage"             => sub { usage () },\r
146     "verbose"           => sub { set_verbose () },\r
147     "debug"             => sub { set_debug () },\r
148     "userid=s"          => \$_userid,\r
149     "password=s"        => \$_password,\r
150     "database=s"        => \$_db_name,\r
151     "ucmwb"             => \$_ucmwb,\r
152   ) || usage ();\r
153 \r
154   exit (commandLoop(@ARGV));\r
155 } # MAIN\r
156 \r
157 ##############################################################################\r
158 # Subroutines\r
159 ##############################################################################\r
160 \r
161 #-----------------------------------------------------------------------------\r
162 # shutdown (): Ends program\r
163 #-----------------------------------------------------------------------------\r
164 sub shutdown () {\r
165   exit (0);\r
166 } # exit\r
167 \r
168 #-----------------------------------------------------------------------------\r
169 # help (): Displays help\r
170 #-----------------------------------------------------------------------------\r
171 sub help () {\r
172   display ($DESC);\r
173   display <<END;\r
174 \r
175 Valid commands are:\r
176 \r
177 activate <wor> <project> <est_hours> <startdate> <enddate>:\r
178         Activate WOR\r
179 assign <wor> <assignee> <project> <planned_hours> <startdate>:\r
180         Assign the WOR\r
181 clone <wor>:\r
182         Clones a WOR\r
183 comment <wor> <comment>\r
184         Add a comment to the Notes_Entry field for the WOR\r
185 complete <wor> <actual_hours>:\r
186         Complete WOR\r
187 createhd:\r
188         Create a new Help Desk Ticket\r
189 createwor:\r
190         Create a new WOR\r
191 effort <wor> <hours>:\r
192         Update the WOR's actual hours\r
193 exit|quit:\r
194         Exits $FindBin::Script\r
195 help:\r
196         This display\r
197 link <parent wor> <child wor>:\r
198         Link a parent WOR to a child WOR\r
199 resolve <wor>:\r
200         Resolve WOR\r
201 set <wor> <field> <value>\r
202         Set <field> to <value> for the <wor>\r
203 usage:\r
204         Displays command line usage\r
205 version:\r
206         Displays version of $FindBin::Script\r
207 END\r
208 } # help\r
209 \r
210 #-----------------------------------------------------------------------------\r
211 # announce (): Announce ourselves\r
212 #-----------------------------------------------------------------------------\r
213 sub announce () {\r
214   display ($DESC);\r
215 } # Announce\r
216 \r
217 #-----------------------------------------------------------------------------\r
218 # dberror ($): Handle errors when talking to Clearquest. Note we need to reset\r
219 #              the database connection if an error happens.\r
220 #-----------------------------------------------------------------------------\r
221 sub dberror ($) {\r
222   my ($msg) = @_;\r
223 \r
224   # Need to not only report the error but to reopen the\r
225   # database. Something gets corruppted if we don't!\r
226   error ($msg);\r
227 \r
228   closeDB ();\r
229 \r
230   openDB ($_userid, $_password, $_db_name);\r
231 } # DBError\r
232 \r
233 #-----------------------------------------------------------------------------\r
234 # getEntity ($$): Get an entity from Clearquest\r
235 #-----------------------------------------------------------------------------\r
236 sub getEntity ($$) {\r
237   my ($recordname, $wor) = @_;\r
238 \r
239   my $entity;\r
240 \r
241   eval {\r
242     $entity = $CQTool::session->GetEntity ($recordname, $wor);\r
243   };\r
244 \r
245   if ($@) {\r
246     chomp $@;\r
247     dberror ($@);\r
248     return undef;\r
249   } else {\r
250     return $entity;\r
251   } # if\r
252 } # getEntity\r
253 \r
254 #-----------------------------------------------------------------------------\r
255 # set ($$$): Set $field to $value for $wor\r
256 #-----------------------------------------------------------------------------\r
257 sub set ($$@) {\r
258   my ($wor, $field, $value) = @_;\r
259 \r
260   if (!$wor or $wor eq "") {\r
261     error ("WOR is required");\r
262     return 1;\r
263   } # if\r
264 \r
265   if (!$field or $field eq "") {\r
266     error ("Field is required");\r
267     return 1;\r
268   } # if\r
269 \r
270   my $entity    = getEntity ("WOR", $wor);\r
271 \r
272   return 1 if !$entity;\r
273 \r
274   $session->EditEntity ($entity, "modify");\r
275 \r
276   $_log->msg ("Modifying $field to \"$value\"") if get_debug;\r
277   eval {\r
278     $entity->SetFieldValue ($field, $value);\r
279   };\r
280 \r
281   if ($@) {\r
282     dberror ("$field set failed for WOR $wor:\n$@");\r
283     return 2;\r
284   } # if\r
285 \r
286   my $status = $entity->Validate ();\r
287 \r
288   if ($status ne "") {\r
289     $entity->Revert ();\r
290     error ("$field validate failed for WOR $wor:\n$status");\r
291     return 2;\r
292   } # if\r
293 \r
294   $status = $entity->Commit ();\r
295 \r
296   if ($status ne "") {\r
297     error ("$field update failed during Submit for $wor:\n$status");\r
298     return 2;\r
299   } # if\r
300 \r
301    return 0;\r
302 } # set\r
303 \r
304 #-----------------------------------------------------------------------------\r
305 # clone ($): Clone a WOR\r
306 #-----------------------------------------------------------------------------\r
307 sub clone ($) {\r
308   my ($wor) = @_;\r
309 \r
310   if (!$wor) {\r
311     error ("WOR not specified!");\r
312     return 1;\r
313   } # if\r
314 \r
315   $entity = getEntity ("WOR", $wor);\r
316 \r
317   return 1 if !$entity;\r
318 \r
319   # Check state\r
320   my $state = $entity->GetFieldValue ("state")->GetValue ();\r
321 \r
322   if ($state ne "Closed") {\r
323     error ("WOR $wor not closed - Unable to clone!");\r
324     return 1;\r
325   } # if\r
326 \r
327   verbose ("Cloning WOR $wor...");\r
328 \r
329   my $result = 0;\r
330 \r
331   eval {\r
332     # Currently Clone doesn't return a proper result but eventually...\r
333     $result = $CQTool::session->FireRecordScriptAlias ($entity, "Clone");\r
334   };\r
335 \r
336   if ($@) {\r
337     chomp $@;\r
338     dberror ($@);\r
339     return 1;\r
340   } # if\r
341 \r
342   return $result;\r
343 } # clone\r
344 \r
345 #-----------------------------------------------------------------------------\r
346 # effort ($$): Update actual hours for a WOR\r
347 #-----------------------------------------------------------------------------\r
348 sub effort ($$) {\r
349   my ($wor, $actualHrs) = @_;\r
350 \r
351   return set $wor, "ActualEffort", $actualHrs;\r
352 } # effort\r
353 \r
354 #-----------------------------------------------------------------------------\r
355 # comment (): Update the Notes_Entry comment field for a WOR\r
356 #-----------------------------------------------------------------------------\r
357 sub comment ($) {\r
358   my ($wor) = @_;\r
359 \r
360   if (!$wor) {\r
361     error "WOR not defined in call to comment!";\r
362     return 1;\r
363   } # if\r
364 \r
365   if (!$_ucmwb) {\r
366     display ("Enter comments below. When finished, enter \".\" on a line by itself or hit ^D:");\r
367   } else {\r
368     # We still need to prompt for the comments however signal UCMWB\r
369     # that command is ready for more input.\r
370     display_nolf ($UCMWB_PROMPT);\r
371   } # if\r
372 \r
373   my $comments;\r
374 \r
375   while (<STDIN>) {\r
376     last if $_ eq ".\n";\r
377     $comments .= $_;\r
378   } # while\r
379 \r
380   chomp $comments;\r
381 \r
382   $_log->msg ("Comments:\n$comments") if get_debug;\r
383 \r
384   return set $wor, "Note_Entry", $comments;\r
385 } # Comment\r
386 \r
387 #-----------------------------------------------------------------------------\r
388 # linkParentWor2ChildWor ($$): Link a child WOR to a parent WOR\r
389 #-----------------------------------------------------------------------------\r
390 sub linkParentWor2ChildWor ($$) {\r
391   my ($parentWor, $childWor) = @_;\r
392 \r
393   my $status;\r
394 \r
395   verbose ("Linking $parentWor -> $childWor...");\r
396 \r
397   my $childentity       = getEntity ("WOR", $childWor);\r
398   my $parententity      = getEntity ("WOR", $parentWor);\r
399 \r
400   return 1 unless $childentity and $parententity;\r
401 \r
402   $session->EditEntity ($parententity, "modify");\r
403 \r
404   $parententity->AddFieldValue ("wor_children", $childWor);\r
405 \r
406   $status = $parententity->Validate ();\r
407 \r
408   if ($status ne "") {\r
409     $parententity->Revert ();\r
410     error ("Validation failed while attempting to add child WOR $childWor to parent WOR $parentWor:\n$status");\r
411     return 1;\r
412   } # if\r
413 \r
414   eval {\r
415     $status = $parententity->Commit ();\r
416   };\r
417 \r
418   $status = $@ if $@;\r
419 \r
420   if ($status ne "") {\r
421     (error "Commit failed while trying to add child WOR $childWor to parent WOR $parentWor:\n$status");\r
422     return 2;\r
423   } # if\r
424 \r
425   debug "Modifying child $childWor...";\r
426   $session->EditEntity ($childentity, "modify");\r
427 \r
428   $childentity->SetFieldValue ("wor_parent", $parentWor);\r
429 \r
430   $status = $childentity->Validate ();\r
431 \r
432   if ($status ne "") {\r
433     $childentity->Revert ();\r
434     error "Validation failed while attempting to add parent WOR $parentWor to child WOR $childWor:\n$status";\r
435     return 1;\r
436   } # if\r
437 \r
438   eval {\r
439     $status = $childentity->Commit ();\r
440   };\r
441 \r
442   $status = $@ if $@;\r
443 \r
444   if ($status ne "") {\r
445     error "Commit failed while trying to add parent WOR $parentWor to child WOR $childWor:\n$status";\r
446     return 2;\r
447   } # if\r
448 \r
449   return 0;\r
450 } # linkParentWor2ChildWor\r
451 \r
452 #-----------------------------------------------------------------------------\r
453 # assign ($$$$): Assign a WOR\r
454 #-----------------------------------------------------------------------------\r
455 sub assign ($$$$$) {\r
456   my ($wor, $assignee, $project, $plannedHrs, $startDate) = @_;\r
457 \r
458   if (!$wor or $wor eq "") {\r
459     error ("WOR is required");\r
460     return 1;\r
461   } # if\r
462 \r
463   if (!$assignee or $assignee eq "") {\r
464     error ("Assignee must be specified");\r
465     return 1;\r
466   } # if\r
467 \r
468   if (!$project or $project eq "") {\r
469     error ("UCM Project is required");\r
470     return 1;\r
471   } # if\r
472 \r
473   if (!$startDate or $startDate eq "") {\r
474     error ("Planned Start Date is required");\r
475     return 1;\r
476   } # if\r
477 \r
478   my $entity    = getEntity ("WOR", $wor);\r
479 \r
480   return 1 if !$entity;\r
481 \r
482   my $state     = $entity->GetFieldValue ("state")->GetValue ();\r
483 \r
484   if ($state ne "Submitted") {\r
485     error ("WOR $wor is not in Submitted state!\nState: $state");\r
486     return 2;\r
487   } # if\r
488 \r
489   $session->EditEntity ($entity, "assign");\r
490 \r
491   $entity->SetFieldValue ("ucm_project",        $project)       if $project     ne "";\r
492   $entity->SetFieldValue ("PlannedStart",       $startDate)     if $startDate   ne "";\r
493   $entity->SetFieldValue ("PlannedEffort",      $plannedHrs)    if $plannedHrs  ne "";\r
494   $entity->SetFieldValue ("Owner",              $assignee)      if $assignee    ne "";\r
495 \r
496   my $status = $entity->Validate ();\r
497 \r
498   if ($status ne "") {\r
499     $entity->Revert ();\r
500     error ("Assign failed for WOR $wor:\n$status");\r
501     return 2;\r
502   } # if\r
503 \r
504   $status = $entity->Commit ();\r
505 \r
506   if ($status ne "") {\r
507     error ("Assign failed during Submit for WOR $wor:\n$status");\r
508     return 2;\r
509   } # if\r
510 \r
511   return 0;\r
512 } # assign\r
513 \r
514 #-----------------------------------------------------------------------------\r
515 # activate (): Activate a WOR\r
516 #-----------------------------------------------------------------------------\r
517 sub activate ($$$$$) {\r
518   my ($wor, $project, $estHrs, $startDate, $endDate) = @_;\r
519 \r
520   if (!$wor or $wor eq "") {\r
521     error ("WOR is required");\r
522     return 1;\r
523   } # if\r
524 \r
525   if (!$project or $project eq "") {\r
526     error ("UCM Project is required");\r
527     return 1;\r
528   } # if\r
529 \r
530   if (!$startDate or $startDate eq "") {\r
531     error ("Planned Start Date is required");\r
532     return 1;\r
533   } # if\r
534 \r
535   if (!$endDate or $endDate eq "") {\r
536     error ("Planned End Date is required");\r
537     return 1;\r
538   } # if\r
539 \r
540   my $entity    = getEntity ("WOR", $wor);\r
541 \r
542   return 1 if !$entity;\r
543 \r
544   my $state     = $entity->GetFieldValue ("state")->GetValue ();\r
545 \r
546   if ($state ne "Assessing") {\r
547     error ("WOR $wor is not in Assessing state!\nstate: $state");\r
548     return 2;\r
549   } # if\r
550 \r
551   $session->EditEntity ($entity, "activate");\r
552 \r
553   $entity->SetFieldValue ("ucm_project",        $project)       if $project ne "";\r
554   $entity->SetFieldValue ("EstimatedEffort",    $estHrs)        if $estHrs ne "";\r
555   $entity->SetFieldValue ("PlannedStart",       $startDate)     if $startDate ne "";\r
556   $entity->SetFieldValue ("PlannedEnd",         $endDate)       if $endDate ne "";\r
557 \r
558   my $status = $entity->Validate ();\r
559 \r
560   if ($status ne "") {\r
561     $entity->Revert ();\r
562     error ("Activate failed for WOR $wor:\n$status");\r
563     return 2;\r
564   } # if\r
565 \r
566   $status = $entity->Commit ();\r
567 \r
568   if ($status ne "") {\r
569     error ("Activate failed during Submit for WOR $wor:\n$status");\r
570     return 2;\r
571   } # if\r
572 \r
573    return 0;\r
574 } # activate\r
575 \r
576 #-----------------------------------------------------------------------------\r
577 # resolve ($): Resolve a WOR\r
578 #-----------------------------------------------------------------------------\r
579 sub resolve ($) {\r
580   my ($wor) = @_;\r
581 \r
582   if (!$wor or $wor eq "") {\r
583     error ("WOR is required");\r
584     return 1;\r
585   } # if\r
586 \r
587   my $entity    = getEntity ("WOR", $wor);\r
588 \r
589   return 1 if !$entity;\r
590 \r
591   my $state     = $entity->GetFieldValue ("state")->GetValue ();\r
592 \r
593   if ($state ne "Working") {\r
594     error ("WOR $wor is not in Working state!\nState: $state");\r
595     return 2;\r
596   } # if\r
597 \r
598   $session->EditEntity ($entity, "resolve");\r
599 \r
600   my $status = $entity->Validate ();\r
601 \r
602   if ($status ne "") {\r
603     $entity->Revert ();\r
604     error ("Resolve failed for WOR $wor:\n$status");\r
605     return 2;\r
606   } # if\r
607 \r
608   $status = $entity->Commit ();\r
609 \r
610   if ($status ne "") {\r
611     error ("Resolve failed during Submit for WOR $wor:\n$status");\r
612     return 2;\r
613   } # if\r
614 \r
615    return 0;\r
616 } # resolve\r
617 \r
618 #-----------------------------------------------------------------------------\r
619 # complete ($$): Complete a WOR\r
620 #-----------------------------------------------------------------------------\r
621 sub complete ($$) {\r
622   my ($wor, $actualHrs) = @_;\r
623 \r
624   if (!$wor or $wor eq "") {\r
625     error ("WOR is required");\r
626     return 1;\r
627   } # if\r
628 \r
629   if (!$wor or $wor eq "") {\r
630     error ("Actual Hours are required");\r
631     return 1;\r
632   } # if\r
633 \r
634   my $entity    = getEntity ("WOR", $wor);\r
635 \r
636   return 1 if !$entity;\r
637 \r
638   my $state     = $entity->GetFieldValue ("state")->GetValue ();\r
639 \r
640   if ($state ne "Verifying") {\r
641     error ("WOR $wor is not in Verifying state!\nState:$state");\r
642     return 2;\r
643   } # if\r
644 \r
645   $session->EditEntity ($entity, "complete");\r
646   $entity->SetFieldValue ("ActualEffort", $actualHrs) if $actualHrs ne "";\r
647 \r
648   my $status = $entity->Validate ();\r
649 \r
650   if ($status ne "") {\r
651     $entity->Revert ();\r
652     error ("Complete failed for WOR $wor:\n$status");\r
653     return 2;\r
654   } # if\r
655 \r
656   $status = $entity->Commit ();\r
657 \r
658   if ($status ne "") {\r
659     error ("Complete failed during Submit for WOR $wor:\n$status");\r
660     return 2;\r
661   } # if\r
662 \r
663    return 0;\r
664 } # Complete\r
665 \r
666 #-----------------------------------------------------------------------------\r
667 # executeCommand (@): Executes a cqtool command\r
668 #-----------------------------------------------------------------------------\r
669 sub executeCommand (@) {\r
670   my (@args) = @_;\r
671 \r
672   my $cmd = lc shift @args;\r
673 \r
674   return if $cmd eq "";\r
675 \r
676   if ($_commands{$cmd}) {\r
677     if (!$CQTool::session) {\r
678       if ( # Commands that do not require a database connection\r
679           !($cmd eq "exit"      or\r
680             $cmd eq "quit"      or\r
681             $cmd eq "help"      or\r
682             $cmd eq "usage"     or\r
683             $cmd eq "verbose")) {\r
684         verbose "Opening $_db_name as $_userid...";\r
685 \r
686         if (!$_password) {\r
687           display_nolf ("${_userid}'s password:");\r
688           `stty -echo`;\r
689           $_password = <STDIN>;\r
690           chomp $_password;\r
691           display ("");\r
692           `stty echo`;\r
693         } # if\r
694 \r
695         openDB ($_userid, $_password, $_db_name);\r
696       } # if\r
697     } # if\r
698 \r
699     # Treat args: Args that are enclosed in quotes must be\r
700     # combined. For simplicity's sake we will only support matched\r
701     # pairs of double quotes. Anything else results in undefined\r
702     # behavior.\r
703     my (@new_args);\r
704 \r
705     foreach (@args) {\r
706       # Quoted argument starting\r
707       if (/^\"(.*)\"$/s) {\r
708         push @new_args, $1;\r
709       } else {\r
710         push @new_args, $_;\r
711       } # if\r
712     } # foreach\r
713 \r
714     $_log->msg ("$cmd (" . join (",", @new_args) . ")") if get_debug;\r
715 \r
716     return $_commands{$cmd} (@new_args);\r
717   } else {\r
718     error ("Unknown command \"$cmd\" (try help)");\r
719     return 1;\r
720   } # if\r
721 } # executeCommand\r
722 \r
723 #-----------------------------------------------------------------------------\r
724 # commandLoop (@): This is the interactive command loop\r
725 #-----------------------------------------------------------------------------\r
726 sub commandLoop (@) {\r
727   my (@args) = @_;\r
728 \r
729   # For single, command line, commands...\r
730   return executeCommand (@args) if @args;\r
731 \r
732   announce if !$_ucmwb;\r
733 \r
734   while () {\r
735     if (!$_ucmwb) {\r
736       display_nolf ($PROMPT . RESET . UNDERLINE);\r
737     } else {\r
738       display_nolf ($UCMWB_PROMPT);\r
739     } # if\r
740 \r
741     # Read command into $_\r
742     $_ = <STDIN>;\r
743     chomp;\r
744 \r
745     # If we are not being called by ucmwb, display RESET to stop the\r
746     # UNDERLINE we were using. This keeps the output from being\r
747     # underlined. In ucmwb mode we are not using any of the terminal\r
748     # sequences.\r
749     display_nolf (RESET) if !$_ucmwb;\r
750 \r
751     # If the user hit Control-d then a ^D is displayed but we remain\r
752     # on the same line. So output a carriage return and exit 0.\r
753     if (!$_) {\r
754       display ("");\r
755       exit 0;\r
756     } # if\r
757 \r
758     # Special handling for set command since we want to take\r
759     # everything after <field> to be a value, and we may get long\r
760     # values that are space separated and space significant\r
761     # (e.g. description?)\r
762     if (/^\s*(\w+)\s+(\w+)\s+(\w+)\s+(.*)/) {\r
763       if (lc $1 eq "set") {\r
764         my $cmd         = $1;\r
765         my $wor         = $2;\r
766         my $field       = $3;\r
767         my $value       = $4;\r
768 \r
769         # Change "\n"'s back to \n's\r
770         $value =~ s/\\n/\n/g;\r
771 \r
772         executeCommand ($cmd, $wor, $field, "\"$value\"");\r
773       } else {\r
774         executeCommand (split);\r
775       } # if\r
776     } else {\r
777       executeCommand (split);\r
778     } # if\r
779   } # while\r
780 } # commandLoop\r