m3middle/src/M3File.m3


Copyright (C) 1994, Digital Equipment Corp.
 File: M3File.m3                                             

UNSAFE MODULE M3File;

IMPORT FS, File, OSError, Text;

TYPE
  BufPtr = UNTRACED REF ARRAY BufferLength OF File.Byte;

PROCEDURE Read (f: File.T; VAR(*OUT*)buf: Buffer; len: BufferLength): INTEGER
  RAISES {OSError.E} =
  VAR ptr: BufPtr;
  BEGIN
    IF (NUMBER (buf) <= 0) THEN RETURN 0 END;
    ptr := LOOPHOLE (ADR (buf[0]), BufPtr);
    RETURN f.read (SUBARRAY (ptr^, 0, MIN (len, NUMBER (buf))),
                   mayBlock := TRUE);
  END Read;

PROCEDURE Copy (src, dest: TEXT) RAISES {OSError.E} =
  VAR
    rd, wr : File.T := NIL;
    len    : INTEGER;
    buf    : ARRAY [0..4095] OF File.Byte;
  BEGIN
    TRY
      rd := FS.OpenFileReadonly (src);
      wr := FS.OpenFile (dest);
      LOOP
        len := rd.read (buf);
        IF (len <= 0) THEN EXIT; END;
        wr.write (SUBARRAY (buf, 0, len));
      END;
    FINALLY
      IF (wr # NIL) THEN wr.close (); END;
      IF (rd # NIL) THEN rd.close (); END;
    END;
  END Copy;

PROCEDURE CopyText (src, dest: TEXT;  eol: TEXT) RAISES {OSError.E} =
  VAR
    rd, wr  : File.T := NIL;
    in_len  : INTEGER;
    out_len : INTEGER;
    ch      : File.Byte;
    in_buf  : ARRAY [0..1023] OF File.Byte;
    out_buf : ARRAY [0..1023] OF File.Byte;
    eol_buf : ARRAY [0..7] OF File.Byte;
    eol_last: INTEGER;
  BEGIN
    eol_last := Text.Length (eol) - 1;
    FOR i := 0 TO eol_last DO eol_buf[i] := ORD(Text.GetChar (eol, i)); END;
    TRY
      rd := FS.OpenFileReadonly (src);
      wr := FS.OpenFile (dest);
      out_len := 0;
      LOOP
        in_len := rd.read (in_buf);
        IF (in_len <= 0) THEN EXIT; END;
        FOR i := 0 TO in_len-1 DO
          IF (out_len >= NUMBER (out_buf)) THEN
            wr.write (out_buf);
            out_len := 0;
          END;
          ch := in_buf [i];
          IF (ch = ORD ('\r')) THEN
            (* eat it. *)
          ELSIF (ch = ORD ('\n')) THEN
            FOR i := 0 TO eol_last DO
              IF (out_len >= NUMBER (out_buf)) THEN
                wr.write (out_buf);
                out_len := 0;
              END;
              out_buf [out_len] := eol_buf[i];
              INC (out_len);
            END;
          ELSE
            out_buf [out_len] := ch;
            INC (out_len);
          END;
        END;
      END;
      IF (out_len > 0) THEN wr.write (SUBARRAY (out_buf, 0, out_len)); END;
    FINALLY
      IF (wr # NIL) THEN wr.close (); END;
      IF (rd # NIL) THEN rd.close (); END;
    END;
  END CopyText;

PROCEDURE IsEqual (a, b: TEXT): BOOLEAN RAISES {OSError.E} =
  VAR
    f1, f2     : File.T := NIL;
    buf1, buf2 : ARRAY [0..1023] OF File.Byte;
    len1, len2 : INTEGER;
  BEGIN
    TRY
      f1 := FS.OpenFileReadonly (a);
      f2 := FS.OpenFileReadonly (b);
      IF (f1.status().size # f2.status().size) THEN RETURN FALSE; END;
      LOOP
        len1 := f1.read (buf1);
        len2 := f2.read (buf2);
        IF (len1 # len2) THEN RETURN FALSE; END;
        IF (len1 <= 0)   THEN RETURN TRUE;  END;
        FOR i := 0 TO len1-1 DO
          IF buf1[i] # buf2[i] THEN RETURN FALSE END;
        END;
      END;
    FINALLY
      IF f1 # NIL THEN f1.close () END;
      IF f2 # NIL THEN f2.close () END;
    END;
  END IsEqual;

PROCEDURE IsDirectory (path: TEXT): BOOLEAN =
  VAR s: File.Status;
  BEGIN
    TRY
      s := FS.Status (path);
      RETURN (s.type = FS.DirectoryFileType);
    EXCEPT OSError.E =>
      RETURN FALSE;
    END;
  END IsDirectory;

PROCEDURE IsReadable (path: TEXT): BOOLEAN =
  (* We don't really check for readablitiy, just for existence *)
  BEGIN
    TRY
      EVAL FS.Status (path);
      RETURN TRUE;
    EXCEPT OSError.E =>
      RETURN FALSE;
    END;
  END IsReadable;

BEGIN
END M3File.