|
Volume Number: | 2 | |
Issue Number: | 7 | |
Column Tag: | Modula-2 Mods |
Make a Path Name for HFS
By Tom Taylor, Santa Clara, CA, MacTutor Contributing Editor
Extending Modula-2 for HFS Support
The Macintosh low-level File Manager is probably familiar to anyone who has programmed in another language besides Modula-2 on the Mac. Until the Heirarchical File System was released, there wasn't a tremendous amount of motivation to use the low level parameter block routines from Modula-2. The high-level File Manager routines implemented by MacModula-2 were usually enough to get the job done. With the release of the Mac Plus, however, the high level calls are not enough. Therefore, I decided to implement a library module that includes all of the low-level File Manager calls specified in the new chapter of the File Manager.
The Low-Level File Manager
Most people are already familiar with the low-level File Manager. For those who are not, a little introduction would be helpful. First of all, the low-level File Manager routines exist in ROM. The high level File Manager routines described by the File Manager Inside Macintosh chapter do not. Instead, the high level calls consist of glue code that calls the low-level routines. Each low-level procedure takes one parameter: a pointer to a parameter block. This parameter block, however, is used to hold many input and output parameters. The File Manager chapter does an excellent job of showing which fields of the parameter block are used for each call. Before using the module presented in this article, you must read the File Manager chapter of Inside Macintosh. In fact, it would be most helpful if you were to read the new chapter that explains the File Manager in terms of both MFS and HFS. There are six different types of parameter blocks. Three of the six blocks contain variant records.
A typical low-level File Manager call looks like this:
PROCEDURE PBCallName (paramBlock: PtrToParamBlk; async: BOOLEAN) : OsErr;
The first parameter is a pointer to one of the six different parameter blocks. Generally, I find it easiest to declare the actual block as a variable and then pass ADR(block) for this parameter. The second parameter, "async", specifies whether the routine should be executed synchronously or asynchronously. It is beyond the scope of this article to explain how to use asynchronous calls in an interpreted system like MacModula-2. Therefore, my example program will always perform synchronous calls by passing FALSE for this parameter.
How it all works
The definition module, PBFileManager.DEF, is very straightforward. All of the parameter block types and procedures are defined. The implementation module is a bit trickier. Basically, every procedure makes a call to the procedure LowLevelPB passing four parameters: the parameter block address, the asynch flag, the value of the A-Trap that ends up calling the actual File Manager procedure, and a routine selector for those procedures that are implemented with the same A-Trap (which are new, HFS only calls). The LowLevelPB procedure immediately makes a call to an assembly routine that calls the toolbox. The assembly routine (source in PBFileManagerASM.ASM) must unstack the A-Trap value and the asynch flag. If the call is to be performed asynchronously, the asynch bit in the trap word is set. In either case, the A-Trap is installed and executed and the returned value is returned back to the Modula-2 calling procedure (and returned back up the many levels of procedure calls!). This has to be the simplest library module ever written, yet one of the most powerful because it gives the Modula-2 programmer almost complete control of the Mac's file system. That is why I thought it is an appropriate subject for this month's article.
Fig. 1 Standard file Dialog to select file name
An example program
Any module is incomplete without an example program. The program here, MakePath.MOD, shows how to find the complete pathname to a file. The program puts up the SFGetFile and allows the user to select any file. Then the program displays a window with the file's complete path name (up to 255 characters, anyway...). Besides showing how to use a few of the low-level File Manager routines, it also shows how to determine if the host Mac is running the HFS file system and whether a volume is an HFS or MFS volume. Because of this, the program will run on any Mac, HFS or not (fat or skinny, regular or Plus, etc.). Macintosh Technical Note #57 says that the location 03F6h contains a global flag that says whether HFS is installed or not. Therefore, the variable HFS in MakePath.MOD is declared as:
VAR HFS [03f6h] : INTEGER;
If HFS = -1, the Macintosh is running MFS, else it's running HFS. When HFS is installed, it's also necessary to determine whether a volume is a MFS or HFS volume. The PBHGetVInfo call will return a field in the parameter block called IOVSigWord. This variable will be D2D7h for a MFS volume and 4244h for an HFS volume.
For HFS volumes, the PBGetCatInfo call is the basis for building path names. By passing -1 in the ioFDirIndex field, PBGetCatInfo will return information about the directory with the WDRefNum passed in the ioVRefNum field. Every directory on an HFS volume has a different directory ID. The root directory always has directory ID of 2. Not only does PBGetCatInfo return the directory ID (in ioDrDirID) and the directory's name (in ioNamePtr), it also returns the directory's parent ID. By calling PBGetCatInfo until the directory ID equals two, the path name can be built.
Fig. 2 Path Name Program constructs Path
Here are the steps for building the PBFileManager module and the example program:
--- To make the library module... ---
1-Assemble PBFileManagerASM.ASM
2-Link (using MDS or Consulair Link) the PBFileManagerASM.REL file using the file PBFileManagerASM.link
3-Run RMaker on PBFileManager.r
4-Rename PBFileManager.REL.RSRC to PBFileManager.REL
5-Using M2 Compiler, compile PBFileManager.DEF and PBFileManager.MOD
--- To make the example program... ---
1-Run RMaker on MakePath.r
2-Rename MakePath.REL.RSRC to MakePath.REL
3-Using M2 Compiler, compile and link MakePath.MOD
4-Execute MakePath.LOD and have fun!
----------- PBFileManager.DEF ----------- (* Tom Taylor 3707 Poinciana Dr. #137 Santa Clara, CA 95051 *) DEFINITION MODULE PBFileManager; (* This module defines the low level file system described in the latest File Manager documentation. The types and procedures defined in this module support both MFS and HFS calls. *) FROM OSQueues IMPORT QElemPtr; FROM MacSystemTypes IMPORT LongCard, Ptr, OsErr, StringPtr; FROM FileManager IMPORT FInfo; FROM SYSTEM IMPORT ADDRESS; EXPORT QUALIFIED (* Types *) ParamBlkType, ParmBlkPtr, ParamBlockRec, CMovePBPtr, CMovePBRec, HParmBlkPtr, HParamBlockRec, WDPBPtr, WDPBRec, CInfoType, CInfoPBPtr, CInfoPBRec, FCBPBPtr, FCBPBRec, (* Procedures *) PBMountVol, PBGetVInfo, PBHGetVInfo, PBHSetVInfo, PBGetVol, PBHGetVol, PBSetVol, PBHSetVol, PBFlushVol, PBUnmountVol, PBOffLine, PBEject, PBOpen, PBHOpen, PBOpenRF, PBHOpenRF, PBLockRange, PBUnlockRange, PBRead, PBWrite, PBGetFPos, PBSetFPos, PBGetEOF, PBSetEOF, PBAllocate, PBAllocContig, PBFlushFile, PBClose, PBCreate, PBHCreate, PBDirCreate, PBDelete, PBHDelete, PBGetFInfo, PBHGetFInfo, PBSetFInfo, PBHSetFInfo, PBSetFLock, PBHSetFLock, PBRstFLock, PBHRstFLock, PBSetFVers, PBRename, PBHRename, PBGetCatInfo, PBSetCatInfo, PBCatMove, PBOpenWD, PBCloseWD, PBGetWDInfo, PBGetFCBInfo; TYPE ParamBlkType = (ioParam, fileParam, volumeParam, cntrlParam); ParmBlkPtr = POINTER TO ParamBlockRec; ParamBlockRec = RECORD qLink:QElemPtr; qType:INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion:ADDRESS; ioResult: OsErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; CASE ParamBlkType OF ioParam: ioRefNum:INTEGER; ioVersPerm: ARRAY [0..1] OF CHAR; (* ioVersPerm[0] = ioVersNum ioVersPerm[1] = ioPermssn *) ioMisc:Ptr; ioBuffer:Ptr; ioReqCount: LongCard; ioActCount: LongCard; ioPosMode: INTEGER; ioPosOffset: LongCard; | fileParam: ioFRefNum: INTEGER; ioFVersNum: ARRAY [0..1] OF CHAR; (* ioFVersNum[0] = ioFVersNum ioFVersNum[1] = filler1 *) ioFDirIndex: INTEGER; ioFlAttrVers: ARRAY [0..1] OF CHAR; (* ioFlAttrVers[0] = ioFlAttrib ioFlAttrVers[1] = ioFlVersNum *) ioFlFndrInfo: FInfo; ioFlNum: LongCard; ioFlStBlk: INTEGER; ioFlLgLen: LongCard; ioFlPyLen: LongCard; ioFlRStBlk: INTEGER; ioFlRLgLen: LongCard; ioFlRPyLen: LongCard; ioFlCrDat: LongCard; ioFlMdDat: LongCard; | volumeParam: filler2: LongCard; ioVolIndex: INTEGER; ioVCrDate: LongCard; ioVLsBkUp: LongCard; ioVAtrb: INTEGER; ioVNmFls:INTEGER; ioVDirSt:INTEGER; ioVBlLn: INTEGER; ioVNmAlBlks: INTEGER; ioVAlBlkSiz: LongCard; ioVClpSiz: LongCard; ioAlBlSt:INTEGER; ioVNxtFNum: LongCard; ioVFrBlk:INTEGER; | cntrlParam: (* used by Device Manager *) END; END; CMovePBPtr = POINTER TO CMovePBRec; CMovePBRec = RECORD qLink:QElemPtr; qType:INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion:ADDRESS; ioResult: OsErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; filler1: LongCard; ioNewName: StringPtr; filler2: LongCard; ioNewDirID:LongCard; filler3: ARRAY [1..2] OF LongCard; ioDirID: LongCard; END; HParmBlkPtr = POINTER TO HParamBlockRec; HParamBlockRec = RECORD qLink:QElemPtr; qType:INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion:ADDRESS; ioResult: OsErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; CASE ParamBlkType OF ioParam: ioRefNum:INTEGER; ioVersPerm: ARRAY [0..1] OF CHAR; (* ioVersPerm[0] = ioVersNum ioVersPerm[1] = ioPermssn *) ioMisc:Ptr; ioBuffer:Ptr; ioReqCount: LongCard; ioActCount: LongCard; ioPosMode: INTEGER; ioPosOffset: LongCard; | fileParam: ioFRefNum: INTEGER; ioFVersNum: ARRAY [0..1] OF CHAR; (* ioFVersNum[0] = ioFVersNum ioFVersNum[1] = filler1 *) ioFDirIndex: INTEGER; ioFlAttrVers: ARRAY [0..1] OF CHAR; (* ioFlAttrVers[0] = ioFlAttrib ioFlAttrVers[1] = ioFlVersNum *) ioFlFndrInfo: FInfo; ioDirID: LongCard; ioFlStBlk: INTEGER; ioFlLgLen: LongCard; ioFlPyLen: LongCard; ioFlRStBlk: INTEGER; ioFlRLgLen: LongCard; ioFlRPyLen: LongCard; ioFlCrDat: LongCard; ioFlMdDat: LongCard; | volumeParam: filler2: LongCard; ioVolIndex: INTEGER; ioVCrDate: LongCard; ioVLsMod:LongCard; ioVAtrb: INTEGER; ioVNmFls:INTEGER; ioVBitMap: INTEGER; ioAllocPtr: INTEGER; ioVNmAlBlks: INTEGER; ioVAlBlkSiz: LongCard; ioVClpSiz: LongCard; ioAlBlSt:INTEGER; ioVNxtCNID: LongCard; ioVFrBlk:INTEGER; ioVSigWord: INTEGER; ioVDrvInfo: INTEGER; ioVDRefNum: INTEGER; ioVFSID: INTEGER; ioVBkUp: LongCard; ioVSeqNum: INTEGER; ioVWrCnt:LongCard; ioVFilCnt: LongCard; ioVDirCnt: LongCard; ioVFndrInfo: ARRAY [1..8] OF LongCard; END; END; WDPBPtr = POINTER TO WDPBRec; WDPBRec = RECORD qLink:QElemPtr; qType:INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion:ADDRESS; ioResult: OsErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; filler1: INTEGER; ioWDIndex: INTEGER; ioWDProcID:LongCard; ioWDVRefNum: INTEGER; filler2: ARRAY [1..7] OF INTEGER; ioWDDirID: LongCard; END; CInfoType = (hFileInfo, dirInfo); CInfoPBPtr = POINTER TO CInfoPBRec; CInfoPBRec = RECORD qLink:QElemPtr; qType:INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion:ADDRESS; ioResult: OsErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; ioFRefNum: INTEGER; filler1: INTEGER; ioFDirIndex: INTEGER; ioFlAttrib:ARRAY [0..1] OF CHAR; (* ioFlAttrib[0] = ioFlAttrib ioFlAttrib[1] = filler2 *) CASE CInfoType OF hFileInfo: ioFlFndrInfo: FInfo; ioFlNum: LongCard; ioFlStBlk: INTEGER; ioFlLgLen: LongCard; ioFlPyLen: LongCard; ioFlRStBlk: INTEGER; ioFlRLgLen: LongCard; ioFlRPyLen: LongCard; ioFlCrDat: LongCard; ioFlMdDat: LongCard; ioFlBkDat: LongCard; ioFlXFndrInfo:FInfo; ioFlParID: LongCard; ioFlClpSiz: LongCard; | dirInfo: ioDrUsrWds: ARRAY [1..8] OF INTEGER; ioDrDirID: LongCard; ioDrNmFls: INTEGER; filler3: ARRAY [1..9] OF INTEGER; ioDrCrDat: LongCard; ioDrMdDat: LongCard; ioDrBkDat: LongCard; ioDrFndrInfo: ARRAY [1..8] OF INTEGER; ioDrParID: LongCard; END; END; FCBPBPtr = POINTER TO FCBPBRec; FCBPBRec = RECORD qLink:QElemPtr; qType:INTEGER; ioTrap: INTEGER; ioCmdAddr: Ptr; ioCompletion:ADDRESS; ioResult: OsErr; ioNamePtr: StringPtr; ioVRefNum: INTEGER; ioRefNum: INTEGER; filler1: INTEGER; ioFCBIndx: LongCard; ioFCBFlNm: LongCard; ioFCBFlags:INTEGER; ioFCBStBlk:INTEGER; ioFCBEOF: LongCard; ioFCBPLen: LongCard; ioFCBCrPs: LongCard; ioFCBVRefNum:INTEGER; ioFCBClpSiz: LongCard; ioFCBParID:LongCard; END; PROCEDURE PBMountVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetVInfo (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHGetVInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHSetVInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHGetVol (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBSetVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHSetVol (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; PROCEDURE PBFlushVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBUnmountVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBOffLine (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBEject (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBOpen (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHOpen (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBOpenRF (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHOpenRF (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBLockRange (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBUnlockRange (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBRead (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBWrite (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetFPos (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBSetFPos (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetEOF (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBSetEOF (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBAllocate (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBAllocContig (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBFlushFile (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBClose (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBCreate (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHCreate (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBDirCreate (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBDelete (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHDelete (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetFInfo (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHGetFInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBSetFInfo (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHSetFInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBSetFLock (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHSetFLock (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBRstFLock (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHRstFLock (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBSetFVers (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBRename (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBHRename (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetCatInfo (pBlk: CInfoPBPtr; async: BOOLEAN) : OsErr; PROCEDURE PBSetCatInfo (pBlk: CInfoPBPtr; async: BOOLEAN) : OsErr; PROCEDURE PBCatMove (pBlk: CInfoPBPtr; async: BOOLEAN) : OsErr; PROCEDURE PBOpenWD (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; PROCEDURE PBCloseWD (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetWDInfo (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; PROCEDURE PBGetFCBInfo (pBlk: FCBPBPtr; async: BOOLEAN) : OsErr; END PBFileManager. ----------- PBFileManager.MOD ----------- (* Tom Taylor 3707 Poinciana Dr. #137 Santa Clara, CA 95051 *) IMPLEMENTATION MODULE PBFileManager; (* This module implements the low level file system described in the latest File Manager documentation. The procedures implemented in this module support both MFS and HFS calls. However, attempting to call an HFS-only routine on a system without HFS will bomb. *) FROM ASMInterface IMPORT ASM_MCode, InstallAssembly; FROM Terminal IMPORT WriteString; FROM MacSystemTypes IMPORT OsErr; FROM SYSTEM IMPORT ADDRESS; VAR modnum : INTEGER; (* Module number of assembly routine *) PROCEDURE PBMountVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A00Fh, 0); END PBMountVol; PROCEDURE PBGetVInfo (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A007h, 0); END PBGetVInfo; PROCEDURE PBHGetVInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A207h, 0); END PBHGetVInfo; PROCEDURE PBHSetVInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 11); END PBHSetVInfo; PROCEDURE PBGetVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A014h, 0); END PBGetVol; PROCEDURE PBHGetVol (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A214h, 0); END PBHGetVol; PROCEDURE PBSetVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A015h, 0); END PBSetVol; PROCEDURE PBHSetVol (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A215h, 0); END PBHSetVol; PROCEDURE PBFlushVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A013h, 0); END PBFlushVol; PROCEDURE PBUnmountVol (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A00Eh, 0); END PBUnmountVol; PROCEDURE PBOffLine (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A035h, 0); END PBOffLine; PROCEDURE PBEject (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A017h, 0); END PBEject; PROCEDURE PBOpen (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A000h, 0); END PBOpen; PROCEDURE PBHOpen (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A20Fh, 0); END PBHOpen; PROCEDURE PBOpenRF (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A00Ah, 0); END PBOpenRF; PROCEDURE PBHOpenRF (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A20Ah, 0); END PBHOpenRF; PROCEDURE PBLockRange (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 16); END PBLockRange; PROCEDURE PBUnlockRange (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 17); END PBUnlockRange; PROCEDURE PBRead (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A002h, 0); END PBRead; PROCEDURE PBWrite (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A003h, 0); END PBWrite; PROCEDURE PBGetFPos (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A018h, 0); END PBGetFPos; PROCEDURE PBSetFPos (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A044h, 0); END PBSetFPos; PROCEDURE PBGetEOF (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A011h, 0); END PBGetEOF; PROCEDURE PBSetEOF (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A012h, 0); END PBSetEOF; PROCEDURE PBAllocate (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A010h, 0); END PBAllocate; PROCEDURE PBAllocContig (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A210h, 0); END PBAllocContig; PROCEDURE PBFlushFile (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A045h, 0); END PBFlushFile; PROCEDURE PBClose (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A001h, 0); END PBClose; PROCEDURE PBCreate (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A008h, 0); END PBCreate; PROCEDURE PBHCreate (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A208h, 0); END PBHCreate; PROCEDURE PBDirCreate (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 6); END PBDirCreate; PROCEDURE PBDelete (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A009h, 0); END PBDelete; PROCEDURE PBHDelete (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A209h, 0); END PBHDelete; PROCEDURE PBGetFInfo (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A00Ch, 0); END PBGetFInfo; PROCEDURE PBHGetFInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A20Ch, 0); END PBHGetFInfo; PROCEDURE PBSetFInfo (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A00Dh, 0); END PBSetFInfo; PROCEDURE PBHSetFInfo (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A20Dh, 0); END PBHSetFInfo; PROCEDURE PBSetFLock (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A041h, 0); END PBSetFLock; PROCEDURE PBHSetFLock (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A241h, 0); END PBHSetFLock; PROCEDURE PBRstFLock (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A042h, 0); END PBRstFLock; PROCEDURE PBHRstFLock (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A242h, 0); END PBHRstFLock; PROCEDURE PBSetFVers (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A043h, 0); END PBSetFVers; PROCEDURE PBRename (pBlk: ParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A00Bh, 0); END PBRename; PROCEDURE PBHRename (pBlk: HParmBlkPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A20Bh, 0); END PBHRename; PROCEDURE PBGetCatInfo (pBlk: CInfoPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 9); END PBGetCatInfo; PROCEDURE PBSetCatInfo (pBlk: CInfoPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 10); END PBSetCatInfo; PROCEDURE PBCatMove (pBlk: CInfoPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 5); END PBCatMove; PROCEDURE PBOpenWD (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 1); END PBOpenWD; PROCEDURE PBCloseWD (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 2); END PBCloseWD; PROCEDURE PBGetWDInfo (pBlk: WDPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 7); END PBGetWDInfo; PROCEDURE PBGetFCBInfo (pBlk: FCBPBPtr; async: BOOLEAN) : OsErr; BEGIN RETURN LowLevelPB (pBlk, async, 0A260h, 8); END PBGetFCBInfo; PROCEDURE LowLevelPB (pBlk: ADDRESS; async: BOOLEAN; trap: CARDINAL; selector: INTEGER) : OsErr; (* This procedure is responsible for calling the assembly language routine that actually calls the PB trap. *) PROCEDURE LowLevelPB (pBlk: ADDRESS; async: BOOLEAN; trap: CARDINAL; selector: INTEGER; modnum: INTEGER) : OsErr; CODE ASM_MCode; 0; END LowLevelPB; BEGIN RETURN LowLevelPB (pBlk, async, trap, selector, modnum); END LowLevelPB; BEGIN (* Look for a MASM resource with ID of 1986 in current open resource files. It better be in our .LOD file, put there by M2 Linker *) modnum := InstallAssembly("",1986); IF modnum < 1 THEN WriteString("Cannot load PB asm code"); HALT END; END PBFileManager. ----------- PBFileManagerASM.ASM---------- ; Tom Taylor ; 3707 Poinciana Dr. #137 ; Santa Clara, CA 95051 ; ; The one procedure in this ; file is used to implement ; all of the PB calls. The ; higher level Modula-2 program ; (PBFileManager.MOD) ; passes in the actual value ; of the PB trap and the ; procedure here modifies itself ; to execute that trap. DC.W LowLevelPB ; Offset to routine asyncTrpBit EQU $400 ; PROCEDURE LowLevelPB (pBlk: ParmBlkPtr; ; async: BOOLEAN; ; trap: CARDINAL; ; selector: INTEGER) : OsErr; LowLevelPB: MOVE.W (A4)+,D0 ; get trap selector ; (HFS only) MOVE.W (A4)+,D1 ; get trap value TST.W (A4)+ ; check for async call BEQ.S NotAsync ; nope ORI.W #asyncTrpBit,D1 ; yep, make trap async NotAsync: LEA Trapper,A0 ; get address of trap ; location MOVE.W D1,(A0) ; install trap MOVE.L (A4)+,A0 ; get param block address Trapper: DC.W 0 ; PB Trap goes here MOVE.W D0,-(A4) ; return result RTS ----------- PBFileManagerASM.LINK---------- PBFileManagerASM /Output MacModula-2:PBFileManager.made /Type '????' '????' $ ----------- PBFileManager.r--------- * Tom Taylor * 3707 Poinciana Dr. #137 * Santa Clara, CA 95051 * After running this file through * RMaker, rename PBFileManager.REL.RSRC * to PBFileManager.REL before compiling * PBFileManager.MOD MacModula-2:PBFileManager.REL.RSRC LODRM2MC Type MASM = PROC ,1986 MacModula-2:PBFileManager.made ----------- MakePath.MOD--------- (* Tom Taylor 3707 Poinciana Dr. #137 Santa Clara, CA 95051 *) MODULE MakePath; (* This program demonstrates a use of the PBFileManager module. The program puts up the SFGetFile dialog and allows the user to select a file. The program will then print out the full path name to the file. Click the mouse to continue and click the SFGetFile's cancel button to quit. *) FROM PBFileManager IMPORT PBGetCatInfo, CInfoPBRec, HParamBlockRec, PBHGetVInfo; FROM PackageManager IMPORT SFGetFile, SFReply, SFTypeList; FROM SYSTEM IMPORT ADR; FROM MacSystemTypes IMPORT Str255, LongCard; FROM Strings IMPORT StrMacCat, StrModToMac; FROM WindowManager IMPORT WindowPtr, GetNewWindow, DisposeWindow; FROM QuickDraw1 IMPORT MoveTo, DrawString, SetPort, Point, TextFont; FROM DialogManager IMPORT StopAlert; FROM EventManager IMPORT StillDown, Button; CONST MFSInstalled = -1; (* Location in low memory tells whether HFS system installed *) HFSvolume = 04244h; (* Value specifying a HFS volume *) TYPE Str255Ptr = POINTER TO Str255; VAR reply : SFReply; typelist : SFTypeList; HFS [03f6h] : INTEGER; wind : WindowPtr; behind : LongCard; path : Str255; where : Point; hfsFlag : BOOLEAN; PROCEDURE WriteString (s : ARRAY OF CHAR); (* This routine simply writes a Modula-2 style string. *) VAR macs : Str255; BEGIN StrModToMac (macs,s); DrawString (macs); END WriteString; PROCEDURE MakePath (name : Str255Ptr; vRefNum : INTEGER; VAR path : Str255; VAR hfsFlag : BOOLEAN); (* This procedure, the focus of this program, takes a vRefNum (which might be a WDRefNum) and figures out the full path to the directory. It does this by finding the parent each directory until the parent is the root. This procedure works on both MFS and HFS Macs. *) VAR blk : CInfoPBRec; volBlk : HParamBlockRec; getname, volname : Str255; len : CARDINAL; PROCEDURE CheckError (err : INTEGER); BEGIN IF err # 0 THEN err := StopAlert (1986, NIL); HALT END; END CheckError; BEGIN path := name^; (* Start the path with the destination file *) volname := ""; (* Clear out the volume name *) (* Get the volume info for the desired volume. This calls works on both HFS and MFS systems. *) WITH volBlk DO ioCompletion := NIL; ioNamePtr := ADR(volname); ioVRefNum := vRefNum; ioVolIndex := 0; ioVSigWord := 0; CheckError (PBHGetVInfo (ADR(volBlk), FALSE)); END; (* This next line determines whether the HFS system is installed and whether the current volume is an HFS volume. *) hfsFlag := (HFS # MFSInstalled) AND (volBlk.ioVSigWord = HFSvolume); IF hfsFlag THEN (* Only attempt to build a path name deeper than just a volume and file on HFS volumes *) WITH blk DO ioCompletion := NIL; getname := ""; ioNamePtr := ADR(getname); ioVRefNum := vRefNum; (* Probably a WDRefNum *) ioFDirIndex := -1; (* directory info only *) ioDrDirID.r := 0.0; (* kludge for LongCard zero *) CheckError (PBGetCatInfo (ADR(blk), FALSE)); WHILE (ioDrDirID.h # 0) OR (ioDrDirID.l # 2) DO (* Keep looping until the directory ID is the root directory (dir ID = 2) *) (* Insert a colon in the path *) len := CARDINAL(getname[0]); IF len < 255 THEN INC(len); getname[len] := ':'; getname[0] := CHAR(len); END; (* Append the path made so far with the piece we just got. *) StrMacCat(getname,path); (* Save the partial path in path. *) path := getname; getname := ""; ioFDirIndex := -1; (* directory info only *) ioDrDirID := ioDrParID; (* Get info about the parent directory. *) CheckError (PBGetCatInfo (ADR(blk), FALSE)); END; END; END; (* Lastly, append the path to the volume name *) len := CARDINAL(volname[0]); INC(len); volname[len] := ':'; volname[0] := CHAR(len); StrMacCat(volname, path); path := volname; END MakePath; BEGIN behind.h := 65535; (* kludge for LongCard -1 *) behind.l := behind.h; where.h := 100; (* location of SFGetFile *) where.v := 100; LOOP SFGetFile (where, "", NIL, -1, typelist, NIL, reply); WITH reply DO IF NOT good THEN EXIT END; (* Exit if user hit cancel *) (* Figure out path to the file *) MakePath (ADR(fName), vRefNum, path, hfsFlag); TextFont (0); (* so window title comes up right *) wind := GetNewWindow (1986, NIL, WindowPtr(behind)); SetPort (wind); MoveTo (5,17); WriteString ("The path name on this "); IF hfsFlag THEN WriteString ("HFS"); ELSE WriteString ("MFS"); END; WriteString (" volume is:"); MoveTo (5, 37); DrawString (path); WHILE StillDown () DO END; WHILE NOT Button () DO END; (* Really need to use GetNextEvent so this button press is eaten *) DisposeWindow (wind); END; END; END MakePath. ----------- MakcPath.r---------- * Tom Taylor * 3707 Poinciana Dr. #137 * Santa Clara, CA 95051 * After running this file through * RMaker, rename MakePath.REL.RSRC * to MakePath.REL before compiling * MakePath.MOD MacModula-2:MakePath.REL.RSRC LODRM2MC type ALRT ,1986 50 50 250 250 1986 7fff type DITL ,1986 2 button 100 10 130 80 OK? staticText 30 80 190 190 A file manager error occured! type WIND ,1986 Path Name 50 3 100 509 Visible NoGoAway 4 0
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine