-- UECPImpl.mesa
-- Last edit by Gifford on June 18, 1982 10:55 am

DIRECTORY
  Inline USING [LongCOPY],
  Rope,
  UECP;

UECPImpl: CEDAR PROGRAM
  IMPORTS Inline, Rope
  EXPORTS UECP = {
  OPEN UECP;

  UnmatchedQuote: ERROR = CODE;

  CPData: TYPE = RECORD [
    ch: CHARACTER ← ' , -- first char of next token; initially blank
    swChar: CHARACTER, -- switch character
    ropeIndex: LONG INTEGER ← 0,  -- index into Rope command line
    rope: Rope.ROPE ← NIL, -- command line passed from client
    done: BOOLEAN ← FALSE, -- used up all of command line
    argC: INT ← 0, -- number of tokens found
    args: LIST OF Rope.ROPE ← NIL  -- list of tokens
    ];
    
  Parse: PUBLIC PROC [commands: Rope.ROPE, switchchar: CHARACTER ← '-] RETURNS [argv: Argv] = {
    cpd: REF CPData ← NEW[CPData];
    Fooey: PROC RETURNS [LIST OF Rope.ROPE, INT] = {
      r: Rope.ROPE ← IGet[cpd];
      IF r = NIL THEN RETURN [NIL, 1]
      ELSE {
	n: LIST OF Rope.ROPE;
	c: INT;
	[n, c] ← Fooey[];
	RETURN [CONS[r, n], c+1];
	};
      };
    cpd.swChar ← switchchar;
    cpd.rope ← commands;
    argv ← NIL;
    [cpd.args, cpd.argC] ← Fooey[! UnmatchedQuote => GOTO Lose];
    argv ← NEW[ArgHandleObject[cpd.argC]];
    argv[0] ← "";
    FOR i: NAT IN [1..argv.argc) DO
      argv[i] ← cpd.args.first;
      cpd.args ← cpd.args.rest;
      ENDLOOP;
    EXITS
    Lose => NULL;
    };--Parse

  IGet: PROC [cpd: REF CPData] RETURNS [result: Rope.ROPE] = {
    -- Returns next token.
    -- This scanner
    -- (1) ignores leading blanks,
    -- (2) returns a quoted token intact (excluding the quotes),
    -- (3) returns an unquoted token delimited by a blank (not included)
    --or switchchar (included in next token), the default switchchar is '/
    -- (4) returns NIL at CR or end of file.
    -- (5) if the switchchar is '- then it must be preceded by a blank
    chlook: CHARACTER;
    workstr: REF TEXT;
      -- delimiter for token: either blank, meaning blank
      -- or switchchar (usually '/),
      -- or '", or '", meaning '" not followed by another '".

    RopeWP: PROC [c: CHARACTER] = {
      IF workstr=NIL THEN workstr ← NEW[TEXT[40]];
      IF workstr.length >= workstr.maxLength THEN TRUSTED {
        old: REF TEXT ← workstr;
	workstr ← NEW[TEXT[2*old.maxLength]];
	Inline.LongCOPY[
          from: LOOPHOLE[old, LONG POINTER] + 2, nwords: (old.maxLength + 1)/2,
          to: LOOPHOLE[workstr, LONG POINTER] + 2];
	workstr.length ← old.length;
	};
      workstr[workstr.length] ← c;
      workstr.length ← SUCC[workstr.length];
      };

    WHILE cpd.ch = '  AND GetCh[cpd] DO ENDLOOP;
    IF cpd.done OR cpd.ch = '\n THEN RETURN[NIL];
    chlook ← ' ;
    IF cpd.ch = '" THEN {
      [] ← GetCh[cpd];
      chlook ← '";
      };
    DO
      IF cpd.done OR cpd.ch = '\n THEN GOTO EOL;
      SELECT chlook FROM
        
        '  => SELECT cpd.ch FROM
                '  , '" => IF workstr#NIL THEN EXIT;
		cpd.swChar => IF cpd.ch#'- AND workstr#NIL THEN EXIT;
              ENDCASE;
        '" => SELECT cpd.ch FROM
                '" => IF (NOT GetCh[cpd]) OR (cpd.ch # '") THEN EXIT;
              ENDCASE;
        ENDCASE => ERROR;
      -- ch now contains a character to be included in the token
      RopeWP[cpd.ch];
      IF NOT GetCh[cpd] THEN GOTO EOL;
      REPEAT
        EOL => IF chlook = '" THEN ERROR UnmatchedQuote;
      ENDLOOP;
    IF workstr = NIL OR workstr.length=0 THEN RETURN [NIL];
    result ← Rope.FromRefText[workstr];
    };--IGet

  GetCh: PROC [cpd: REF CPData] RETURNS [BOOL] = {
    IF cpd.ropeIndex >= Rope.Size[cpd.rope] THEN GOTO EOS;
    cpd.ch ← Rope.Fetch[cpd.rope, cpd.ropeIndex];
    cpd.ropeIndex ← SUCC[cpd.ropeIndex];
    RETURN [TRUE];
    EXITS
    EOS => {
      cpd.done ← TRUE;
      cpd.ch ← ' ;
      RETURN [FALSE];
      };
    }; -- GetCh

}.-- UECPImpl


CHANGE LOG

Created by Stewart on 19-Mar-82 17:31
Rename Open to Parse by Gifford 23-Mar-82 14:46:08
CEDAR PROGRAM, Schroeder, September 17, 1982 3:20 pm