   PROCEDURE readcmd(VAR arg: wrdarray; VAR numargs: byte);
{  
         +------------------------------------------------------------+
         |WRITTEN FOR ZUG USE.                  PASCAL Z, version 4.0 |
         |BY       Clif Kinne                   DATE:  12/15/82       |
         |                                                            |
         |PURPOSE  This procedure was designed to read and parse the  |
         |         command tail on a program call.                    |
         |                                                            |
         |CALL:    Readcmd(name,nargs)   - typical.                   |
         |                                                            |
         |INPUT    Reads a string, LINE, of up to 80 characters from  |
         |DATA           from the console.                            |
         |                                                            |
         |RETURNS: 1. The words from LINE in an array, ARG[1..maxargs]|
         |         2.  NARGS, the actual number of words found.       |
         |         3.  Dummy 1-character arguments to pad out the     |
         |              array from numargs to maxargs.                |
         |                                                            |
         |GLOBALS  CONST maxword  = Max. no. of characters in a word  |
         |REQUIRED       maxargs  = Max. no. of arguments allowed     |
         |               maxline  = 80;                               |
         |                                                            |
         |         TYPE  wrdtype  = string maxword;                   |
         |               wrdarray = ARRAY[1..maxargs] OF wrdtype;     |
         |               byte     = 0..255;                           |
         |                                                            |
         |         VAR   <argname>: wrdarray;                         |
         |                                                            |
         |FEATURES 1.  Truncates long words to MAXWORD characters.    |
         |         2.  If command tail is empty, invites operator to  |
         |              enter arguments, continue without arguments,  |
         |              or quit.                                      |
         |         3.  Trailing dummy arguments can signal calling    |
         |              program it has asked for unavailable argument.|
         |         4.  Can have up to 5 14-character or 38 1-character|
         |              arguments, or any mixture up to 77 characters.|
         |         5.  Even though MAXARGS arguments are allowed, any |
         |             lesser no. of arguments, including none, may be|
         |             entered. If none are needed, the command should|
         |             be followed by 2 spaces to avoid the reminder. |
         |                                                            |
         |BUGS     Does not handle tab characters satisfactorily.     |
         +------------------------------------------------------------+
.pa}
    CONST   blank     = ' ';
            dummy     = '\';

    TYPE    linetype  = string maxline;
            string0   = string 0;                         
            string255 = string 255;                       

    VAR     pos,i     : byte;
            line      : linetype;

    FUNCTION length(x: string255): INTEGER; external;  

    PROCEDURE reminder; 

{           +------------------------------------------------------+
            |This procedure is intended for use with the procedure,|
            |READCMD. It can be made external to READCMD so that it|
            |may be tailored to the calling program.               |
            +------------------------------------------------------+
}
      BEGIN {----------------------------reminder-----------------------------}

        WRITELN(margin,
            'You neglected to include any arguments with the program call.'); 
        WRITELN; WRITELN(margin,
               'Please enter them now (or enter "Q" to quit, or RETURN to');
        WRITELN; WRITELN(margin,'continue without arguments).'); 
        WRITELN; WRITELN; WRITE(margin,'===> ')
  
      END;  {----------------------------reminder-----------------------------}

    PROCEDURE linetoolong;

      BEGIN {---------------------------linetoolong---------------------------}

        WRITELN(margin,'Command line is too long.'); WRITELN;
        WRITELN(margin,'Reenter arguments here.  Do not exceed',
                        (maxline - 3):3,' characters.');
        WRITELN; READLN(line)

      END;  {---------------------------linetoolong---------------------------}
{.p.a}
    PROCEDURE getword(VAR word: string0; VAR line: linetype; VAR pos: byte);
            
{         +----------------------------------------------------------+
          |This procedure receives a string, LINE, and a character   |
          |position, POS.                                            |
          |It extracts the first group of non-space characters after |
          |POS, and returns it to the calling program as WORD.       |
          |Long words will be truncated at MAXWORD characters.       |
          |POS is returned to the calling program so that additional |
          |words may be extracted.                                   |
          +----------------------------------------------------------+
}
      CONST   blank = ' ';
  
      PROCEDURE setlength(VAR x: string0; y: INTEGER); external;
  
      BEGIN {-----------------------------getword-----------------------------}
  
        WHILE ((line[pos] = blank) OR (line[pos]= CHR(9))) AND (pos<maxline) DO
          pos := pos+1; {SKIPBLANKS}
        setlength(word,0);                 {INITIALIZES word TO A NULL STRING.}
        WHILE (line[pos] <> blank) AND (line[pos] <> CHR(9)) AND 
              (length(word) < maxword) DO
          BEGIN
            APPEND(word,line[pos]);        {BUILDS THE STRING, word.          }
            pos := pos + 1
          END;
        WHILE (line[pos] <> blank) AND (line[pos] <> CHR(9)) DO 
          pos := pos + 1    {SKIPS OVER ANY EXTRA NON-BLANK CHARACTERS IN word}
      END;  {-----------------------------getword-----------------------------}

    BEGIN {-------------------------------readcmd-----------------------------}

      pos := 1;
      IF EOLN THEN reminder;         {REPORT NO COMMAND LINE ARGUMENTS AT ALL }
      READLN(line); WRITELN;
      WHILE length(line) > (maxline - 3) DO linetoolong;
      APPEND(line,blank);            {APPEND DUMMY ARGUMENT TO SIGNIFY NO MORE}
      APPEND(line,dummy);            {ARGUMENTS IN THE COMMAND LINE           }
      FOR i := length(line) TO maxline - 1 DO append(line,blank);
                      {NEEDED SO THAT getword WILL BEHAVE AFTER DUMMY ARGUMENT}
      numargs := 0;
      REPEAT                         {GET ACTUAL ARGUMENTS IN ARRAY, arg, AND }
        numargs := numargs + 1;      {THE COUNT OF THE ARGUMENTS IN numargs:  }
        getword(arg[numargs],line,pos)
      UNTIL (arg[numargs] = dummy) OR (numargs = maxargs);  
      FOR i := numargs + 1 TO maxargs DO arg[i] := dummy;  {PAD ARGUMENT LIST }
                                          {OUT TO maxargs WITH DUMMY ARGUMENTS}
      IF arg[numargs] = dummy THEN numargs := numargs - 1;     {ADJUST numargs}
      
    END;  {-----------------------------readcmd ------------------------------}

   
