{       MODULE FOR LIST AND TREE OPERATIONS ARGUMENTS }
{       RANDALL VENHOLA JULY 8, 1987                  }


[INHERIT('SCREENHANDLERS','UTILITYOPS'), environment('argops')]

MODULE ARGOPS;

CONST

  maxchars = 31;              {# of chars in arg literal }
  maxargsinarray = 30;      {for conversion to an array of args}
  indexofunknowntexcommand = 0;

TYPE

  pckstr = VARYING [ maxchars ] of char;

  comparisons = (notvalid, lessthan, equal, greaterthan);

  setofcomparisons = set of comparisons;

  argtype = ( dsrverb, int, signedint, stylespecifier,
           textpckstr, character, quotedpckstr, nulltype);

  setofargtype = set of argtype;

          argument =  record
                        source            : pckstr;
                        isgeneralization : boolean;
                        texindex         : integer;
                        class             : setofargtype
                      end;

  argarray = array[1..maxargsinarray] of argument;




[GLOBAL] FUNCTION argliteral( arg : argument; smooth : boolean ) : pckstr;

var
 s : pckstr;
 i,j, firstchar, lastchar : integer;
 ch : char;

procedure findfirstchar( s : pckstr; var firstchar : integer);
begin
   firstchar := 1;
   while (firstchar < s.length) and (s.body[firstchar] <= blank) do
     firstchar := firstchar + 1
end;

procedure findlastchar( s : pckstr; var lastchar : integer );
begin
  lastchar := s.length;
  while (lastchar > 1) and (s.body[lastchar] <= blank) do
     lastchar := lastchar - 1
end;

begin
  if smooth then
  begin
    findfirstchar( arg.source, firstchar);
    findlastchar( arg.source, lastchar);
    j := 0;
    for i := firstchar to lastchar do
    begin
      ch := arg.source.body[i];
      if ch < blank then ch := blank;
      if ch in ['a'..'z'] then ch := chr(ord(ch) - ord(blank));
      j := j + 1;
      s.body[j] := ch
    end;
    if (j = 1) and (s.body[1] = blank) then
      s.length := 0
    else
      s.length := j
  end
  else
    s := arg.source;
  argliteral := s
end;





[GLOBAL] FUNCTION pckstrisgeneralization( s : pckstr ) : boolean;
 label
   routineexit;
 var
   flag : boolean;
 begin
    flag := false;
    if s = '[N]' then
    begin
      flag := true;
      goto routineexit
    end;
    if s = '[C]' then
    begin
      flag := true;
      goto routineexit
    end;
    if s = '[Y]' then
    begin
      flag := true;
      goto routineexit
    end;
    if s = '[T]' then
    begin
      flag := true;
      goto routineexit
    end;
    if s = '[Q]' then
    begin
      flag := true;
      goto routineexit
    end;
    routineexit : pckstrisgeneralization := flag
end;




[GLOBAL] FUNCTION argisgeneralization( arg : argument ) : boolean;
begin
  argisgeneralization := arg.isgeneralization
end;




[GLOBAL] FUNCTION textualmatch( arg1, arg2 : argument) : boolean;
begin
  textualmatch := false;
  if (arg1.source = '[T]') and (textpckstr in arg2.class) then
       textualmatch := true
  else
     if (arg2.source = '[T]') and (textpckstr in arg1.class) then
       textualmatch := true
end;




[GLOBAL] FUNCTION compareargs( leftarg, rightarg : argument ) : comparisons;
label
 routineexit;
var
 lefts, rights : pckstr;
 equalpckstrs : boolean;
 comp : comparisons;

 procedure greaterorlessthancompare;
 begin
    if lefts < rights then
      comp := lessthan
    else
     comp := greaterthan
 end;

 procedure checktexindex;
 begin
    if (leftarg.texindex  = indexofunknowntexcommand) or
       (rightarg.texindex = indexofunknowntexcommand) then
        comp := equal
    else
       if leftarg.texindex = rightarg.texindex then
         comp := equal
       else
          greaterorlessthancompare
 end;

begin
  if textualmatch( leftarg, rightarg) then
  begin
    comp := equal;
    goto routineexit
  end;
  if (leftarg.class = [nulltype]) or (rightarg.class = [nulltype]) then
  begin
     comp := equal;
     goto routineexit
  end;
  lefts := argliteral(leftarg, TRUE);
  rights := argliteral(rightarg, TRUE);
  equalpckstrs := (lefts = rights);
  comp := notvalid;
  if leftarg.class * rightarg.class <> [] then
  begin
    if equalpckstrs then
       comp := equal
    else
       if (leftarg.isgeneralization) or (rightarg.isgeneralization) then
         checktexindex
       else
         greaterorlessthancompare
  end
  else
    greaterorlessthancompare;
  routineexit : compareargs := comp
end;




[GLOBAL] FUNCTION argtexindex( arg : argument ) : integer;
begin
  argtexindex := arg.texindex
end;




[GLOBAL] FUNCTION argclass( arg : argument ) : setofargtype;
begin
  argclass := arg.class
end;




[GLOBAL] PROCEDURE initarg( var arg : argument; classification : setofargtype;
                  lit : pckstr; index : integer; general : boolean );
begin
  arg.source            := lit;
  arg.class             := classification;
  arg.texindex         := index;
  arg.isgeneralization := general
end;




[GLOBAL] PROCEDURE reassignargclass( var arg : argument; newclass : setofargtype);
begin
  arg.class := newclass
end;




[GLOBAL] PROCEDURE reassignargtexindex( var arg : argument; newindex:integer);
begin
 arg.texindex := newindex
end;



[GLOBAL] PROCEDURE reassignarggeneralization( var arg : argument;general:boolean);
begin
  arg.isgeneralization := general
end;




[GLOBAL] PROCEDURE appendchartoarg( ch : char; var arg : argument );
begin
 if arg.source.length = maxchars then
     warningmessage('appendchartoarg','argument too long')
 else
 begin
   arg.source.length := arg.source.length + 1;
   arg.source.body[arg.source.length] := ch
 end
end;




[GLOBAL] PROCEDURE extractintegerfromargument( arg : argument; var successful : boolean;
                                      var int : integer;
                                      var signed : boolean );
var
 s  : pckstr;
begin
  s := argliteral( arg, TRUE);
  readv( s, int, error := continue );
  if statusv <> 0 then
    successful := false
  else
  begin
     successful := true;
     signed := (s.body[1] = '+') or (s.body[1] = '-')
  end
end;



END.