Unit FileIO;

{***************************************************************************}

{* Dir                I/O       FILE    integer

{* DirDirs            I/O       FILE    integer

{* DirExists          I/O       FILE

{* DirFiles           I/O       FILE

{* DirKill            I/O       FILE

{* DirKillDef         I/O       FILE    definitely kills the dir

{* DirMake            I/O       FILE

{* FileDataBool       I/O       FILE    bool: true if no IOError

{* FileCopy           I/O       FILE

{* FileCreate         I/O       FILE

{* FileDel            I/O       FILE

{* FileExists         I/O       FILE

{* FileKill           I/O       FILE    integer

{* FileKillDef        I/O       FILE    integer  definitely kills it

{* FileLine           I/O       FILE

{* FileLineCount      I/O       FILE

{* FileLineDel        I/O       FILE

{* FileOpen           I/O       FILE

{* FileSearch         I/O       FILE

{* GetDirFile         I/O       FILE

{* GetDirFileOnly     I/O       FILE

{* GetFileName        I/O       FILE

{* SayFile            I/O       FILE

{* WildCardFormat     I/O       FILE

{***************************************************************************}



interface

{***************************************************************************}

{***************************************************************************}



Function  Dir(DirStr: string): integer;

Function  DirDirs(DirStr: string): integer;

Function  DirExists(DirStr: string): boolean;

procedure DirFiles(SearchStr: string; var Count: integer);

Function  DirKill(DirStr: string): integer;

Function  DirKillDef(DirStr: string): integer;

Function  DirMake(DirStr: string): boolean;

Procedure FileCopy(OriginalFile: string; NewFile: string);

Function  FileCreate(NewFile: string): boolean;

Function  FileDataBool(OpChar: char; FileStr: string; PosNum: longint;

            var BoolVal: boolean): boolean;

procedure FileDel(FileSpec: string; var Code: integer);

function  FileExists(FileStr: string): boolean;

Function  FileExistsMake(FileStr: string): boolean;

Function  FileKill(DeadFile: string): integer;

Function  FileKillDef(DeadFile: string): integer;

Function  FileLine(ModeChar: char; FileStr: string;

            LineNum: integer; var LineStr: string): boolean;

Function  FileLineCount(FileStr: string): integer;

Procedure FileLineDel(FileStr: string; StartNum, StopNum: integer);

Function  FileOpen(ModeChar:char; InFileStr:string;

            var InFile:text): integer;

Function  FileSearch(ModeChar: char; FileStr: string;

            var MatchStr: string): integer;

function  GetDirFile(SearchStr: string): string;

function  GetDirFileOnly(SearchStr: string): string;

procedure GetFileName(var Lead8, Ext: string);

Procedure SayFile(SayFileStr: string);

procedure SplitFileName(InFile: string; var Lead8, Extension: string);



implementation

{***************************************************************************}

{***************************************************************************}

Uses

  Crt,

  Dos,

  Globals,

  IOPorts, {* fix this! this is BBS specific for Say & SayL *}

  Keyboard,

  MiscSubs,

  Video;



const

  TempFile = 'TempFile.TMP';



Function Dir(DirStr: string): integer;

{***************************************************************************}

var

  count: integer;

  S: SearchRec;

begin

  count := 0;

  FindFirst(DirStr, AnyFile, S);

  while DosError <> 18 do

    begin

      writeln(S.Name);

      Inc(Count);

      FindNext(S);

    end;

  Dir := Count;

end;



Function DirDirs(DirStr: string): integer;

{***************************************************************************}

var

  count: integer;

  S: SearchRec;

begin

  count := 0;

  FindFirst(DirStr, AnyFile, S);

  while DosError <> 18 do

    begin

      if (S.Attr and Directory = Directory) and

        ((S.Name <> '.') and (S.Name <> '..')) then

          begin

            if (Count mod 4 = 0) and (Count <> 0) then

              writeln;

            GotoXY((Count mod 4)*20, WhereY);

            write(S.Name);

            Inc(Count);

          end;

      FindNext(S);

    end;

  if count <> 0 then

    writeln;

  DirDirs := Count;

end;



Function DirExists(DirStr: string): boolean;

{***************************************************************************}

var

  S: SearchRec;

begin

  FindFirst(DirStr, Directory, S);

  if S.Name <> '' then

    DirExists := true

  else

    begin

      SayL('Creating '+DirStr+'...');

      {$I-}

      MkDir(DirStr);

      {$I+}

      if IOResult <> 0 then

        DirExists := false

      else

        DirExists := true;

    end;

end;



procedure DirFiles(SearchStr: string; var Count: integer);

{***************************************************************************}

var

  DirInfo: SearchRec;

begin

  writeln('Directory of all "',SearchStr,'".');

  Count := 0;

  FindFirst(SearchStr,AnyFile,DirInfo);

  while DosError = 0 do

    begin

      if DirInfo.Attr <> 16 then

        begin

          GotoXY((Count mod 4)*20, WhereY);

          Inc(Count);

          Write(Count,') ',DirInfo.Name);

          if Factorial(Count, 4) then

            writeln;

        end;

      FindNext(DirInfo);

    end;

  if WhereX <> 1 then

    writeln;

end;



Function  DirKill(DirStr: string): integer;

{***************************************************************************}

begin

  {$I-}

  RmDir(DirStr);

  {$I+}

  DirKill := IOResult;

end;



Function  DirKillDef(DirStr: string): integer;

{***************************************************************************}

var

  DirResult: integer;

  S: SearchRec;

begin

  DirResult := DirKill(DirStr);

  if DirResult = 5 then

    begin

      FindFirst(DirStr+'\*.*', $3F, S);

      repeat

        if S.Attr and $10 = $10 then {* directory *}

          begin

            if (S.Name <> '.') and (S.Name <> '..') then

              DumInt := DirKillDef(DirStr + '\' + S.Name);

          end

        else

          DirResult := FileKillDef(DirStr + '\' + S.Name);

        FindNext(S);

      until DosError = 18; {* no more files *}

      DirResult := DirKill(DirStr);

    end;

  DirKillDef := DirResult;

end;



Function  DirMake(DirStr: string): boolean;

{***************************************************************************}

{* Will create multi-level directories with one call.

{***************************************************************************}

var

  SaveDir: string;

  DirChar: char;

  WorkDir: string;

begin

  GetDir(0, SaveDir);

  while DirStr <> '' do

    begin

      WorkDir := '';

      repeat

        DirChar := DirStr[1];

        DirStr := copy(DirStr, 2, length(DirStr) - 1);

        if DirChar <> '\' then

          WorkDir := WorkDir + DirChar;

      until (DirChar = '\') or (length(DirStr) = 0);

      {$I-}

      MkDir(WorkDir);

      if DirStr <> '' then

        ChDir(WorkDir);

      {$I+}

    end;

  DumInt := IOResult;

  {$I-}

  ChDir(SaveDir);

  {$I+}

  if IOResult = 0 then

    DirMake := true

  else

    DirMake := false;

end;



Procedure FileCopy(OriginalFile: string; NewFile: string);

{***************************************************************************}

var

  Orig,

  NewF: text;

  LineStr: string;

begin

  if FileOpen('R', OriginalFile, Orig) = 0 then

    if FileOpen('W', NewFile, NewF) = 0 then

      begin

        while not(EOF(Orig)) do

          begin

            readln(Orig, LineStr);

            writeln(NewF, LineStr);

          end;

        close(Orig);

        close(NewF);

      end;

end;



Function FileCreate(NewFile: string): boolean;

{***************************************************************************}

var

  NF: text;

begin

  if FileOpen('W', NewFile, NF) = 0 then

    begin

      close(NF);

      FileCreate := true;

    end

  else

    FileCreate := false;

end;



Function FileDataBool(OpChar: char; FileStr: string; PosNum: longint;

           var BoolVal: boolean): boolean;

{***************************************************************************}

var

  Temp: boolean;

  F: file of boolean;

  alpha: longint;

begin

{$I-}

  Temp := false;

  case OpChar of

    'R':

      begin

        Assign(F, FileStr);

        Reset(F);

        if PosNum <= FileSize(F) then

          begin

            Seek(F, PosNum);

            Read(F, BoolVal);

          end;

        Close(F);

        Temp := true;

      end;

    'W':

      begin

        Assign(F, FileStr);

        Reset(F);

        if PosNum <= FileSize(F) then

          begin

            Seek(F, PosNum);

            write(F, BoolVal);

          end

        else

          begin

            DumBool := false;

            Seek(F, FileSize(F));

            for alpha := 1 to PosNum - FileSize(F) do

              write(F, DumBool);

            write(F, BoolVal);

          end;

        Close(F);

      end;

  end; {* case *}

  if IOResult <> 0 then

    Temp := false;

  FileDataBool := Temp;

{$I+}

end;



procedure FileDel(FileSpec: string; var Code: integer);

{***************************************************************************}

{* page 147 Turbo Pascal Programmer's Toolkit by Rugg and Feldman

{***************************************************************************}

var

  Reg: registers;

begin

  FileSpec := FileSpec + chr(0);

  Reg.DX := ofs(FileSpec[1]);

  Reg.DS := seg(FileSpec[1]);

  Reg.AX := $4100;

  msdos(Reg);

  Code := Lo(Reg.Ax);

  if (Reg.Flags and $01) = 0 then

    Code := 0;

end;



function  FileExists(FileStr: string): boolean;

{***************************************************************************}

var

  S:  SearchRec;

begin

  S.Name := '';

  FindFirst(FileStr, AnyFile, S);

  if S.Name = '' then

    FileExists := false

  else

    FileExists := true;

end;



Function  FileExistsMake(FileStr: string): boolean;

{***************************************************************************}

var

  Temp: boolean;

begin

  Temp := FileExists(FileStr);

  if not(Temp) then

    Temp := FileCreate(FileStr);

  FileExistsMake := Temp;

end;



Function FileKill(DeadFile: string): integer;

{***************************************************************************}

var

  DF: text;

begin

  Assign(DF, DeadFile);

  {$I-}

  Erase(DF);

  {$I+}

  FileKill := IOResult;

end;



Function FileKillDef(DeadFile: string): integer;

{***************************************************************************}

var

  DF: text;

begin

  Assign(DF, DeadFile);

  {$I-}

  SetFAttr(DF, 0);

  Erase(DF);

  {$I+}

  FileKillDef := IOResult;

end;



Function  FileLine(ModeChar: char; FileStr: string; LineNum: integer;

            var LineStr: string): boolean;

{***************************************************************************}

var

  alpha: integer;

  InStr: string;

  TF,

  InFile: text;

begin

  ModeChar := upcase(ModeChar);

  if FileOpen('R', FileStr, InFile) <> 0 then

    begin

      if ModeChar = 'O' then

        begin

          if FileCreate(FileStr) then

            begin

              if FileOpen('R', FileStr, InFile) <> 0 then

                begin

                  FileLine := false;

                  exit;

                end;

            end

          else

            begin

              FileLine := false;

              exit;

            end;

        end

      else

        begin

          FileLine := false;

          exit;

        end;

    end;

  if FileOpen('W', TempFile, TF) <> 0 then

    begin

      close(InFile);

      FileLine := false;

      exit;

    end;

  case ModeChar of

    'R': {* Read a line *}

      begin

        close(TF);

        for alpha := 1 to LineNum do

          readln(InFile, LineStr);

        close(InFile);

      end;

    'D': {* Delete *}

      begin

        alpha := 0;

        repeat

          inc(alpha);

          readln(InFile, InStr);

          if alpha <> LineNum then

            writeln(TF, InStr);

        until EOF(InFile);

        close(InFile);

        close(TF);

        Erase(InFile);

        Rename(TF, FileStr);

      end;

    'I': {* Insert *}

      begin

        for alpha := 1 to LineNum - 1 do

          begin

            if EOF(InFile) then

              InStr := ''

            else

              readln(InFile, InStr);

            writeln(TF, InStr);

          end;

        writeln(TF, LineStr);

        while not(EOF(InFile)) do

          begin

            readln(InFile, InStr);

            writeln(TF, InStr);

          end;

        close(TF);

        close(InFile);

        Erase(InFile);

        Rename(TF, FileStr);

      end;

    'O': {* Overwrite *}

      begin

        for alpha := 1 to LineNum - 1 do

          begin

            if EOF(InFile) then

              InStr := ''

            else

              readln(InFile, InStr);

            writeln(TF, InStr);

          end;

        if not(EOF(InFile)) then

          readln(InFile, DumStr);

        writeln(TF, LineStr);

        while not(EOF(InFile)) do

          begin

            readln(InFile, InStr);

            writeln(TF, InStr);

          end;

        close(TF);

        close(InFile);

        Erase(InFile);

        Rename(TF, FileStr);

      end;

    else

      begin

        SayL(Beep+'Function Text Line used improperly!');

        FileLine := false;

        exit;

      end;

  end; {case}

  FileLine := true;

end;



Function  FileLineCount(FileStr: string): integer;

{***************************************************************************}

var

  TempFileLineCount: integer;

  FS: text;

begin

  TempFileLineCount := -1;

  if FileOpen('R', FileStr, FS) = 0 then

    begin

      TempFileLineCount := 0;

      while not(EOF(FS)) do

        begin

          readln(FS);

          inc(TempFileLineCount);

        end;

      close(FS);

    end;

  FileLineCount := TempFileLineCount;

end;



Procedure FileLineDel(FileStr: string; StartNum, StopNum: integer);

{***************************************************************************}

var

  FS,

  TF: text;

  Line: integer;

  InStr: string;

begin

  if (StartNum <= 0) or (StopNum < StartNum) then

    begin

      writeln('No lines deleted from the file ',FileStr,'.');

      exit;

    end;

  Assign(FS, FileStr);

  Reset(FS);

  Assign(TF, TempFile);

  Rewrite(TF);

  Line := 0;

  while not(EOF(FS)) do

    begin

      readln(FS, InStr);

      Inc(Line);

      if (Line < StartNum) or (Line > StopNum) then

        writeln(TF, InStr);

    end;

  close(FS);

  close(TF);

  erase(FS);

  rename(TF, FileStr);

end;



Function FileOpen(ModeChar:char; InFileStr:string; var InFile:text): integer;

{***************************************************************************}

var

  Dir: DirStr;

  Name: NameStr;

  Ext: ExtStr;

  TempFileOpen: integer;

  CheckIO: integer;

begin

  Assign(InFile, InFileStr);

  ModeChar := UpCase(ModeChar);

  {$I-}

  case ModeChar of

    'R': Reset(InFile);

    'W':

      begin

        Rewrite(InFile);

        if IOResult = 3 then

          if FileOpen('P', InFileStr, InFile) = 0 then

            Rewrite(InFile);

      end;

    'A': begin

           Append(InFile);

           CheckIO := IOResult;

           if CheckIO <> 0 then

             begin

               case CheckIO of

                 2: Rewrite(InFile);

                 3:

                   begin

                     DumInt := FileOpen('P', InFileStr, InFile);

                     Rewrite(InFile);

                   end;

                 else

                   Append(InFile);

               end; {case}

             end;

         end;

    'P': {* create Path *}

      begin

        FSplit(InFileStr, Dir, Name, Ext);

        Dir := copy(Dir, 1, length(Dir) - 1);

        DumBool := DirMake(Dir);

      end;

    else

      SayL(Beep+'Function FileOpen improperly used!');

  end; {case}

  {$I+}

  TempFileOpen := IOError;

  if TempFileOpen <> 0 then

    ErrSayL('** Error with "'+InFileStr+'".');

  FileOpen := TempFileOpen;

end;



Function  FileSearch(ModeChar: char; FileStr: string;

            var MatchStr: string): integer;

{***************************************************************************}

{* Modes: 'u'=case insensitive, 'l'=case sensitive

{* Return: -1 if file problem or bad mode, 0 if not found

{***************************************************************************}

var

  TempFileSearch: integer;

  Match: boolean;

  LineStr: string;

  alpha: integer;

  FS: text;

begin

  ModeChar := upcase(ModeChar);

  case ModeChar of

    'U': MatchStr := UpCaseStr(MatchStr);

    'L':

      begin

      end;

    else

      begin

        SayL(Beep+'Bad mode character used with Function FileSearch!');

        FileSearch := -1;

        exit;

      end;

  end; {case}

  TempFileSearch := -1;

  Match := false;

  alpha := 0;

  if FileOpen('R', FileStr, FS) = 0 then

    begin

      TempFileSearch := 0;

      repeat

        inc(alpha);

        readln(FS, LineStr);

        if ModeChar = 'U' then

          begin

            if UpCaseStr(LineStr) = MatchStr then

              begin

                Match := true;

                MatchStr := LineStr;

              end;

          end

        else

          if LineStr = MatchStr then

            Match := true;

      until Match or EOF(FS);

      close(FS);

    end;

  if Match then

    TempFileSearch := alpha;

  FileSearch := TempFileSearch;

end;



Function GetDirFile(SearchStr: string): string;

{***************************************************************************}

var

  Count: integer;

  TempDirFile: string;

  FileOpt: integer;

  DirInfo: SearchRec;

  FileNameGood: boolean;

  Lead8: string;

begin

  TempDirFile := '';

  DirFiles(SearchStr, Count);

  writeln(Count+1,') Input a new file name.');

  AskPos('Which file (1 to '+StrInt(Count+1)+')',Count+1, FileOpt);

  if FileOpt = Count + 1 then

    begin

      repeat

        SplitFileName(SearchStr, DumStr, TempDirFile);

        GetFileName(Lead8, DumStr);

        TempDirFile := Lead8 + '.' + TempDirFile;

        writeln('Creating ',TempDirFile,'...');

        wait;

        FileNameGood := WildCardFormat(SearchStr,TempDirFile);

        if not(FileNameGood) then

          begin

            write(Beep);

            writeln('Must be of ',SearchStr,' format!');

            Wait;

            BackUpLines(5);

          end;

      until FileNameGood;

    end

  else

    begin

      FindFirst(SearchStr, AnyFile, DirInfo);

      for count := 1 to FileOpt do

        begin

          if DirInfo.Attr = 16 then

            count := count - 1

          else

            if count = FileOpt then

              TempDirFile := DirInfo.Name;

          FindNext(DirInfo);

        end;

    end;

  GetDirFile := TempDirFile;

end;



function GetDirFileOnly(SearchStr: string): string;

{***************************************************************************}

var

  Count: integer;

  TempDirFile: string;

  FileOpt: integer;

  DirInfo: SearchRec;

  FileNameGood: boolean;

begin

  TempDirFile := '';

  DirFiles(SearchStr, Count);

  if Count = 0 then

    begin

      Write(Beep);

      writeln;

      writeln('No ',SearchStr,' files found!');

      PoliteHalt;

    end;

  AskPos('Which file (1 to '+StrInt(Count)+')',Count, FileOpt);

  FindFirst(SearchStr, AnyFile, DirInfo);

  for count := 1 to FileOpt do

    begin

      if DirInfo.Attr = 16 then

        count := count - 1

      else

        if count = FileOpt then

          TempDirFile := DirInfo.Name;

      FindNext(DirInfo);

    end;

  GetDirFileOnly := TempDirFile;

end;



procedure GetFileName(var Lead8, Ext: string);

{***************************************************************************}

var

  InStr: string;

  NameGood: boolean;

begin

  repeat

    Ask('File name', InStr);

    SplitFileName(InStr, Lead8, Ext);

    if Lead8 = '' then

      begin

        NameGood := false;

        Write(Beep);

        BackUpLine;

      end

    else

      NameGood := true;

  until NameGood;

end;



Procedure SayFile(SayFileStr: string);

{***************************************************************************}

var

  TheSayFile: text;

  LineStr: string;

begin

  Assign(TheSayFile, SayFileStr);

  {$I-}

  Reset(TheSayFile);

  {$I+}

  if IOGood then

    begin

      clr;

      repeat

        readln(TheSayFile, LineStr);

        Say(LineStr);

        if WhereY >= 22 then

          begin

            wait;

            clr;

          end;

      until EOF(TheSayFile);

    end;

  Close(TheSayFile);

  Wait;

end;



procedure SplitFileName(InFile: string; var Lead8, Extension: string);

{***************************************************************************}

{*  If a non-filename is inputted, Lead8 will contain the first 8 and

{*  Extension will contain the next 3.  The rest will be discarded.

{***************************************************************************}

var

  Dot: integer;

  ExtLen: integer;

begin

  Dot := Pos('.',InFile);

  if Dot > 9 then

    Lead8 := copy(InFile, 1, 8)

  else

    if Dot = 1 then

      Lead8 := ''

    else

      if Dot = 0 then

        Lead8 := copy(InFile, 1, 8)

      else

        Lead8 := copy(InFile, 1, Dot - 1);

  if Dot > 0 then

    begin

      ExtLen := length(InFile) - length(Lead8) - 1;

      if ExtLen > 3 then

        ExtLen := 3;

      Extension := copy(InFile, Dot+1, ExtLen);

    end

  else

    Extension := '';

end;





{***************************************************************************}

{***************************************************************************}

{***************************************************************************}

begin

end.