Modula-2 でプログラミング -- 文字列探索プログラム find の製作 (その3) -- ― 2025年01月05日 21:19
前回紹介したfindプログラムは、FileSearchモジュールの不備で、ファイル一覧の構造が 丸見えになっていました。FileSearchモジュールに2つ手続きを追加して不具合を解消しました。
新しいFileSearchモジュールの定義モジュールは以下の通り。
DEFINITION MODULE FileSearch; FROM OpSys IMPORT FCB,FCBFileName; EXPORT QUALIFIED pFileList,FileNameNode, GetNextFile,GetFileName,LoginDisk,MakeFileList,DumpFileList; CONST DMABufferSize = 128; FileNameSize = 14; TYPE pFileList = POINTER TO FileNameNode; FileNameNode = RECORD FileName: ARRAY [0..FileNameSize] OF CHAR; Next: pFileList END; DMA = ARRAY [0..DMABufferSize-1] OF CHAR; PROCEDURE GetNextFile(FileLIst: pFileList): pFileList; PROCEDURE GetFileName(FileList: pFileList;VAR FileName: ARRAY OF CHAR); PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; PROCEDURE MakeFileList(FIleMatch: ARRAY OF CHAR): pFileList; PROCEDURE DumpFileList(pList: pFileList); END FileSearch.手続き、次のファイルを取り出すGetNextFileとファイル名を取り出すGetFileNameを追加しました。 実現モジュールは以下の通り。
IMPLEMENTATION MODULE FileSearch; FROM InOut IMPORT WriteHex,Write,WriteString,WriteLn; FROM OpSys IMPORT FCB,FCBFileName,BdosFunctions,Bdos; FROM SYSTEM IMPORT ALLOCATE,TSIZE,ADR,WORD; FROM FileNames IMPORT StrToFCB,FCBToStr,NameState; CONST EOS = 0C; PROCEDURE GetNextFile(FileList: pFileList): pFileList; BEGIN RETURN FileList^.Next END GetNextFile; PROCEDURE GetFileName(FileList: pFileList; VAR FileName: ARRAY OF CHAR); VAR i: CARDINAL; BEGIN i := 0; WHILE ( FileList^.FileName[i] # EOS ) DO FileName[i] := FileList^.FileName[i]; INC(i) END; FileName[i] := EOS END GetFileName; PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; VAR DiskCode: CARDINAL; Junk: WORD; BEGIN IF FCBBuf.name.disk = 0C THEN Bdos(retCDsk,Junk,DiskCode); RETURN (CHR(ORD(DiskCode)+ORD('A'))); ELSE RETURN (CHR(ORD(FCBBuf.name.disk)+ORD('A')-1)); END; END LoginDisk; PROCEDURE MakeFileList(FileMatch: ARRAY OF CHAR): pFileList; VAR Disk: CHAR; FCBBuffer: FCB; BdosRc: CARDINAL; DMABuffer: DMA; CPos: CARDINAL; NameStatus: NameState; pList: pFileList; pNewFileName: pFileList; FCBFile: FCBFileName; Formatted: BOOLEAN; Junk: WORD; BEGIN pList := NIL; (* Clear FCB Buffer and set file name *) FCBBuffer.name.text := ''; FCBBuffer.rest := ''; NameStatus := StrToFCB(FileMatch,FCBBuffer.name); Disk := LoginDisk(FCBBuffer); (* set DMA Bufer *) Bdos(setDMA,ADR(DMABuffer),Junk); (* find first much file *) Bdos(searchFst,ADR(FCBBuffer),BdosRc); WHILE BdosRc # 255 DO ALLOCATE(pNewFileName,TSIZE(FileNameNode)); FOR CPos := 0 TO 11 DO FCBFile.text[CPos] := DMABuffer[CPos+BdosRc*32] END; FCBFile.disk := CHR(ORD(Disk) - ORD('A') + 1); FCBToStr(FCBFile,pNewFileName^.FileName,FALSE); pNewFileName^.Next := pList; pList := pNewFileName; (* find next file *) Bdos(searchNxt,Junk,BdosRc); END; RETURN pList END MakeFileList; PROCEDURE WriteFileName(FileName: ARRAY OF CHAR); BEGIN WriteString(FileName); WriteLn END WriteFileName; PROCEDURE DumpFileList(pList: pFileList); BEGIN WHILE pList # NIL DO WriteFileName(pList^.FileName); pList := pList^.Next; END; END DumpFileList; END FileSearch.
これらの変更を反映したfindは、以下のとおり。
MODULE Find; FROM InOut IMPORT Write,WriteCard,WriteString,WriteLn; FROM Files IMPORT FILE,FileState,Open,Close,Read; FROM CmdArgs IMPORT Argc,Argv; FROM FileSearch IMPORT GetFileName,GetNextFile, FileNameNode,MakeFileList,pFileList; FROM BasicFileIO IMPORT FileIOStruct,pFileIOStruct, OpenFile,CloseFile,EOFFile,FileIOStatus; FROM StdFileIO IMPORT GetLine; CONST EOS = 0C; MAXLINE = 128; FILENAMESIZE = 14; EOFMARK = 32C; VAR FileName: ARRAY [0..FILENAMESIZE] OF CHAR; FileMatch: ARRAY [0..FILENAMESIZE] OF CHAR; Target: ARRAY [0..MAXLINE] OF CHAR; CPos,FileNumber,LineNumber,nArgc: CARDINAL; pList: pFileList; PROCEDURE putLine(FileName:ARRAY OF CHAR;Line:CARDINAL; Buffer: ARRAY OF CHAR); BEGIN WriteString(FileName); Write(' ');WriteCard(Line,1);Write(':'); WriteString(Buffer); WriteLn END putLine; PROCEDURE findTarget(Target,Line:ARRAY OF CHAR): BOOLEAN; VAR t,l: CARDINAL; found: BOOLEAN; BEGIN found := FALSE; t := 0; l := 0; WHILE (Line[l] # EOS) AND (NOT found) DO IF Line[l] = Target[0] THEN t := 1; WHILE Line[l+t] = Target[t] DO INC(t); END; IF Target[t] = EOS THEN found := TRUE; END; END; INC(l); END; RETURN found END findTarget; PROCEDURE Usage(); BEGIN WriteString('find');WriteLn; WriteString(' TargetString File1 File2 FIle3,,,,');WriteLn END Usage; PROCEDURE MatchLines(FileName,TargetString: ARRAY OF CHAR); VAR pFileIO: pFileIOStruct; Line: ARRAY [0..MAXLINE-1] OF CHAR; Chars: CARDINAL; NLines: CARDINAL; Junk: FileIOStatus; BEGIN IF OpenFile(FileName,pFileIO) = Success THEN NLines := 1; WHILE NOT EOFFile(pFileIO) DO Chars := GetLine(pFileIO,Line); IF findTarget(TargetString,Line) THEN putLine(FileName,NLines,Line); END; INC(NLines); END; Junk := CloseFile(pFileIO) END END MatchLines; BEGIN nArgc := Argc(); IF nArgc < 1 THEN Usage(); HALT END; Argv(0,Target); FileNumber := 1; WHILE FileNumber < nArgc DO Argv(FileNumber,FileMatch); pList := MakeFileList(FileMatch); WHILE pList # NIL DO GetFileName(pList,FileName); MatchLines(FileName,Target); pList := GetNextFile(pList) END; INC(FileNumber) END END Find.
これで、FileSearchモジュール内部のデータ構造をFindが知る必要がなくなりました。
最近のコメント