MODULE ObxAscii;
(**

   project   = "BlackBox"
   organization   = "www.oberon.ch"
   contributors   = "Oberon microsystems"
   version   = "System/Rsrc/About"
   copyright   = "System/Rsrc/About"
   license   = "Docu/BB-License"
   purpose   = "formatted I/O from/to ASCII text files"
   changes   = ""
   issues   = ""

**)

   IMPORT Files, Stores, Converters, TextModels, TextMappers, TextViews;

   TYPE

      Text* = POINTER TO RECORD
         done-: BOOLEAN;   (* last operation was successful *)
         reading: BOOLEAN;
         form: TextMappers.Formatter;
         scan: TextMappers.Scanner
      END;
   VAR conv: Converters.Converter;

   PROCEDURE PathToFileSpec (IN path: ARRAY OF CHAR; OUT loc: Files.Locator; OUT name: Files.Name);

      VAR i, j: INTEGER; ch: CHAR;
   BEGIN
      i := 0; j := 0; loc := Files.dir.This("");
      WHILE (loc.res = 0) & (i < LEN(path) - 1) & (j < LEN(name) - 1) & (path[i] # 0X) DO
         ch := path[i]; INC(i);
         IF (j > 0) & (ch = "/") THEN name[j] := 0X; j := 0; loc := loc.This(name)
         ELSE name[j] := ch; INC(j)
         END
      END;
      IF path[i] = 0X THEN name[j] := 0X ELSE loc.res := 1; name := "" END
   END PathToFileSpec;
   PROCEDURE Open* (loc: Files.Locator; IN name: ARRAY OF CHAR): Text;

      VAR s: Stores.Store; fname: Files.Name; text: Text;
   BEGIN
      IF loc = NIL THEN PathToFileSpec(name, loc, fname) ELSE fname := name$ END;
      IF loc.res = 0 THEN
         Converters.Import(loc, fname, conv, s);
         IF (s # NIL) & (s IS TextViews.View) THEN
            NEW(text); text.reading := TRUE; text.scan.ConnectTo(s(TextViews.View).ThisModel());
            RETURN text
         ELSE RETURN NIL
         END
      ELSE RETURN NIL
      END
   END Open;
   PROCEDURE NewText* (): Text;

      VAR text: Text;
   BEGIN
      NEW(text); text.reading := FALSE; text.form.ConnectTo(TextModels.dir.New());
      RETURN text
   END NewText;
   
   PROCEDURE Register* (t: Text; loc: Files.Locator; IN name: ARRAY OF CHAR);
      VAR fname: Files.Name; v: TextViews.View;
   BEGIN
      IF ~t.reading & (name # "") THEN
         IF loc = NIL THEN PathToFileSpec(name, loc, fname) ELSE fname := name$ END;
         IF loc.res = 0 THEN v := TextViews.dir.New(t.form.rider.Base());
            Converters.Export(loc, fname, conv, v); t.done := TRUE
         ELSE t.done := FALSE
         END
      ELSE t.done := FALSE
      END
   END Register;
   PROCEDURE Eot* (t: Text): BOOLEAN;

   BEGIN
      RETURN t.reading & t.scan.rider.eot
   END Eot;
   PROCEDURE ReadChar* (t: Text; OUT c: CHAR);

   BEGIN
      ASSERT(t.reading, 20);
      t.scan.rider.ReadChar(c); t.done := ~t.scan.rider.eot
   END ReadChar;
   PROCEDURE ReadString* (t: Text; OUT s: ARRAY OF CHAR);

   BEGIN
      ASSERT(t.reading, 20);
      t.scan.Scan; t.done :=t.scan.type = TextMappers.string; s := t.scan.string$
   END ReadString;
   PROCEDURE ReadInt* (t: Text; OUT i: INTEGER);

   BEGIN
      ASSERT(t.reading, 20);
      t.scan.Scan; t.done := t.scan.type = TextMappers.int; i := t.scan.int
   END ReadInt;
   PROCEDURE WriteString* (t: Text; IN s: ARRAY OF CHAR);

   BEGIN
      ASSERT(~t.reading, 20);
      t.form.WriteString(s); t.done := TRUE
   END WriteString;
   PROCEDURE WriteLn* (t: Text);

   BEGIN
      ASSERT(~t.reading, 20);
      t.form.WriteLn; t.done := TRUE
   END WriteLn;
   PROCEDURE WriteInt* (t: Text; i: INTEGER);

   BEGIN
      ASSERT(~t.reading, 20);
      t.form.WriteInt(i); t.done := TRUE
   END WriteInt;
BEGIN

   conv := Converters.list;
   WHILE (conv # NIL) & (conv.imp # "HostTextConv.ImportText") DO
      conv := conv.next
   END
END ObxAscii.