-- CountWords.mesa 
-- Edited by Sweet, 24-Aug-81 10:16:40

DIRECTORY
  AltoDefs,
  CommanderDefs USING [AddCommand, CommandBlockHandle],
  IODefs,
  SegmentDefs,
  Storage,
  StreamDefs;
  
Subst: PROGRAM 
  IMPORTS CommanderDefs, IODefs, SegmentDefs, StreamDefs, Storage  =
  BEGIN
  
  BuffSize: CARDINAL = 30;
  
  CountWords: PROCEDURE [fileName: STRING] =
    BEGIN OPEN StreamDefs;
    in: StreamHandle;
    c: CHARACTER;
    eof: BOOLEAN ← FALSE;
    buffer: POINTER TO PACKED ARRAY [0..0) OF CHARACTER ← NIL;
    bptr, btop: CARDINAL ← 0;
    words: CARDINAL ← 0;
    fileRead: BOOLEAN ← FALSE;
    
    fillbuffer: PROCEDURE =
      BEGIN
      n: CARDINAL;
      n ← ReadBlock[in, buffer, BuffSize*AltoDefs.PageSize];
      IF in.endof[in] THEN
	BEGIN
	fileRead ← TRUE;
	IF GetIndex[in].byte MOD 2 # 0 THEN btop ← 2*n-1
	ELSE btop ← 2*n;
	END
      ELSE btop ← 2*n;
      bptr ← 0;
      END;
      
    get: PROCEDURE RETURNS [c: CHARACTER] =
      BEGIN
      IF bptr < btop THEN 
	  BEGIN c ← buffer[bptr]; bptr ← bptr+1 END
      ELSE IF fileRead THEN c ← 0C
      ELSE
	BEGIN
	fillbuffer[];
	c ← buffer[0];
	bptr ← 1;
	END;
      eof ← fileRead AND bptr >= btop;
      END;
      
    peek: PROCEDURE RETURNS [c: CHARACTER] =
      BEGIN
      IF bptr < btop THEN 
	c ← buffer[bptr]
      ELSE IF fileRead THEN c ← 0C
      ELSE
	BEGIN
	fillbuffer[];
	c ← buffer[0];
	bptr ← 0;
	END;
      END;
      
    buffer ← Storage.Pages[BuffSize];
    in ← NewByteStream[fileName, Read !
      SegmentDefs.FileNameError =>
	BEGIN
	IODefs.WriteLine["--file not found"];
	Storage.FreePages[buffer];
	GO TO noFile;
	END];
    WHILE ~eof DO
      c ← get[];
      SELECT c FROM
	IN ['0..'9], IN ['A..'Z], IN ['a..'z] =>
	  BEGIN
	  WHILE ~eof DO
	    SELECT peek[] FROM
	      IN ['0..'9], IN ['A..'Z], IN ['a..'z] => NULL;
	      ENDCASE => {words ← words + 1; EXIT};
	    c ← get[];
	    ENDLOOP;
	  END;
	ENDCASE;
      ENDLOOP;
    in.destroy[in];
    Storage.FreePages[buffer];
    IODefs.WriteDecimal[words]; IODefs.WriteLine[" words"L];
    EXITS
      noFile => NULL;
    END;
    
  Init: PROCEDURE =
    BEGIN OPEN CommanderDefs;
    command: CommandBlockHandle;
    
    command ← AddCommand["CountWords", LOOPHOLE[CountWords], 1];
    command.params[0] ← [type: string, prompt: "Filename"];
    END;
    
  Init[];
  END.