Added explanation documents.
@ -47,6 +47,7 @@ bool process_command() {
|
||||
printf("\n");
|
||||
|
||||
char *arg_str = strchr(cmd, ' ');
|
||||
while(*arg_str == ' ') arg_str++;
|
||||
if(arg_str) arg_val = atoi(arg_str);
|
||||
|
||||
switch( tolower(cmd[0]) ) {
|
||||
@ -60,6 +61,7 @@ bool process_command() {
|
||||
case 'u': mac_unmount(arg_val); break;
|
||||
case 't': run_tip(arg_val); break;
|
||||
case 'q': return false;
|
||||
case 'o': SetRichEditText(arg_str); break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
BIN
mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin
Normal file
BIN
mac-cpp-source/tip-doc.sit.bin
Normal file
@ -85,10 +85,13 @@ void WndProc(long iMessage, long wParam) {
|
||||
case DISK_Z_TRACK_FAILURE:
|
||||
case DISK_TEST_FAILURE:
|
||||
case DISK_PROTECTED:
|
||||
//EjectIomegaCartridge();
|
||||
EjectIomegaCartridge();
|
||||
break;
|
||||
case DISK_LOW_SPARES:
|
||||
SetRichEditText(szNotRunning);
|
||||
SetWindowText(hTestButton, szPressToStart);
|
||||
PrepareToBeginTesting();
|
||||
InvalidateRect(hTestMonitor);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -37,6 +37,11 @@ extern long SingleTransferLBA;
|
||||
|
||||
// ----------------------- Macintosh Compatibility -----------------------
|
||||
|
||||
enum AlertTypes {
|
||||
ERR_DLG,
|
||||
YN_DLG
|
||||
};
|
||||
|
||||
enum {
|
||||
BACK_COLOR = -1,
|
||||
BLACK_COLOR = 0x000000,
|
||||
@ -57,6 +62,8 @@ void SetColor(long color);
|
||||
void SetColor(long color, long monoColor);
|
||||
void DrawLed(int x, int y, long color);
|
||||
void StrToPascal(Str255 pStr, const char *str);
|
||||
int ShowAlert(AlertTypes type, const char* format, ...);
|
||||
void SetRichEditText(const char *name);
|
||||
long GetTextExtent(const char *str, unsigned long len);
|
||||
void TextOut(int x, int y, Str255 str);
|
||||
void TextOut(int x, int y, const char *str);
|
||||
@ -137,6 +144,25 @@ extern const char *szPressToSpin;
|
||||
extern const char *szPressToEject;
|
||||
extern const char *szPressToProceed;
|
||||
|
||||
/************* Filenames *************/
|
||||
|
||||
extern const char *szInstructions;
|
||||
extern const char *szNoASPI;
|
||||
extern const char *szASPITrouble;
|
||||
extern const char *szPPAVersion;
|
||||
extern const char *szDefectList;
|
||||
extern const char *szLocked;
|
||||
extern const char *szNoSpares;
|
||||
extern const char *szOutOfSpares;
|
||||
extern const char *szFewSpares;
|
||||
extern const char *szNotRunning;
|
||||
extern const char *szRunning;
|
||||
extern const char *szInterrupted;
|
||||
extern const char *szPerfectResult;
|
||||
extern const char *szExplainResult;
|
||||
extern const char *szBadResult;
|
||||
extern const char *szIomegaQuote;
|
||||
|
||||
/************* Cartridge Status Text *************/
|
||||
|
||||
typedef struct {long code; char *str;} ErrorTypeList;
|
||||
@ -227,7 +253,8 @@ long GetSpareSectorCounts(char);
|
||||
void HandleDriveChanging();
|
||||
void SetCartridgeStatusToEAX(long eax);
|
||||
long PerformRegionTransfer(short XferCmd, void *pBuffer);
|
||||
long TestTheDisk();
|
||||
void TestTheDisk();
|
||||
long GetElapsedTimeInSeconds();
|
||||
void PrepareToBeginTesting();
|
||||
void BumpErrorCounts(long ErrorCode);
|
||||
void EjectIomegaCartridge();
|
||||
|
@ -92,15 +92,6 @@ struct DEFECT_LIST_HEADER {
|
||||
|
||||
#define CHECK_CONDITION 0x02
|
||||
|
||||
enum {
|
||||
szBadResult,
|
||||
szInterrupted,
|
||||
szExplainResult,
|
||||
szPerfectResult,
|
||||
szNoSpares,
|
||||
szOutOfSpares
|
||||
};
|
||||
|
||||
long CurrentDevice = 0;
|
||||
long DriveCount = 0;
|
||||
|
||||
@ -454,11 +445,12 @@ long GetSpareSectorCounts(char checkPassword) {
|
||||
if(!Side_0_SparesCount && !Side_1_SparesCount) {
|
||||
NoSpares:
|
||||
CartridgeStatus = DISK_TEST_FAILURE;
|
||||
eax = szNoSpares;
|
||||
const char *eax = szNoSpares;
|
||||
// if were running give them a different error message
|
||||
if(TestingPhase) {
|
||||
eax = szOutOfSpares;
|
||||
}
|
||||
SetRichEditText(eax);
|
||||
goto ErrorExit;
|
||||
}
|
||||
|
||||
@ -470,6 +462,7 @@ long GetSpareSectorCounts(char checkPassword) {
|
||||
// show the richedit control for the trouble
|
||||
if (eax == DEFECT_LIST_READ_ERROR) {
|
||||
CartridgeStatus = DISK_Z_TRACK_FAILURE;
|
||||
SetRichEditText(szDefectList);
|
||||
ErrorExit:
|
||||
return -1;
|
||||
}
|
||||
@ -533,6 +526,7 @@ void SetCartridgeStatusToEAX(long eax) {
|
||||
esi = szPressToStop;
|
||||
break;
|
||||
case DISK_NOT_PRESENT:
|
||||
SetRichEditText(szNotRunning);
|
||||
goto DisableActions;
|
||||
case DISK_AT_SPEED:
|
||||
eax = GetSpareSectorCounts(true); // update the Cart Condition
|
||||
@ -556,6 +550,7 @@ void SetCartridgeStatusToEAX(long eax) {
|
||||
}
|
||||
if(Side_1_SparesCount < MINIMUM_ZIP_SPARES) {
|
||||
InsufficientSpares:
|
||||
SetRichEditText(szFewSpares);
|
||||
CartridgeStatus = DISK_LOW_SPARES;
|
||||
esi = szPressToProceed;
|
||||
goto EnableTestBtn;
|
||||
@ -656,6 +651,23 @@ void BumpErrorCounts(long ErrorCode) {
|
||||
HardErrors++;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* EJECT IOMEGA CARTRIDGE
|
||||
*******************************************************************************/
|
||||
void EjectIomegaCartridge() {
|
||||
// Could NOT do it through the IOCTL layer ... so eject with SCSI
|
||||
// make sure the media is not locked...
|
||||
char Scsi[6] = {0};
|
||||
Scsi[0] = SCSI_Cmd_PreventAllow;
|
||||
SCSICommand(CurrentDevice, Scsi, 0, 0);
|
||||
// issue an Asynchronous STOP command to induce spindown and ejection
|
||||
memset(Scsi, 0, sizeof(Scsi));
|
||||
Scsi[0] = SCSI_Cmd_StartStopUnit;
|
||||
Scsi[1] = 1; // Set the IMMED bit for offline
|
||||
Scsi[4] = 2; // eject a Jaz disk after stopping
|
||||
SCSICommand(CurrentDevice, Scsi, 0, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* PERFORM REGION TRANSFER
|
||||
*******************************************************************************/
|
||||
@ -775,18 +787,19 @@ Exit:
|
||||
* TEST THE DISK
|
||||
*******************************************************************************/
|
||||
|
||||
long TestTheDisk() {
|
||||
void TestTheDisk() {
|
||||
void *pPatternBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
|
||||
void *pUserDataBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
|
||||
|
||||
if(pPatternBuffer == NULL || pUserDataBuffer == NULL) {
|
||||
printf("Allocation error\n");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
StopApplicationTimer();
|
||||
|
||||
PreventProgramExit();
|
||||
SetRichEditText(szRunning);
|
||||
CartridgeStatus = DISK_TEST_UNDERWAY;
|
||||
TestingPhase = TESTING_STARTUP; // inhibit stopping now
|
||||
SetWindowText(hTestButton, szPressToStop);
|
||||
@ -869,7 +882,8 @@ GetOut:
|
||||
AllowProgramExit();
|
||||
|
||||
// compute the number of serious troubles
|
||||
long eax, errors = FirmErrors + HardErrors;
|
||||
const char *eax;
|
||||
long errors = FirmErrors + HardErrors;
|
||||
if (errors >= BADNESS_THRESHOLD) {
|
||||
eax = szBadResult;
|
||||
}
|
||||
@ -885,8 +899,8 @@ GetOut:
|
||||
eax = szPerfectResult;
|
||||
}
|
||||
}
|
||||
|
||||
SetRichEditText(eax);
|
||||
InvalidateRect(hTestMonitor);
|
||||
Exit:
|
||||
StartApplicationTimer();
|
||||
return eax;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <SIOUX.h>
|
||||
@ -7,6 +8,8 @@
|
||||
#include <Windows.h>
|
||||
#include <Quickdraw.h>
|
||||
|
||||
#include "pstring.h"
|
||||
#include "LaunchLib.h"
|
||||
#include "mac_vol.h"
|
||||
#include "tip.h"
|
||||
|
||||
@ -30,7 +33,10 @@ void run_tip(int id) {
|
||||
WinMain(id);
|
||||
RgnHandle cursorRgn = NewRgn();
|
||||
|
||||
SetRichEditText(szInstructions);
|
||||
NewTipWindow();
|
||||
EnableWindow(hTestButton, false);
|
||||
|
||||
gDone = false;
|
||||
do {
|
||||
EventRecord event;
|
||||
@ -195,17 +201,15 @@ void DoDiskEvent(EventRecord &event) {
|
||||
mac_get_drive_volumes(driveNum, volumes);
|
||||
|
||||
// Ask the user whether they want to unmount the disk
|
||||
ParamText(volumes, "\p", "\p", "\p");
|
||||
if (CautionAlert(128, NULL) == 1) {
|
||||
// The user wishes to unmount the disk
|
||||
OSErr err = mac_unmount_drive(driveNum);
|
||||
if(err != noErr) {
|
||||
if(err == fBsyErr) {
|
||||
ParamText("\pFailed to unmount. One or more files are open.", "\p", "\p", "\p");
|
||||
ShowAlert(ERR_DLG, "Failed to unmount. One or more files are open.");
|
||||
} else {
|
||||
ParamText("\pFailed to unmount.", "\p", "\p", "\p");
|
||||
ShowAlert(ERR_DLG, "Failed to unmount. Error Code: %d", err);
|
||||
}
|
||||
StopAlert(129, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,6 +221,69 @@ void StrToPascal(Str255 pStr, const char *str) {
|
||||
strncpy((char*)pStr + 1, str, 255);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SHOW ALERT BOX
|
||||
*******************************************************************************/
|
||||
|
||||
int ShowAlert(AlertTypes type, const char* format, ...) {
|
||||
Str255 pStr;
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsprintf((char*)pStr + 1, format, argptr);
|
||||
va_end(argptr);
|
||||
pStr[0] = strlen((char*)pStr + 1);
|
||||
ParamText(pStr, "\p", "\p", "\p");
|
||||
switch(type) {
|
||||
case ERR_DLG: return StopAlert(129, NULL);
|
||||
case YN_DLG: return NoteAlert(130, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SET RICH EDIT TEXT
|
||||
*
|
||||
* This routine will open one of the TIP explanation files using SimpleText
|
||||
*
|
||||
* This uses code from Thomas Tempelmann's C libraries
|
||||
*
|
||||
* http://www.tempel.org/macdev/index.html
|
||||
*******************************************************************************/
|
||||
|
||||
void SetRichEditText(const char *name) {
|
||||
static const char *lastName = 0;
|
||||
if(name == lastName) return;
|
||||
|
||||
if(ShowAlert(YN_DLG, "Would you like to read the document \"%s\" now?", name) == 2) {
|
||||
return;
|
||||
}
|
||||
Str255 docName;
|
||||
StrToPascal(docName, name);
|
||||
|
||||
Str255 pathName;
|
||||
pstrcpy(pathName, "\p:tip-doc:");
|
||||
pstrcat(pathName, docName);
|
||||
|
||||
FSSpec docSpec;
|
||||
FSSpec appSpec;
|
||||
OSErr err = FSMakeFSSpec(0, 0, pathName, &docSpec);
|
||||
if(err) {
|
||||
ShowAlert(ERR_DLG, "Can't find the \"%s\" file. Make sure it is inside the \"tip-doc\" folder.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
err = FindApplicationFromDocument(&docSpec, &appSpec);
|
||||
if(err) {
|
||||
ShowAlert(ERR_DLG, "Can't find an application to open \"%s\". Is \"SimpleText\" installed?", name);
|
||||
return;
|
||||
}
|
||||
err = LaunchApplicationWithDocument(&appSpec, &docSpec, false);
|
||||
if(err) {
|
||||
ShowAlert(ERR_DLG, "Can't open \"%s\". If \"%#s\" is already running, please close it.", name, appSpec.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SET COLOR
|
||||
*******************************************************************************/
|
||||
|
@ -26,6 +26,25 @@ const char *szPressToSpin = "Press to Spin Up";
|
||||
const char *szPressToEject = "Press to Eject";
|
||||
const char *szPressToProceed = "Press to Proceed";
|
||||
|
||||
// Filenames
|
||||
|
||||
const char *szInstructions = "Instructions";
|
||||
const char *szNoASPI = "No ASPI";
|
||||
const char *szASPITrouble = "No Drives";
|
||||
const char *szPPAVersion = "Parallel Port";
|
||||
const char *szDefectList = "Z-Track Failure";
|
||||
const char *szLocked = "Cartridge Locked";
|
||||
const char *szNoSpares = "No Spares";
|
||||
const char *szOutOfSpares = "Out of Spares";
|
||||
const char *szFewSpares = "Few Spares";
|
||||
const char *szNotRunning = "Not Running";
|
||||
const char *szRunning = "Test Running";
|
||||
const char *szInterrupted = "Test Interrupted";
|
||||
const char *szPerfectResult = "Perfect Result";
|
||||
const char *szExplainResult = "Good Result";
|
||||
const char *szBadResult = "Bad Result";
|
||||
const char *szIomegaQuote = "Iomega Quote";
|
||||
|
||||
/************* Cartridge Status Text *************/
|
||||
|
||||
const char *szUnknownStat = "Ejecting Cartridge";
|
||||
|
BIN
mac-cpp-source/utils/.finf/FileLib.c
Normal file
BIN
mac-cpp-source/utils/.finf/FileLib.h
Normal file
BIN
mac-cpp-source/utils/.finf/LaunchLib.c
Normal file
BIN
mac-cpp-source/utils/.finf/LaunchLib.h
Normal file
BIN
mac-cpp-source/utils/.finf/PascalLib.c
Normal file
BIN
mac-cpp-source/utils/.finf/PascalLib.h
Normal file
BIN
mac-cpp-source/utils/.finf/TrapAvail.c
Normal file
BIN
mac-cpp-source/utils/.finf/TrapAvail.h
Normal file
BIN
mac-cpp-source/utils/.finf/pstring.h
Normal file
BIN
mac-cpp-source/utils/.rsrc/FileLib.c
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/FileLib.h
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/LaunchLib.c
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/LaunchLib.h
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/PascalLib.c
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/PascalLib.h
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/TrapAvail.c
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/TrapAvail.h
Normal file
After Width: | Height: | Size: 410 B |
BIN
mac-cpp-source/utils/.rsrc/pstring.h
Normal file
After Width: | Height: | Size: 410 B |
184
mac-cpp-source/utils/FileLib.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* File Utilities (System 7 and above)
|
||||
*
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*/
|
||||
|
||||
|
||||
#include <Types.h>
|
||||
#include <Files.h>
|
||||
#include <Errors.h>
|
||||
#include <Devices.h>
|
||||
#include <Aliases.h>
|
||||
#include <Resources.h>
|
||||
#include <Folders.h>
|
||||
//#include <LowMem.h>
|
||||
|
||||
#define CALL_NOT_IN_CARBON 1 // for Universal Headers 3.3
|
||||
#include <FSM.h>
|
||||
|
||||
#include "FileLib.h"
|
||||
#include "TrapAvail.h"
|
||||
|
||||
#pragma push
|
||||
#pragma cplusplus on
|
||||
|
||||
static Boolean inited = false;
|
||||
static FSSpec ThisPath = {0,1,"\p"}; // 27.3.96: dirID mu§te von 0 auf 1 geŠndert werden, weil sonst u.U. ResolveAlias einen Endlos-Loop machte
|
||||
|
||||
static OSErr getInfo (CInfoPBPtr pb, FSSpec &fs)
|
||||
{
|
||||
pb->hFileInfo.ioVRefNum = fs.vRefNum;
|
||||
pb->hFileInfo.ioNamePtr = fs.name;
|
||||
pb->hFileInfo.ioFDirIndex = 0;
|
||||
pb->hFileInfo.ioDirID = fs.parID;
|
||||
return PBGetCatInfoSync (pb);
|
||||
}
|
||||
|
||||
OSErr FSpResolveAlias (FSSpec &spec)
|
||||
// PrŸft, ob die Datei ein Alias ist und lšst den ggf. auf.
|
||||
// Liefert Fehlercode, z.B., wenn ein Login-Dialog vom User abgebrochen wurde.
|
||||
{
|
||||
Boolean isFolder, wasAlias;
|
||||
return ResolveAliasFile (&spec, true, &isFolder, &wasAlias);
|
||||
}
|
||||
|
||||
|
||||
DrvQElPtr FindDrvQ (short drvNum)
|
||||
{
|
||||
DrvQElPtr qep = (DrvQElPtr)(GetDrvQHdr()->qHead);
|
||||
while (qep) {
|
||||
if (qep->dQDrive == drvNum) return qep;
|
||||
qep = (DrvQElPtr)qep->qLink;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
short FindVolByDriveNum (short drvNum)
|
||||
{
|
||||
HVolumeParam pb;
|
||||
short err, idx;
|
||||
|
||||
idx = 1;
|
||||
do {
|
||||
pb.ioVolIndex = idx;
|
||||
pb.ioNamePtr = NULL;
|
||||
err = PBHGetVInfoSync ((HParamBlockRec*)&pb);
|
||||
if (err) break;
|
||||
if (pb.ioVDrvInfo == drvNum) {
|
||||
return pb.ioVRefNum;
|
||||
}
|
||||
++idx;
|
||||
} while (true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSErr GetSysVolume (short *vRefNum)
|
||||
// returns the boot volume
|
||||
{
|
||||
long dir;
|
||||
OSErr err = FindFolder (kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
|
||||
if (err) *vRefNum = -1;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
OSErr FindInFolderByCreator (short vRefNum, long dirID, OSType creator, OSType fileType, FSSpec *foundSpec)
|
||||
{
|
||||
OSErr err;
|
||||
HFileParam pb;
|
||||
short idx = 1;
|
||||
do {
|
||||
pb.ioVRefNum = vRefNum;
|
||||
pb.ioDirID = dirID;
|
||||
pb.ioFDirIndex = idx++;
|
||||
pb.ioNamePtr = foundSpec->name;
|
||||
pb.ioFVersNum = 0;
|
||||
err = PBHGetFInfoSync ((HParmBlkPtr)&pb);
|
||||
if (!err) {
|
||||
if (pb.ioFlFndrInfo.fdCreator == creator && (fileType == 0 || pb.ioFlFndrInfo.fdType == fileType)) {
|
||||
foundSpec->vRefNum = vRefNum;
|
||||
foundSpec->parID = dirID;
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
} while (!err);
|
||||
return err;
|
||||
}
|
||||
|
||||
OSErr FindOnDiskByCreator (short vRefNum, OSType creator, OSType fileType, FSSpec *foundSpec)
|
||||
{
|
||||
OSErr err;
|
||||
CSParam pb;
|
||||
CInfoPBRec info1;
|
||||
CInfoPBRec info2 = {0};
|
||||
|
||||
pb.ioVRefNum = vRefNum;
|
||||
pb.ioNamePtr = nil;
|
||||
pb.ioMatchPtr = foundSpec;
|
||||
pb.ioReqMatchCount = 1;
|
||||
pb.ioCatPosition.initialize = 0;
|
||||
pb.ioOptBuffer = nil;
|
||||
pb.ioOptBufSize = 0;
|
||||
pb.ioSearchTime = 0;
|
||||
pb.ioSearchBits = fsSBFlAttrib | fsSBFlFndrInfo;
|
||||
pb.ioSearchInfo1 = &info1;
|
||||
pb.ioSearchInfo2 = &info2;
|
||||
if (fileType) {
|
||||
info1.hFileInfo.ioFlFndrInfo.fdType = fileType;
|
||||
info2.hFileInfo.ioFlFndrInfo.fdType = (UInt32) -1; // mask
|
||||
}
|
||||
info1.hFileInfo.ioFlFndrInfo.fdCreator = creator;
|
||||
info2.hFileInfo.ioFlFndrInfo.fdCreator = (UInt32) -1; // mask
|
||||
info1.hFileInfo.ioFlAttrib &= ~ioDirMask; // looking for files, not dirs
|
||||
info2.hFileInfo.ioFlAttrib |= ioDirMask; // set the mask for files/dirs
|
||||
err = PBCatSearchSync (&pb);
|
||||
if (!err && pb.ioActMatchCount > 0) {
|
||||
return noErr;
|
||||
}
|
||||
return fnfErr;
|
||||
}
|
||||
#if 0 // Disable by MLT
|
||||
EXTERN_API(Ptr) GetFCBSPtr(void) TWOWORDINLINE(0x2EB8, 0x034E);
|
||||
|
||||
OSErr FindOpenFileByTypeAndCreator (OSType type, OSType creator, FSSpec *itsSpec)
|
||||
// type = 0 -> don't care
|
||||
{
|
||||
OSErr err;
|
||||
short idx = 1;
|
||||
Boolean hasFSM = TrapAvailable(0xA824);
|
||||
do {
|
||||
FCBPBRec pb;
|
||||
pb.ioFCBIndx = idx++;
|
||||
pb.ioVRefNum = 0; // means: index through all volumes
|
||||
pb.ioNamePtr = itsSpec->name;
|
||||
err = PBGetFCBInfoSync (&pb);
|
||||
if (!err) {
|
||||
FCBRecPtr fcb;
|
||||
if (hasFSM) {
|
||||
UTResolveFCB (pb.ioRefNum, &fcb);
|
||||
} else {
|
||||
fcb = (FCBRecPtr) ((Ptr)GetFCBSPtr() + pb.ioRefNum);
|
||||
}
|
||||
if (type == 0 || type == fcb->fcbFType) {
|
||||
if (creator) {
|
||||
itsSpec->vRefNum = pb.ioVRefNum;
|
||||
itsSpec->parID = pb.ioFCBParID;
|
||||
FInfo fi;
|
||||
err = FSpGetFInfo (itsSpec, &fi);
|
||||
if (!err) {
|
||||
if (creator == fi.fdCreator) {
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma pop
|
||||
|
||||
// EOF
|
27
mac-cpp-source/utils/FileLib.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* File Utilities (System 7 and above)
|
||||
*
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*/
|
||||
|
||||
#include <Devices.h>
|
||||
|
||||
#pragma push
|
||||
#pragma cplusplus on
|
||||
|
||||
Boolean FSpIsAlias (FSSpec &spec);
|
||||
OSErr FSpResolveAlias (FSSpec &spec); // Lšst ggf. Aliase auf
|
||||
|
||||
DrvQElPtr FindDrvQ (short drv);
|
||||
short FindVolByDriveNum (short drvNum);
|
||||
|
||||
OSErr GetSysVolume (short *vRefNum); // gets the boot volume
|
||||
|
||||
OSErr FindInFolderByCreator (short vRefNum, long dirID, OSType creator, OSType fileType, FSSpec *foundSpec);
|
||||
OSErr FindOnDiskByCreator (short vRefNum, OSType creator, OSType fileType, FSSpec *foundSpec);
|
||||
|
||||
OSErr FindOpenFileByTypeAndCreator (OSType type, OSType creator, FSSpec *itsSpec);
|
||||
|
||||
#pragma pop
|
||||
|
||||
// EOF
|
684
mac-cpp-source/utils/LaunchLib.c
Normal file
@ -0,0 +1,684 @@
|
||||
/*
|
||||
* Functions for launching apps with documents
|
||||
*
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*
|
||||
* some of these routines are not from me (TT), but from some DTS sample code.
|
||||
* here's a link to it: <http://developer.apple.com/dev/techsupport/source/code/Snippets/Processes/LaunchWithDoc2.1/LaunchWithDoc2.c.html>
|
||||
*/
|
||||
|
||||
|
||||
//#include <Processes.h>
|
||||
#include <AppleEvents.h>
|
||||
#include <AERegistry.h>
|
||||
#include <AEPackObject.h>
|
||||
#include <AEObjects.h>
|
||||
#include <Aliases.h>
|
||||
#include <Errors.h>
|
||||
#include "PascalLib.h"
|
||||
#include "FileLib.h"
|
||||
#include "LaunchLib.h"
|
||||
|
||||
|
||||
#pragma cplusplus on
|
||||
|
||||
/*
|
||||
Korrekturen:
|
||||
TT 23.2.95: foundFlag wurde nicht auf "false" initialisiert.
|
||||
TT 5.11.96: LaunchAppl() neu, OpenSpecifiedDocument() kann auch APPLs direkt starten
|
||||
TT 30.1.99: FindApplicationFromDocument() stellt nun sicher, da§ die App wirklich existiert (das
|
||||
ist nicht der Fall, wenn das Volume not mounted ist oder wenn die App verschoben
|
||||
oder gelšscht wurde, oder wenn die Datei nicht vom Typ 'APPL' ist).
|
||||
TT 13.2.99: FindApplicationFromDocument() updated to use the proper algorith that the Finder
|
||||
uses. For that, the code has been largely rewritten (reordered)
|
||||
Note: it is not perfectly like the Finder: The Finder orders remote vols by their
|
||||
speed, thru the parm "volumeGrade", while I ignore this information, since most
|
||||
vols are having a grade of 0, anyways.
|
||||
Attention: It does not use the "fopn" Finder interception AE that has been introduced
|
||||
in Mac OS 8!
|
||||
TT 16.2.99: LaunchAppl(): launchNoFileFlags was set in wrong field (in launchFileFlags instead
|
||||
launchControlFlags)
|
||||
TT 23.3.99: added: FindApplicationByCreator(), OpenWithFinder(), FindRunningAppBySignature(),
|
||||
SendFSSEventToProcess().
|
||||
TT 15.4.99: added the file type 'APPD' to the list of launchable apps in checkThisVolume().
|
||||
(APPD is used for apps routed to the Apple Menu Items folder)
|
||||
TT 31.7.99: added "Boolean inBackground" parm to OpenSpecifiedDocument() and LaunchAppl(),
|
||||
and added SetFrontProcess() in OpenSpecifiedDocument() and in LaunchApplicationWithDocument()
|
||||
in order to bring the app to the front when it was already running.
|
||||
TT 24.4.00: added the file type 'appe' to the list of launchable apps in checkThisVolume(),
|
||||
added types 'APPC', 'APPD' and 'appe' to
|
||||
*/
|
||||
|
||||
// OpenSpecifiedDocument searches to see if the application which
|
||||
// created the document is already running. If so, it sends
|
||||
// an OpenSpecifiedDocuments Apple event to the target application
|
||||
// (remember that, because of puppet strings, this works even
|
||||
// if the target application is not Apple event-aware.)
|
||||
|
||||
OSErr OpenSpecifiedDocument(const FSSpec * documentFSSpecPtr, Boolean inBackground)
|
||||
{
|
||||
OSErr retCode;
|
||||
ProcessSerialNumber currPSN;
|
||||
ProcessInfoRec currProcessInfo;
|
||||
FSSpec applicationSpec;
|
||||
FInfo documentFInfo;
|
||||
Boolean foundRunningProcessFlag;
|
||||
|
||||
// verify the document file exists and get its creator type
|
||||
|
||||
retCode = FSpGetFInfo(documentFSSpecPtr, &documentFInfo);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
// check the current processes to see if the creator app is already
|
||||
// running, and get its process serial number (as currPSN)
|
||||
|
||||
currPSN.lowLongOfPSN = kNoProcess;
|
||||
currPSN.highLongOfPSN = 0;
|
||||
|
||||
currProcessInfo.processInfoLength = sizeof(ProcessInfoRec);
|
||||
currProcessInfo.processName = nil;
|
||||
currProcessInfo.processAppSpec = &applicationSpec;
|
||||
|
||||
foundRunningProcessFlag = false;
|
||||
while (GetNextProcess(&currPSN) == noErr) {
|
||||
if (GetProcessInformation(&currPSN, &currProcessInfo) == noErr) {
|
||||
if (currProcessInfo.processSignature == documentFInfo.fdCreator) {
|
||||
foundRunningProcessFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundRunningProcessFlag) {
|
||||
// if the creator is running, send it an OpenDocuments Apple event
|
||||
// since there is no need to launch it
|
||||
|
||||
if (currProcessInfo.processType != documentFInfo.fdType) { // this would be the case if the doc is an app
|
||||
retCode = SendOpenDocumentEventToProcess(&currPSN, documentFSSpecPtr);
|
||||
}
|
||||
if (retCode == noErr) {
|
||||
if (!inBackground) {
|
||||
SetFrontProcess (&currPSN);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (documentFInfo.fdType == 'APPL' || documentFInfo.fdType == 'APPC' || documentFInfo.fdType == 'APPD' || documentFInfo.fdType == 'appe') {
|
||||
// else if the creator is not running and if the document to be opened is a application,
|
||||
// then launch it directly.
|
||||
|
||||
retCode = LaunchAppl (documentFSSpecPtr, inBackground);
|
||||
|
||||
} else {
|
||||
// else if the creator is neither running nor an application, find it on disk and launch
|
||||
// it with the OpenDocuments event included as a part of the launch parameters
|
||||
|
||||
retCode = FindApplicationFromDocument(documentFSSpecPtr, &applicationSpec);
|
||||
|
||||
if (retCode == noErr) {
|
||||
retCode = LaunchApplicationWithDocument(&applicationSpec, documentFSSpecPtr, inBackground);
|
||||
}
|
||||
}
|
||||
|
||||
Bail:
|
||||
return retCode;
|
||||
}
|
||||
|
||||
OSErr LaunchAppl (const FSSpec * applicationFSSpecPtr, Boolean inBackground)
|
||||
{
|
||||
LaunchParamBlockRec launchParams;
|
||||
launchParams.launchAppParameters = nil;
|
||||
launchParams.launchBlockID = extendedBlock;
|
||||
launchParams.launchEPBLength = extendedBlockLen;
|
||||
launchParams.launchFileFlags = 0;
|
||||
launchParams.launchControlFlags = launchContinue | launchNoFileFlags;
|
||||
if (inBackground) launchParams.launchControlFlags |= launchDontSwitch;
|
||||
launchParams.launchAppSpec = (FSSpecPtr)applicationFSSpecPtr;
|
||||
return LaunchApplication (&launchParams);
|
||||
}
|
||||
|
||||
// given an application and a document, LaunchApplicationWithDocument
|
||||
// launches the application and passes the application an
|
||||
// OpenDocuments event for the document
|
||||
// if the app is already running, then it simply gets the open event
|
||||
|
||||
OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr,
|
||||
const FSSpec * documentFSSpecPtr, Boolean inBackground)
|
||||
{
|
||||
OSErr retCode;
|
||||
LaunchParamBlockRec launchParams;
|
||||
ProcessSerialNumber myPSN;
|
||||
AppleEvent theAppleEvent;
|
||||
AEDesc myAddrDesc, launchParamDesc, docDesc;
|
||||
AEDescList docDescList;
|
||||
AliasHandle docAlias;
|
||||
ProcessSerialNumber currPSN;
|
||||
ProcessInfoRec currProcessInfo;
|
||||
FSSpec applicationSpec;
|
||||
Boolean foundRunningProcessFlag;
|
||||
|
||||
// to simplify cleanup, ensure that handles are nil to start
|
||||
theAppleEvent.dataHandle = nil;
|
||||
launchParamDesc.dataHandle = nil;
|
||||
docDescList.dataHandle = nil;
|
||||
docDesc.dataHandle = nil;
|
||||
docAlias = nil;
|
||||
|
||||
// check if the app is already running
|
||||
currPSN.lowLongOfPSN = kNoProcess;
|
||||
currPSN.highLongOfPSN = 0;
|
||||
currProcessInfo.processInfoLength = sizeof(ProcessInfoRec);
|
||||
currProcessInfo.processName = nil;
|
||||
currProcessInfo.processAppSpec = &applicationSpec;
|
||||
foundRunningProcessFlag = false;
|
||||
while (GetNextProcess(&currPSN) == noErr) {
|
||||
if (GetProcessInformation(&currPSN, &currProcessInfo) == noErr) {
|
||||
if (applicationSpec.vRefNum == applicationFSSpecPtr->vRefNum
|
||||
&& applicationSpec.parID == applicationFSSpecPtr->parID
|
||||
&& pstrcmp (applicationSpec.name, (const StringPtr)applicationFSSpecPtr->name) == 0) {
|
||||
foundRunningProcessFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundRunningProcessFlag) {
|
||||
retCode = SendOpenDocumentEventToProcess (&currPSN, documentFSSpecPtr);
|
||||
if (retCode == noErr) {
|
||||
if (!inBackground) {
|
||||
SetFrontProcess (&currPSN);
|
||||
}
|
||||
}
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// the Apple event will need a valid address descriptor (even though its
|
||||
// contents will not matter since we will not be calling AESend) so make
|
||||
// one using my own serial number
|
||||
|
||||
(void) GetCurrentProcess(&myPSN);
|
||||
retCode = AECreateDesc(typeProcessSerialNumber, (Ptr) &myPSN,
|
||||
sizeof(ProcessSerialNumber), &myAddrDesc);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
// make a descriptor list containing just a descriptor with an
|
||||
// alias to the document
|
||||
|
||||
retCode = AECreateList(nil, 0, false, &docDescList);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
retCode = NewAlias(nil, documentFSSpecPtr, &docAlias);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
HLock((Handle) docAlias);
|
||||
retCode = AECreateDesc(typeAlias, (Ptr) *docAlias,
|
||||
GetHandleSize((Handle) docAlias), &docDesc);
|
||||
HUnlock((Handle) docAlias);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
retCode = AEPutDesc(&docDescList, 0, &docDesc);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
// now make the 'odoc' AppleEvent descriptor and insert the
|
||||
// document descriptor list as the direct object
|
||||
|
||||
retCode = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments,
|
||||
&myAddrDesc, kAutoGenerateReturnID, kAnyTransactionID,
|
||||
&theAppleEvent);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDescList);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
// this Apple event will not be sent but rather will be used
|
||||
// as a parameter to the LaunchApplication call, so coerce it
|
||||
// to the magic type typeAppParamters
|
||||
|
||||
retCode = AECoerceDesc(&theAppleEvent, typeAppParameters, &launchParamDesc);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
// finally, fill in the launch parameter block, including the
|
||||
// Apple event, and make the launch call
|
||||
|
||||
HLock((Handle) launchParamDesc.dataHandle);
|
||||
launchParams.launchAppParameters =
|
||||
(AppParametersPtr) *(launchParamDesc.dataHandle);
|
||||
|
||||
launchParams.launchBlockID = extendedBlock;
|
||||
launchParams.launchEPBLength = extendedBlockLen;
|
||||
launchParams.launchFileFlags = launchNoFileFlags;
|
||||
launchParams.launchControlFlags = launchContinue;
|
||||
if (inBackground) launchParams.launchControlFlags |= launchDontSwitch;
|
||||
launchParams.launchAppSpec = (FSSpecPtr) applicationFSSpecPtr;
|
||||
|
||||
retCode = LaunchApplication(&launchParams);
|
||||
|
||||
Bail:
|
||||
// dispose of everything that was allocated
|
||||
|
||||
if (theAppleEvent.dataHandle != nil) (void) AEDisposeDesc(&theAppleEvent);
|
||||
if (launchParamDesc.dataHandle != nil) (void) AEDisposeDesc(&launchParamDesc);
|
||||
if (docDescList.dataHandle != nil) (void) AEDisposeDesc(&docDescList);
|
||||
if (docDesc.dataHandle != nil) (void) AEDisposeDesc(&docDesc);
|
||||
if (launchParamDesc.dataHandle != nil) (void) AEDisposeDesc(&launchParamDesc);
|
||||
if (docAlias != nil)
|
||||
DisposeHandle((Handle) docAlias);
|
||||
|
||||
return retCode;
|
||||
|
||||
}
|
||||
|
||||
|
||||
OSErr SendFSSEventToProcess (ProcessSerialNumber *targetPSN, OSType aeClass, OSType aeCmd, const FSSpec *documentFSSpecPtr)
|
||||
{
|
||||
OSErr retCode;
|
||||
AppleEvent theAppleEvent = {typeNull, nil}, theReplyEvent = {typeNull, nil};
|
||||
AEDesc targetAddrDesc = {typeNull, nil}, docDesc = {typeNull, nil};
|
||||
//AEDescList docDescList;
|
||||
AliasHandle docAlias;
|
||||
|
||||
// to simplify cleanup, ensure that handles are nil to start
|
||||
theAppleEvent.dataHandle = nil;
|
||||
//docDescList.dataHandle = nil;
|
||||
docDesc.dataHandle = nil;
|
||||
docAlias = nil;
|
||||
|
||||
// create an address descriptor based on the serial number of
|
||||
// the target process
|
||||
|
||||
retCode = AECreateDesc(typeProcessSerialNumber, (Ptr) targetPSN,
|
||||
sizeof(ProcessSerialNumber), &targetAddrDesc);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
/* I see no reason to make a list here, it's always just one item anyway
|
||||
// make a descriptor list containing just a descriptor with an
|
||||
// alias to the document
|
||||
retCode = AECreateList(nil, 0, false, &docDescList);
|
||||
if (retCode != noErr) goto Bail;
|
||||
*/
|
||||
|
||||
retCode = NewAlias(nil, documentFSSpecPtr, &docAlias);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
HLock((Handle) docAlias);
|
||||
retCode = AECreateDesc(typeAlias, (Ptr) *docAlias,
|
||||
GetHandleSize((Handle) docAlias), &docDesc);
|
||||
HUnlock((Handle) docAlias);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
/* I see no reason to make a list here, it's always just one item anyway
|
||||
retCode = AEPutDesc(&docDescList, 0, &docDesc);
|
||||
if (retCode != noErr) goto Bail;
|
||||
*/
|
||||
|
||||
// now make the AppleEvent descriptor and insert the
|
||||
// document descriptor list as the direct object
|
||||
|
||||
retCode = AECreateAppleEvent(aeClass, aeCmd,
|
||||
&targetAddrDesc, kAutoGenerateReturnID, kAnyTransactionID,
|
||||
&theAppleEvent);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
// retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDescList);
|
||||
retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDesc);
|
||||
if (retCode != noErr) goto Bail;
|
||||
|
||||
// finally, send the Apple event
|
||||
retCode = AESend (&theAppleEvent, &theReplyEvent, kAENoReply,
|
||||
kAEHighPriority, 2*60 /* timeout: 2 seconds */, nil, nil);
|
||||
|
||||
Bail:
|
||||
// dispose of everything that was allocated
|
||||
|
||||
if (theAppleEvent.dataHandle != nil) (void) AEDisposeDesc(&theAppleEvent);
|
||||
//if (docDescList.dataHandle != nil) (void) AEDisposeDesc(&docDescList);
|
||||
if (docDesc.dataHandle != nil) (void) AEDisposeDesc(&docDesc);
|
||||
if (docAlias != nil) DisposeHandle((Handle) docAlias);
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
||||
|
||||
// given an application's serial number and a document,
|
||||
// SendOpenDocumentEventToProcess passes
|
||||
// the application an OpenDocuments event for the document
|
||||
|
||||
OSErr SendOpenDocumentEventToProcess(ProcessSerialNumber *targetPSN, const FSSpec * documentFSSpecPtr)
|
||||
{
|
||||
return SendFSSEventToProcess (targetPSN, kCoreEventClass, kAEOpenDocuments, documentFSSpecPtr);
|
||||
}
|
||||
|
||||
|
||||
static Boolean HasCatSearch (short vRefNum)
|
||||
{
|
||||
IOParam pb;
|
||||
GetVolParmsInfoBuffer buf;
|
||||
pb.ioVRefNum = vRefNum;
|
||||
pb.ioBuffer = (Ptr)&buf;
|
||||
pb.ioReqCount = 6;
|
||||
pb.ioNamePtr = nil;
|
||||
if (PBHGetVolParmsSync ((HParmBlkPtr)&pb) == noErr) {
|
||||
if (pb.ioActCount >= 6 && (buf.vMAttrib & (1L<<bHasCatSearch)) != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Boolean IsRemoteVolume (short vRefNum)
|
||||
{
|
||||
IOParam pb;
|
||||
GetVolParmsInfoBuffer buf;
|
||||
pb.ioVRefNum = vRefNum;
|
||||
pb.ioBuffer = (Ptr)&buf;
|
||||
pb.ioReqCount = 14;
|
||||
pb.ioNamePtr = nil;
|
||||
if (PBHGetVolParmsSync ((HParmBlkPtr)&pb) == noErr) {
|
||||
if (pb.ioActCount >= 14 && buf.vMLocalHand != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static OSErr checkThisVolume (short currVRefNum, OSType creator, FSSpecPtr applicationFSSpecPtr, Boolean *foundRef)
|
||||
{
|
||||
OSErr retCode;
|
||||
Boolean foundFlag = false;
|
||||
|
||||
// find the path refNum for the desktop database for
|
||||
// the volume we're interested in
|
||||
|
||||
DTPBRec desktopParams;
|
||||
desktopParams.ioVRefNum = currVRefNum;
|
||||
desktopParams.ioNamePtr = nil;
|
||||
retCode = PBDTGetPath(&desktopParams);
|
||||
|
||||
if (retCode == noErr) {
|
||||
if (desktopParams.ioDTRefNum == 0) {
|
||||
// oops?!
|
||||
retCode = -1; // !TT new 30 Jan 99
|
||||
} else {
|
||||
|
||||
// iterate over all possible creators on one volume
|
||||
|
||||
short idx = 0;
|
||||
do {
|
||||
// use the GetAPPL call to find the preferred application
|
||||
// for opening any document with this one's creator
|
||||
|
||||
desktopParams.ioIndex = idx++; // this is the way the Finder in OS 7.6.1 does it: starts with idx 0, then comes 1, 2, ...
|
||||
desktopParams.ioFileCreator = creator;
|
||||
desktopParams.ioNamePtr = applicationFSSpecPtr->name;
|
||||
retCode = PBDTGetAPPLSync(&desktopParams);
|
||||
|
||||
if (retCode == noErr) {
|
||||
|
||||
// okay, found it; fill in the application file spec
|
||||
// and set the flag indicating we're done
|
||||
|
||||
applicationFSSpecPtr->parID = desktopParams.ioAPPLParID;
|
||||
applicationFSSpecPtr->vRefNum = currVRefNum;
|
||||
|
||||
// However, we have to make sure that the app
|
||||
// really still exists and that it is a APPL in deed.
|
||||
// If not, we have to continue to search
|
||||
|
||||
CInfoPBRec ci;
|
||||
HFileInfo &fi = (HFileInfo&)ci;
|
||||
fi.ioNamePtr = applicationFSSpecPtr->name;
|
||||
fi.ioVRefNum = currVRefNum;
|
||||
fi.ioDirID = applicationFSSpecPtr->parID;
|
||||
fi.ioFDirIndex = 0;
|
||||
if (PBGetCatInfoSync (&ci) == noErr) {
|
||||
if (/* do not check the creation date, because the Finder doesn't do it either: fi.ioFlCrDat == desktopParams.ioTagInfo && */
|
||||
fi.ioFlFndrInfo.fdCreator == desktopParams.ioFileCreator &&
|
||||
fi.ioFlFndrInfo.fdType == 'APPL' || fi.ioFlFndrInfo.fdType == 'APPC' || fi.ioFlFndrInfo.fdType == 'APPD' || fi.ioFlFndrInfo.fdType == 'appe' // +++ add more types or use a better detection?
|
||||
) {
|
||||
foundFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!foundFlag && retCode == noErr);
|
||||
}
|
||||
}
|
||||
*foundRef = foundFlag;
|
||||
return retCode;
|
||||
}
|
||||
|
||||
// FindApplicationByCreator uses the Desktop Database to
|
||||
// locate the creator application for the given document
|
||||
//
|
||||
// this routine will first check the desktop database of the disk
|
||||
// containing the document, then the desktop database of all local
|
||||
// disks, then the desktop databases of all server volumes
|
||||
// (so up to three passes will be made)
|
||||
// exception (13.2.99): when the file is located on a remote vol,
|
||||
// the boot vol is searched first
|
||||
// now returns fnfErr if app is not found
|
||||
|
||||
// Attention: It does not support the "fopn" Finder interception AE that has been introduced
|
||||
// in Mac OS 8!
|
||||
|
||||
OSErr FindApplicationByCreator (OSType creator, short firstVol, FSSpec *applicationFSSpecRef)
|
||||
{
|
||||
short volumeIndex;
|
||||
OSErr err;
|
||||
Boolean found = false;
|
||||
short vRefNum, skipThisVol = 0;
|
||||
|
||||
if (IsRemoteVolume (firstVol)) {
|
||||
// first, check the boot vol
|
||||
GetSysVolume (&vRefNum);
|
||||
checkThisVolume (vRefNum, creator, applicationFSSpecRef, &found);
|
||||
if (found) return noErr;
|
||||
skipThisVol = vRefNum;
|
||||
}
|
||||
|
||||
// check the vol the doc is on
|
||||
checkThisVolume (firstVol, creator, applicationFSSpecRef, &found);
|
||||
if (found) return noErr;
|
||||
|
||||
for (int remotePass = 0; remotePass <= 3; ++remotePass) {
|
||||
volumeIndex = 0;
|
||||
do {
|
||||
HParamBlockRec pb;
|
||||
HVolumeParam &vp = (HVolumeParam&)pb;
|
||||
|
||||
vp.ioNamePtr = nil;
|
||||
vp.ioVRefNum = 0;
|
||||
vp.ioVolIndex = ++volumeIndex;
|
||||
err = PBHGetVInfoSync (&pb);
|
||||
if (err != nsvErr) {
|
||||
if (err != noErr) return err;
|
||||
if (vp.ioVRefNum != firstVol && vp.ioVRefNum != skipThisVol) {
|
||||
// prio: 0 & 1 for local, 2 & 3 for remote; 0 & 2 with CatSearch, 1 & 3 without CatSearch
|
||||
int volumePrio = IsRemoteVolume (vp.ioVRefNum) * 2 + (HasCatSearch (vp.ioVRefNum)?0:1);
|
||||
if (remotePass == volumePrio) {
|
||||
checkThisVolume (vp.ioVRefNum, creator, applicationFSSpecRef, &found);
|
||||
if (found) {
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (err != nsvErr);
|
||||
}
|
||||
if (err == nsvErr) err = fnfErr;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
OSErr FindApplicationFromDocument (const FSSpec * documentFSSpecPtr, FSSpec *applicationFSSpecRef)
|
||||
{
|
||||
OSErr err;
|
||||
OSType creator;
|
||||
|
||||
// verify the document file exists and get its creator type
|
||||
{
|
||||
FInfo documentFInfo;
|
||||
err = FSpGetFInfo(documentFSSpecPtr, &documentFInfo);
|
||||
if (err != noErr) return err;
|
||||
creator = documentFInfo.fdCreator;
|
||||
}
|
||||
|
||||
return FindApplicationByCreator (creator, documentFSSpecPtr->vRefNum, applicationFSSpecRef);
|
||||
}
|
||||
|
||||
OSErr OpenWithFinder (const FSSpec *spec)
|
||||
{
|
||||
ProcessSerialNumber finderPSN;
|
||||
FSSpec finderSpec;
|
||||
OSErr err = FindRunningAppBySignature ('FNDR', 'MACS', &finderPSN, &finderSpec);
|
||||
if (!err) {
|
||||
err = SendFSSEventToProcess (&finderPSN, kCoreEventClass, kAEOpenDocuments, spec);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
OSErr FindRunningAppBySignature (OSType fileType, OSType creator, ProcessSerialNumber *psn, FSSpec *fileSpec)
|
||||
// from: "SignatureToApp.c", by Jens Alfke, DTS, Apple Computer 1991
|
||||
{
|
||||
OSErr err;
|
||||
ProcessInfoRec info;
|
||||
psn->highLongOfPSN = 0;
|
||||
psn->lowLongOfPSN = kNoProcess;
|
||||
do{
|
||||
err = GetNextProcess(psn);
|
||||
if (!err) {
|
||||
info.processInfoLength = sizeof (info);
|
||||
info.processName = NULL;
|
||||
info.processAppSpec = fileSpec;
|
||||
err = GetProcessInformation (psn, &info);
|
||||
}
|
||||
} while (!err && info.processSignature != creator && info.processType != fileType);
|
||||
if (!err) *psn = info.processNumber;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static long CountItems (AEDesc *d)
|
||||
{
|
||||
long items = 1;
|
||||
if(d->descriptorType == typeNull) {
|
||||
items = 0;
|
||||
} else if((d->descriptorType == typeAEList) || (d->descriptorType == typeAERecord)) {
|
||||
AECountItems(d, &items);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
static void ae_dispose (AEDesc &d)
|
||||
{
|
||||
if (d.dataHandle) AEDisposeDesc (&d);
|
||||
}
|
||||
|
||||
OSErr FindOpenCDEVInFinder (Boolean shouldUseAEs, OSType creator, FSSpec *itsSpec)
|
||||
// algorithm: either uses AppleEvents to get list of all windows, coercing the results to FSSpecs
|
||||
// The FSSpecs can then be used for both getting the creator code and for closing the window
|
||||
// returns: 0 if not open in Finder, 1 if open, neg. value if error occured
|
||||
{
|
||||
long theTimeout = 5*60; // wait no more than 5 seconds for Finder to respond
|
||||
|
||||
if (!shouldUseAEs) {
|
||||
return FindOpenFileByTypeAndCreator ('cdev', creator, itsSpec);
|
||||
}
|
||||
|
||||
Boolean found = false;
|
||||
OSErr err;
|
||||
|
||||
AEDesc dataDescriptor = {typeNull,0};
|
||||
AppleEvent reply = {typeNull,0};
|
||||
AEDesc allCreators = {typeNull,0};
|
||||
AEDesc targetAddrDesc = {typeNull,0};
|
||||
AppleEvent ae = {typeNull,0};
|
||||
AEDesc allWinsSpecifier = {typeNull,0}, keyData = {typeNull,0};
|
||||
AEDesc keyData2 = {typeNull,0};
|
||||
AEDesc directObjectSpecifier = {typeNull,0}, nullDesc = {typeNull,0};
|
||||
|
||||
ProcessSerialNumber finderPSN, frontPSN;
|
||||
FSSpec finderSpec;
|
||||
err = FindRunningAppBySignature ('FNDR', 'MACS', &finderPSN, &finderSpec);
|
||||
if (err) goto Bail;
|
||||
|
||||
GetFrontProcess (&frontPSN);
|
||||
Boolean finderIsFrontProcess;
|
||||
SameProcess (&frontPSN, &finderPSN, &finderIsFrontProcess);
|
||||
|
||||
if (finderIsFrontProcess) {
|
||||
// oops, we will not be successful sending the AE (a timeout would occur).
|
||||
// So fall back to the other method.
|
||||
err = FindOpenFileByTypeAndCreator ('cdev', creator, itsSpec);
|
||||
return err; // no cleanup necessary here yet
|
||||
}
|
||||
|
||||
err = AECreateDesc (typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(ProcessSerialNumber), &targetAddrDesc);
|
||||
if (err) goto Bail;
|
||||
|
||||
err = AECreateAppleEvent(kAECoreSuite, kAEGetData, &targetAddrDesc, kAutoGenerateReturnID, kAnyTransactionID, &ae);
|
||||
|
||||
// want:type(cwin), from:'null'(), form:indx, seld:abso('all ')
|
||||
OSType all = 'all ';
|
||||
err = AECreateDesc (typeAbsoluteOrdinal, &all, sizeof(all), &keyData);
|
||||
if (err) goto Bail;
|
||||
|
||||
err = CreateObjSpecifier (cWindow, &nullDesc, formAbsolutePosition, &keyData, true, &allWinsSpecifier);
|
||||
if (err) goto Bail;
|
||||
|
||||
// want:type(prop), from:<allWinsSpecifier>, form:prop, seld:type(cobj)
|
||||
OSType cobj = cObject;
|
||||
err = AECreateDesc (typeType, &cobj, sizeof(cobj), &keyData2);
|
||||
if (err) goto Bail;
|
||||
|
||||
err = CreateObjSpecifier (cProperty, &allWinsSpecifier, formPropertyID, &keyData2, true, &directObjectSpecifier);
|
||||
if (err) goto Bail;
|
||||
|
||||
err = AEPutParamDesc (&ae, keyDirectObject, &directObjectSpecifier);
|
||||
if (err) goto Bail;
|
||||
AEDisposeDesc (&directObjectSpecifier);
|
||||
|
||||
// core,getd,'----':<>, rtyp:type(list)"
|
||||
OSType list = 'list';
|
||||
err = AECreateDesc (typeType, &list, sizeof(list), &dataDescriptor);
|
||||
if (err) goto Bail;
|
||||
|
||||
err = AEPutParamDesc (&ae, keyAERequestedType, &dataDescriptor);
|
||||
if (err) goto Bail;
|
||||
AEDisposeDesc (&dataDescriptor);
|
||||
|
||||
err = AESend (&ae, &reply, kAEWaitReply, kAEHighPriority, theTimeout, nil, nil);
|
||||
if (err) goto Bail;
|
||||
|
||||
ae_dispose (ae);
|
||||
|
||||
err = AEGetParamDesc (&reply, keyAEResult, typeWildCard, &allCreators);
|
||||
if (err) goto Bail;
|
||||
|
||||
long n = CountItems (&allCreators);
|
||||
for (int i = 1; i < n; ++i) {
|
||||
AEDesc w;
|
||||
AEKeyword ignoreKey;
|
||||
if (AEGetNthDesc (&allCreators, i, typeFSS, &ignoreKey, &w) == noErr) {
|
||||
FSSpec spec;
|
||||
spec = *(FSSpec*)*w.dataHandle;
|
||||
AEDisposeDesc (&w);
|
||||
FInfo fi;
|
||||
if (FSpGetFInfo (&spec, &fi) == noErr && fi.fdCreator == creator) {
|
||||
// we found it
|
||||
*itsSpec = spec;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
err = found;
|
||||
|
||||
Bail:
|
||||
ae_dispose (keyData);
|
||||
ae_dispose (keyData2);
|
||||
ae_dispose (targetAddrDesc);
|
||||
ae_dispose (dataDescriptor);
|
||||
ae_dispose (allWinsSpecifier);
|
||||
ae_dispose (directObjectSpecifier);
|
||||
ae_dispose (allCreators);
|
||||
ae_dispose (reply);
|
||||
ae_dispose (ae);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// EOF
|
36
mac-cpp-source/utils/LaunchLib.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Functions for launching apps with documents
|
||||
*
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*
|
||||
* some of these routines are not from me (TT), but from some DTS sample code
|
||||
* here's a link to it: <http://developer.apple.com/dev/techsupport/source/code/Snippets/Processes/LaunchWithDoc2.1/LaunchWithDoc2.c.html>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Processes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
-> also see "SignatureToApp.c" as a demo (comes from Apple and does some things differently)
|
||||
*/
|
||||
OSErr OpenWithFinder (const FSSpec * applicationFSSpecPtr); // uses AppleEvent to open the file
|
||||
OSErr LaunchAppl (const FSSpec * applicationFSSpecPtr, Boolean inBackground); // starts APPLs only
|
||||
OSErr OpenSpecifiedDocument(const FSSpec * documentFSSpecPtr, Boolean inBackground); // starts APPLs or opens docs with its APPLs
|
||||
OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr, const FSSpec * documentFSSpecPtr, Boolean inBackground);
|
||||
OSErr SendOpenDocumentEventToProcess(ProcessSerialNumber *targetPSN, const FSSpec * documentFSSpecPtr);
|
||||
OSErr FindApplicationFromDocument(const FSSpec * documentFSSpecPtr, FSSpec *applicationFSSpecRef);
|
||||
OSErr FindApplicationByCreator (OSType creator, short firstVol, FSSpec *applicationFSSpecRef);
|
||||
OSErr FindRunningAppBySignature (OSType fileType, OSType creator, ProcessSerialNumber *psn, FSSpec *fileSpec);
|
||||
OSErr SendFSSEventToProcess (ProcessSerialNumber *targetPSN, OSType aeClass, OSType aeCmd, const FSSpec *documentFSSpecPtr);
|
||||
OSErr FindOpenCDEVInFinder (Boolean shouldUseAEs, OSType creator, FSSpec *itsSpec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// EOF
|
261
mac-cpp-source/utils/PascalLib.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Library for handling Pascal-Strings
|
||||
*
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*
|
||||
* Originally by Markus Fritze.
|
||||
* Changes and additions by Thomas Tempelmann:
|
||||
* - pstrlen neu
|
||||
* - BlockMoveData statt BlockMove
|
||||
* - pstrcmp liefert nicht Boolean sondern short, wie bei strcmp.
|
||||
* - pstrupper neu
|
||||
* 28.12.95 TT:
|
||||
* - alle Zugriffe auf s[0] und d[0] word-expandiert, bevor mit ihnen gerechnet wird,
|
||||
* um zu verhindern, da§ bei der LŠnge 255 ein †berlauf nach 0 passiert.
|
||||
* 08.04.95 TT:
|
||||
* - pstrcmp() lieferte "C"<"BB", da das LŠngenbyte mit verglichen wurde. Korrigiert.
|
||||
* - BlockMoveData() durch copyBytes() ersetzt, da vermutlich i.d.R. schneller.
|
||||
* 09.04.95 TT:
|
||||
* - Geschw-optimiert: pfindchar, pstrupper, pdelchars
|
||||
* - pstrextract() neu
|
||||
* 30.4.96 TT:
|
||||
* - copyBytes kopierte falsch, wenn source und dest sich Ÿberlagern und dest>source war.
|
||||
* 18.7.96 TT:
|
||||
* - strcatc neu
|
||||
* 14.8.96 TT:
|
||||
* - sicherheitshalber 'far' accesses eingefŸhrt.
|
||||
* 23.07.00 TT:
|
||||
* - disabled the "far" pragmas
|
||||
* - changed "StringPtr" into "unsigned char*" so that it can be compiled for Windows, too.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "PascalLib.h"
|
||||
|
||||
#pragma push
|
||||
#pragma cplusplus on
|
||||
|
||||
/*
|
||||
* We need far data access in this module
|
||||
* (alternatively we could setup A5 appropriately):
|
||||
*/
|
||||
/* !TT July 23, 2000 - removed this
|
||||
#ifndef __powerc
|
||||
#pragma far_data on
|
||||
#pragma far_strings on
|
||||
#pragma far_vtables on
|
||||
#endif
|
||||
*/
|
||||
|
||||
static void copyBytes (const unsigned char* s0, unsigned char* d, unsigned short len)
|
||||
{
|
||||
const unsigned char* s = s0;
|
||||
if (d > s) {
|
||||
// rŸckwŠrts kopieren
|
||||
if (len) {
|
||||
d += len;
|
||||
s += len;
|
||||
do { *--d = *--s; } while (--len);
|
||||
}
|
||||
} else {
|
||||
if (len) do { *d++ = *s++; } while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
void pstrcpy (unsigned char* d, const unsigned char* s)
|
||||
{
|
||||
copyBytes (s, d, ((unsigned short)s[0])+1);
|
||||
}
|
||||
|
||||
void pstrncpy (unsigned char* d, const unsigned char* s, short n)
|
||||
// n: dest buffer size including length char
|
||||
{
|
||||
if (n) {
|
||||
if (n > ((unsigned short)s[0])+1) n = ((unsigned short)s[0])+1;
|
||||
copyBytes (s, d, n);
|
||||
if (n < ((unsigned short)d[0])+1) d[0] = n-1;
|
||||
}
|
||||
}
|
||||
|
||||
void pstrcat (unsigned char* d, const unsigned char* s)
|
||||
{
|
||||
copyBytes (s + 1, d + ((unsigned short)d[0]) + 1, s[0]);
|
||||
d[0] += s[0];
|
||||
}
|
||||
|
||||
void pstrcatc (unsigned char* d, const char* s)
|
||||
{
|
||||
short n = strlen(s);
|
||||
copyBytes ((unsigned char*)s, d + ((unsigned short)d[0]) + 1, n);
|
||||
d[0] += n;
|
||||
}
|
||||
|
||||
void pstrcatchar (unsigned char* d, const unsigned char c)
|
||||
{
|
||||
d[++d[0]] = c;
|
||||
}
|
||||
|
||||
short pfindchar (const unsigned char* d, const unsigned char c)
|
||||
{
|
||||
short i, dlen = d[0];
|
||||
for (i = 1; i <= dlen; i++) {
|
||||
if (d[i] == c) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pstrextract (unsigned char* d, const unsigned char* s, short offset, short len)
|
||||
{
|
||||
short slen;
|
||||
if (offset < 1 || offset > (slen = s[0])) {
|
||||
d[0] = 0;
|
||||
return;
|
||||
}
|
||||
if (((offset-1) + len) > slen) {
|
||||
len = slen - offset + 1;
|
||||
}
|
||||
if (len <= 0) {
|
||||
d[0] = 0;
|
||||
return;
|
||||
}
|
||||
copyBytes (s + offset, d + 1, len);
|
||||
d[0] = len;
|
||||
}
|
||||
|
||||
void pdelchars (unsigned char* d, short offset, short len)
|
||||
{
|
||||
short dlen;
|
||||
if (offset > (dlen = d[0])) return; // Offset zu gro§
|
||||
if (len <= 0) return; // LŠnge zu klein
|
||||
if ((offset + len) > (dlen + 1)) { // LŠnge zu gro§?
|
||||
d[0] = offset; // String zurechtstutzen
|
||||
return;
|
||||
}
|
||||
copyBytes (d + offset + len, d + offset, dlen - len - offset + 1);
|
||||
d[0] -= len;
|
||||
}
|
||||
|
||||
void pstrins (unsigned char* d, const unsigned char* s, short offset)
|
||||
{
|
||||
short slen, dlen;
|
||||
if ((slen = s[0]) == 0) return; // einzufŸgender String = 0 Bytes => raus
|
||||
if (offset > (dlen = d[0])) { // ggf. an den String anhŠngen
|
||||
offset = dlen + 1;
|
||||
}
|
||||
copyBytes (d + offset, d + offset + slen, dlen + 1 - offset); // String nach hinten
|
||||
copyBytes (s + 1, d + offset, slen); // String einfŸgen
|
||||
d[0] += slen; // und die LŠnge updaten
|
||||
}
|
||||
|
||||
short pstrcmp (const unsigned char* s10, const unsigned char* s20)
|
||||
{
|
||||
const unsigned char* s1 = s10;
|
||||
const unsigned char* s2 = s20;
|
||||
unsigned char l1 = *s1++, l2 = *s2++;
|
||||
unsigned char len = (l1 < l2)? l1:l2;
|
||||
|
||||
if (len) do {
|
||||
if (*s1++ != *s2++) {
|
||||
return (s1[-1] < s2[-1])? -1: +1;
|
||||
}
|
||||
} while (--len);
|
||||
if (l1 == l2) {
|
||||
return 0;
|
||||
} else {
|
||||
return (l1 < l2)? -1: +1;
|
||||
}
|
||||
}
|
||||
|
||||
short pstrlen (const unsigned char* s1)
|
||||
{
|
||||
return s1[0];
|
||||
}
|
||||
|
||||
void pstrupper (unsigned char* d)
|
||||
{
|
||||
short i, dlen = d[0];
|
||||
for (i = 1; i <= dlen; i++) {
|
||||
d[i] = toupper (d[i]);
|
||||
}
|
||||
}
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
/*
|
||||
short pfindstr (const unsigned char* target, const unsigned char* search)
|
||||
{
|
||||
unsigned char* s = search;
|
||||
unsigned char* d = target;
|
||||
short slen = s[0];
|
||||
if (slen) {
|
||||
short i;
|
||||
short iend = d[0] - slen + 1;
|
||||
for (i = 1; i <= iend; i++) {
|
||||
if (d[i] == s[1]) {
|
||||
short len = slen - 1;
|
||||
if (len) {
|
||||
unsigned char* s1 = &s[2], d1 = &d[i+1];
|
||||
do {
|
||||
if (*s1++ != *d1++) {
|
||||
break;
|
||||
}
|
||||
} while (--len);
|
||||
}
|
||||
if (len == 0) return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
short pfindstr (const unsigned char* d, const unsigned char* s0)
|
||||
{
|
||||
const unsigned char* s = s0;
|
||||
short slen = *s++;
|
||||
if (slen == 0) return 0;
|
||||
--slen;
|
||||
{
|
||||
byte c = *s++;
|
||||
short i;
|
||||
short end = d[0] - slen;
|
||||
for (i = 1; i <= end; i++) {
|
||||
if (d[i] == c) {
|
||||
const byte *sp = s, *dp = &d[i+1];
|
||||
byte len = slen;
|
||||
do {
|
||||
if (len-- == 0) return i; // gefunden
|
||||
} while (*sp++ == *dp++);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pstrnins (unsigned char* d, short destSize, const unsigned char* s, short offset)
|
||||
// TT 25 Sep 97: does no write over end of dest string
|
||||
// 'destSize': size of dest string including length byte
|
||||
{
|
||||
short slen, dlen;
|
||||
if (offset < 1) return;
|
||||
if ((slen = s[0]) == 0) return; // einzufŸgender String = 0 Bytes => raus
|
||||
if (offset > (dlen = d[0])) { // ggf. an den String anhŠngen
|
||||
offset = dlen + 1;
|
||||
}
|
||||
if (offset >= destSize) return;
|
||||
if (offset + slen > destSize) {
|
||||
slen = destSize - offset;
|
||||
dlen = offset - 1;
|
||||
} else {
|
||||
if (slen + dlen >= destSize) {
|
||||
dlen = destSize - 1 - slen;
|
||||
}
|
||||
copyBytes (d + offset, d + offset + slen, dlen + 1 - offset); // String nach hinten
|
||||
}
|
||||
copyBytes (s + 1, d + offset, slen); // String einfŸgen
|
||||
d[0] = dlen + slen; // und die LŠnge updaten
|
||||
}
|
||||
|
||||
#pragma pop
|
27
mac-cpp-source/utils/PascalLib.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Library for handling Pascal-Strings
|
||||
*
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*/
|
||||
|
||||
#pragma push
|
||||
#pragma cplusplus on
|
||||
|
||||
//#include <MacTypes.h>
|
||||
|
||||
void pstrcpy (unsigned char* d, const unsigned char* s);
|
||||
void pstrcat (unsigned char* d, const unsigned char* s);
|
||||
void pstrcatc (unsigned char* d, const char* s);
|
||||
void pstrcatchar (unsigned char* d, unsigned char c);
|
||||
short pfindchar (const unsigned char* d, const unsigned char c);
|
||||
void pdelchars (unsigned char* d, short offset, short len);
|
||||
void pstrins (unsigned char* d, const unsigned char* s, short offset);
|
||||
short pstrcmp (const unsigned char* s1, const unsigned char* s2);
|
||||
short pstrlen (const unsigned char* s1);
|
||||
void pstrncpy (unsigned char* d, const unsigned char* s, short n); // n: dest buffer size including length char
|
||||
void pstrupper (unsigned char* d);
|
||||
void pstrextract (unsigned char* d, const unsigned char* s, short offset, short len);
|
||||
short pfindstr (const unsigned char* d, const unsigned char* s);
|
||||
void pstrnins (unsigned char* d, short destSize, const unsigned char* s, short offset);
|
||||
|
||||
#pragma pop
|
43
mac-cpp-source/utils/TrapAvail.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* TrapAvail.c
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*/
|
||||
|
||||
#include <Traps.h>
|
||||
#include <OSUtils.h>
|
||||
#include "TrapAvail.h"
|
||||
|
||||
Boolean TrapAvailable (short theTrap);
|
||||
|
||||
#define TrapMask 0x0800
|
||||
|
||||
static short NumToolboxTraps( void )
|
||||
{
|
||||
if (NGetTrapAddress(_InitGraf, ToolTrap) ==
|
||||
NGetTrapAddress(0xAA6E, ToolTrap))
|
||||
return 0x0200;
|
||||
else
|
||||
return 0x0400;
|
||||
}
|
||||
|
||||
static TrapType GetTrapType(short theTrap)
|
||||
{
|
||||
if ((theTrap & TrapMask) > 0)
|
||||
return ToolTrap;
|
||||
else
|
||||
return OSTrap;
|
||||
}
|
||||
|
||||
Boolean TrapAvailable (short theTrap)
|
||||
{
|
||||
TrapType tType;
|
||||
|
||||
tType = GetTrapType(theTrap);
|
||||
if (tType == ToolTrap)
|
||||
theTrap = theTrap & 0x07FF;
|
||||
if (theTrap >= NumToolboxTraps())
|
||||
theTrap = _Unimplemented;
|
||||
return NGetTrapAddress(theTrap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap);
|
||||
}
|
||||
|
||||
// EOF
|
16
mac-cpp-source/utils/TrapAvail.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* TrapAvailable.c
|
||||
* by Thomas Tempelmann, macdev@tempel.org
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
Boolean TrapAvailable (short theTrap);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// EOF
|