i21edu/Mod/Files.odc

MODULE  i21eduFiles; (* info21, 2003; последние изменения: 2010-09-28 *)
(* Простые средства для работы с файлами на уровне школы. 
Модуль следует использовать как пособие для знакомства с собственно файловым вводом-выводом. В качестве примера см. модуль i21eduFilesTest

Ввод-вывод данных в задачках другого типа гораздо удобней делать "документо-ориентированными" средствами (подробнее об этом в документе Текст как интерфейс): 
в русскоязычном варианте это модули i21eduВвод и i21eduВывод,
в англоязычном  i21sysIn и StdLog.
(Для чтения документации по модулям дважды кликнуть по имени модуля и нажать Ctrl+Shift+D или выполнить команду меню Инфо, Документация.) 

Так как на практике этот модуль используется неактивно, его поведение при некорректных действиях может быть пока недостаточно дружественным. 
Доработать его нетрудно, если опыт покажет, что это необходимо.
*)

	IMPORT  Log := StdLog,  Files,  Stores,  Strings,  Dialog;
	
	CONST  noFileOpen* = 0;  reading* = 1;  writing* = -1;
	
	VAR
		path-: ARRAY 2000 OF CHAR;
		filename-: ARRAY 256 OF CHAR;
		mode-: INTEGER; (* noFileOpen; reading; writing *)
		eof-: BOOLEAN;
		
		loc: Files.Locator;  f: Files.File;  wr: Stores.Writer;  rd: Stores.Reader;

	PROCEDURE SetFolder* ( p: ARRAY OF CHAR );
	BEGIN
		loc := Files.dir.This( p );
		IF  loc.res # 0  THEN
			loc := Files.dir.This('');  ASSERT( loc.res = 0, 100 );
			p := '';
		END;
		path := p$
	END SetFolder;
	
	PROCEDURE Close*;
		VAR  res: INTEGER;
	BEGIN
		IF  mode = writing  THEN
			f.Register( filename$, '', Files.dontAsk, res );  ASSERT( res = 0, 60 );
		END;
		wr.ConnectTo( NIL );
		rd.ConnectTo( NIL );
		f := NIL;
		filename := '';
		mode := noFileOpen
	END Close;
	
	PROCEDURE Delete* ( name: ARRAY OF CHAR );
	BEGIN
		Files.dir.Delete( loc, name$ );
		IF  loc.res = 0  THEN
			Dialog.ShowMsg( "Файл "+name$+" стерт." )
		ELSIF  loc.res = 2  THEN
			Dialog.ShowMsg( "Файл "+name$+" не найден." )
		ELSE
			Dialog.ShowMsg( "Неизвестная ошибка при попытке стереть файл." );
		END
	END Delete;
	
	PROCEDURE New* ( name: Files.Name );
		VAR  fi: Files.FileInfo;  NAME, FINAME: ARRAY 256 OF CHAR;
	BEGIN
		ASSERT( name # '', 30 );
		ASSERT( mode = noFileOpen, 20 );
		filename := name$;
		Strings.ToUpper( name$, NAME );
		
		(* проверяем, что такого файла нет [что-то у меня сам Блэкбокс не хочет проверять ...] *)
		fi := Files.dir.FileList( loc );
		LOOP
			IF  fi = NIL  THEN  EXIT  END;
			Strings.ToUpper( fi.name, FINAME );
			IF  FINAME = NAME  THEN  EXIT  END;
			fi := fi.next
		END;
		IF  fi # NIL  THEN
			Dialog.ShowMsg( "Файл " + name$ 
												+ " уже существует. Выберите другое имя или сотрите старый." );
			HALT(128)
		END;
		f := Files.dir.New( loc, Files.ask );
		wr.ConnectTo( f );  
		mode := writing
	END New;
	
	PROCEDURE WriteInt* ( n: INTEGER );
	BEGIN  ASSERT( mode = writing, 21 );
		wr.WriteInt( n )
	END WriteInt;
	
	PROCEDURE WriteChar* ( ch: CHAR );
	BEGIN  ASSERT( mode = writing, 21 );
		wr.WriteChar( ch )
	END WriteChar;
	
	PROCEDURE WriteSChar* ( ch: SHORTCHAR );
	BEGIN  ASSERT( mode = writing, 21 );
		wr.WriteSChar( ch )
	END WriteSChar;
	
	PROCEDURE WriteString* ( a: ARRAY OF CHAR );
	BEGIN  ASSERT( mode = writing, 21 );
		wr.WriteString( a )
	END WriteString;
	
	PROCEDURE WriteReal* ( r: REAL );
	BEGIN  ASSERT( mode = writing, 21 );
		wr.WriteReal( r )
	END WriteReal;
	
	PROCEDURE Open* ( name: Files.Name );
	BEGIN
		ASSERT( name # '', 30 );
		ASSERT( mode = noFileOpen, 20 );

		f := Files.dir.Old( loc, name$, Files.shared );
		IF  loc.res = 0  THEN
			rd.ConnectTo( f );  ASSERT( rd.rider # NIL, 100 );
			filename := name$;
			mode := reading
		ELSE
			Dialog.ShowMsg( "Открыть файл "+name$+" не удалось." );
			ASSERT( filename = '', 70 );
			ASSERT( mode = noFileOpen, 71 );
		END
	END Open;
	
	PROCEDURE ReadInt* ( OUT n: INTEGER );
	BEGIN  ASSERT( mode = reading, 23 );
		rd.ReadInt( n );
		ASSERT( ~rd.rider.eof, 61 )
	END ReadInt;
	
	PROCEDURE ReadChar* ( OUT ch: CHAR );
	BEGIN  ASSERT( mode = reading, 23 );
		rd.ReadChar( ch );
		ASSERT( ~rd.rider.eof, 61 )
	END ReadChar;
	
	PROCEDURE ReadSChar* ( OUT ch: SHORTCHAR );
	BEGIN  ASSERT( mode = reading, 23 );
		rd.ReadSChar( ch );
		ASSERT( ~rd.rider.eof, 61 )
	END ReadSChar;
	
	PROCEDURE ReadString* ( OUT a: ARRAY OF CHAR );
	BEGIN  ASSERT( mode = reading, 23 );
		rd.ReadString( a );
		ASSERT( ~rd.rider.eof, 61 )
	END ReadString;
	
	PROCEDURE ReadReal* ( OUT r: REAL );
	BEGIN  ASSERT( mode = reading, 23 );
		rd.ReadReal( r );
		ASSERT( ~rd.rider.eof, 61 )
	END ReadReal;
	
BEGIN   loc := Files.dir.This( '' );  path := '';  filename := '';
CLOSE  Close
END  i21eduFiles.