From 7a3d4c4b4924235b7b54e229d024aedf3f067aaf Mon Sep 17 00:00:00 2001 From: Marcio T Date: Fri, 26 Nov 2021 14:30:41 -0700 Subject: [PATCH] Added explanation documents. --- mac-cpp-source/Iomega Zip Tester.cpp | 2 + mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin | Bin 0 -> 896 bytes mac-cpp-source/macos/mac_vol.h | 2 +- mac-cpp-source/tip-doc.sit.bin | Bin 0 -> 31616 bytes mac-cpp-source/tip/tip.cpp | 5 +- mac-cpp-source/tip/tip.h | 29 +- mac-cpp-source/tip/tip_aspi.cpp | 44 +- mac-cpp-source/tip/tip_main.cpp | 75 +- mac-cpp-source/tip/tip_text.cpp | 19 + mac-cpp-source/utils/.finf/FileLib.c | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/FileLib.h | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/LaunchLib.c | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/LaunchLib.h | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/PascalLib.c | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/PascalLib.h | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/TrapAvail.c | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/TrapAvail.h | Bin 0 -> 32 bytes mac-cpp-source/utils/.finf/pstring.h | Bin 0 -> 32 bytes mac-cpp-source/utils/.rsrc/FileLib.c | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/FileLib.h | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/LaunchLib.c | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/LaunchLib.h | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/PascalLib.c | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/PascalLib.h | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/TrapAvail.c | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/TrapAvail.h | Bin 0 -> 410 bytes mac-cpp-source/utils/.rsrc/pstring.h | Bin 0 -> 410 bytes mac-cpp-source/utils/FileLib.c | 184 +++++ mac-cpp-source/utils/FileLib.h | 27 + mac-cpp-source/utils/LaunchLib.c | 684 ++++++++++++++++++ mac-cpp-source/utils/LaunchLib.h | 36 + mac-cpp-source/utils/PascalLib.c | 261 +++++++ mac-cpp-source/utils/PascalLib.h | 27 + mac-cpp-source/utils/TrapAvail.c | 43 ++ mac-cpp-source/utils/TrapAvail.h | 16 + 35 files changed, 1432 insertions(+), 22 deletions(-) create mode 100644 mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin create mode 100644 mac-cpp-source/tip-doc.sit.bin create mode 100644 mac-cpp-source/utils/.finf/FileLib.c create mode 100644 mac-cpp-source/utils/.finf/FileLib.h create mode 100644 mac-cpp-source/utils/.finf/LaunchLib.c create mode 100644 mac-cpp-source/utils/.finf/LaunchLib.h create mode 100644 mac-cpp-source/utils/.finf/PascalLib.c create mode 100644 mac-cpp-source/utils/.finf/PascalLib.h create mode 100644 mac-cpp-source/utils/.finf/TrapAvail.c create mode 100644 mac-cpp-source/utils/.finf/TrapAvail.h create mode 100644 mac-cpp-source/utils/.finf/pstring.h create mode 100644 mac-cpp-source/utils/.rsrc/FileLib.c create mode 100644 mac-cpp-source/utils/.rsrc/FileLib.h create mode 100644 mac-cpp-source/utils/.rsrc/LaunchLib.c create mode 100644 mac-cpp-source/utils/.rsrc/LaunchLib.h create mode 100644 mac-cpp-source/utils/.rsrc/PascalLib.c create mode 100644 mac-cpp-source/utils/.rsrc/PascalLib.h create mode 100644 mac-cpp-source/utils/.rsrc/TrapAvail.c create mode 100644 mac-cpp-source/utils/.rsrc/TrapAvail.h create mode 100644 mac-cpp-source/utils/.rsrc/pstring.h create mode 100644 mac-cpp-source/utils/FileLib.c create mode 100644 mac-cpp-source/utils/FileLib.h create mode 100644 mac-cpp-source/utils/LaunchLib.c create mode 100644 mac-cpp-source/utils/LaunchLib.h create mode 100644 mac-cpp-source/utils/PascalLib.c create mode 100644 mac-cpp-source/utils/PascalLib.h create mode 100644 mac-cpp-source/utils/TrapAvail.c create mode 100644 mac-cpp-source/utils/TrapAvail.h diff --git a/mac-cpp-source/Iomega Zip Tester.cpp b/mac-cpp-source/Iomega Zip Tester.cpp index b69c10d..adb4cb3 100644 --- a/mac-cpp-source/Iomega Zip Tester.cpp +++ b/mac-cpp-source/Iomega Zip Tester.cpp @@ -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; } diff --git a/mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin b/mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin new file mode 100644 index 0000000000000000000000000000000000000000..84dace820b27d9ba9d7a2defb0a314f6b017c6f6 GIT binary patch literal 896 zcmZRO^32aoO;1#a$}CU_Ni8l(Ez&D0E=txb&MaXd1_XPCm;$jPvRbCqAl}_$bJIZ> z$jo)}^g~tvVmCF)2rw`Nmz1WZd6p<>Bx@R4TAJ$u2@3_soWzur%shqQN}zjki**z{ z^OE&+6f#Om3as??%gf945+N#zD~t7#^KNinbjO$9rkh=CDkO;L&zuX|2v zUY>$uX>mzr9>Y=~07|$49eC6(=I*gxQxunpiEyFt8L)>B1LKs%pl}Kbc6DK7U~B-} zg{l$AV>-jYz{3jwl2vv!-&yaX*-z%$UrYAQD_wT@I*T~7t7%ekX|kkEx98hby-NoR?@CKgKM|?g znO?QKC%nb%0$;3cRj|G1!MV*Ay(vk_?>UlZx)oYXvJ{y9I(BtTOw8|p6&mLcH7n1| zj40BXdpS`s+Su1^^inMQ@L)JYzYlT(p5b z!T5^dwaYsnzp*{%DC=Hbb$!;{-*Q`2bBv9zm+WEYZO=`&ns(++9cv78Y(P%VnPn!% zzb(QS2=zI4e^vQ>^X{pD>u>U|**8D$jn}lg8mPg;H08p|>=T))s@wQWiz--qimI4< zdLQ<_YsmGP?k=0lmcuP=dCOe3S2z1#{){sIoa8P1*0<(vSbH(9Xv^M0=G#GTt}3dY b9D1L4=TvrnJ@=P`dG1ZAovawKOAP@4FDe=D literal 0 HcmV?d00001 diff --git a/mac-cpp-source/macos/mac_vol.h b/mac-cpp-source/macos/mac_vol.h index 21a50db..7d971f8 100644 --- a/mac-cpp-source/macos/mac_vol.h +++ b/mac-cpp-source/macos/mac_vol.h @@ -1,4 +1,4 @@ void mac_list_volumes(); void mac_unmount(int id); OSErr mac_get_drive_volumes(int driveNum, Str255 str); -OSErr mac_unmount_drive(int driveNum); \ No newline at end of file +OSErr mac_unmount_drive(int driveNum); diff --git a/mac-cpp-source/tip-doc.sit.bin b/mac-cpp-source/tip-doc.sit.bin new file mode 100644 index 0000000000000000000000000000000000000000..deabd678961ed93e640675ca814cdcac4f8a7d14 GIT binary patch literal 31616 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 literal 0 HcmV?d00001 diff --git a/mac-cpp-source/tip/tip.cpp b/mac-cpp-source/tip/tip.cpp index 5273e4e..29e7f90 100644 --- a/mac-cpp-source/tip/tip.cpp +++ b/mac-cpp-source/tip/tip.cpp @@ -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; diff --git a/mac-cpp-source/tip/tip.h b/mac-cpp-source/tip/tip.h index e0d3a8a..006b6df 100644 --- a/mac-cpp-source/tip/tip.h +++ b/mac-cpp-source/tip/tip.h @@ -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(); diff --git a/mac-cpp-source/tip/tip_aspi.cpp b/mac-cpp-source/tip/tip_aspi.cpp index 5beaa44..c40ddec 100644 --- a/mac-cpp-source/tip/tip_aspi.cpp +++ b/mac-cpp-source/tip/tip_aspi.cpp @@ -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; } diff --git a/mac-cpp-source/tip/tip_main.cpp b/mac-cpp-source/tip/tip_main.cpp index 2515c59..4ba2cb9 100644 --- a/mac-cpp-source/tip/tip_main.cpp +++ b/mac-cpp-source/tip/tip_main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,6 +8,8 @@ #include #include +#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 *******************************************************************************/ diff --git a/mac-cpp-source/tip/tip_text.cpp b/mac-cpp-source/tip/tip_text.cpp index e1d3bf3..77c0085 100644 --- a/mac-cpp-source/tip/tip_text.cpp +++ b/mac-cpp-source/tip/tip_text.cpp @@ -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"; diff --git a/mac-cpp-source/utils/.finf/FileLib.c b/mac-cpp-source/utils/.finf/FileLib.c new file mode 100644 index 0000000000000000000000000000000000000000..c13d137a708ff59369b5d8fff8524f8c919e91d7 GIT binary patch literal 32 XcmWG>jRjRRbm4$ literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.finf/LaunchLib.c b/mac-cpp-source/utils/.finf/LaunchLib.c new file mode 100644 index 0000000000000000000000000000000000000000..68071052d10adc24b3d8c094782bb43973d1a114 GIT binary patch literal 32 XcmWG>jRjRjRjRjRjRjRQDg|1$uA2Lq>XeqLg7K8S+@Ffp(&L2N{rGOwQNBX$fZB*Wmwz~~zg90X(w`Gz|=0cknrw-9Fl*$m7dz-%878vu~= BU=RQR literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.rsrc/FileLib.h b/mac-cpp-source/utils/.rsrc/FileLib.h new file mode 100644 index 0000000000000000000000000000000000000000..1b2c2f58bfa12afe723c607187d212170042b530 GIT binary patch literal 410 zcmZvYu}T9$5QhJ|4IT*x5kZV7$s0((#?B;?!@wQn^dwed6u|>AVx^64k%tI^Pmsnc zty{%X5Zl1jLSW0SGR|EPB4l9Z`)3FK-C4i_U`1Tg^em!85GjYV$htzL_le9i%_Hx{ zH&=dqv2$(1M$|lw4mzzSd#KE4=^6Vj#AN*V3D_gP^@Vc)I3K{~y+Ze^3c0ZgSt&uS zl#pN##xnRW8pJ0C4?~TBG-|j*yRQ)z-VnMo=DQ4CQp|*@nR=1+0wr~qWUW6#mHk{N zfglN-XU{rBKIq+cFMC24az0E33(ds9!Z3|dmgyYxO&ERm*o5s2 z3@$T(_!k3%^evE!fU1B20rVM=i3n5X)pLEsjsb;afZ@yN8xR}>WDEI*J2?SqIp((r NS22G8vweW#3;^qZI0FCx literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.rsrc/LaunchLib.h b/mac-cpp-source/utils/.rsrc/LaunchLib.h new file mode 100644 index 0000000000000000000000000000000000000000..8178a026103ae5b5ce6f02a089470645690c0704 GIT binary patch literal 410 zcmZQzU}RumU@AOP4-6Cla%?BeRizyKy0!K8gSSOh{cFnBO< z`sU{)Cg-C#6P3fnz{1eTn8oyx`6P_Kd#vdV0|T=?5bp*l28AO~6)+$mY($tcub%58 o#s!p>VQ^z$^bH6O0fx>|3J4x0P_bh+Xuu0010%O3IG5A literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.rsrc/PascalLib.c b/mac-cpp-source/utils/.rsrc/PascalLib.c new file mode 100644 index 0000000000000000000000000000000000000000..845a8374a5d9959ab2232c98d8efcc175a687fc2 GIT binary patch literal 410 zcmZQzU}RumUp#c_lxB%mS?tsMNJCI%*k5Z8zh=WtI~puPr% zMg}Y*aLrK0-D8!J3=9%nKwD=qFaXUyv|dqwfx&@+`#J*yi_d=`fU5LB(n`o(KY?oD zW-%~u-$FCX3%6Mw44l6Cd5OvSNJ`L|Objdxg^V^#-I1{9KEaARQf4G0bbvW0xZot%KQ9P?YahZ&eZfZ0AkaRva+3O8o} literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.rsrc/PascalLib.h b/mac-cpp-source/utils/.rsrc/PascalLib.h new file mode 100644 index 0000000000000000000000000000000000000000..a806bdcc91418f12dbd38c44a1e16c5587351bd3 GIT binary patch literal 410 zcmZQzU}RumU5_XIvDRU%d*(QXrMoUE&=%ign_;R5iCFo$N;esVamLEu8-I;ppXnOd>MTM ef`fo;A>VK(Cm=1y{PzEUAPol0AHZxM5C;GhqB@fR literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.rsrc/TrapAvail.c b/mac-cpp-source/utils/.rsrc/TrapAvail.c new file mode 100644 index 0000000000000000000000000000000000000000..e7f16a029d944b984d68dff8bd10f78c2b5ccbf9 GIT binary patch literal 410 zcmZQzU}RumUzKv1$_r24;Sst+SBj_$*a{T&-9kztnPtfW*wa5(Ps& z0|j3o3t1VE&8G`i*@PyHh0EsvR=EO;6hg>@fzvlXFEKeEA%wwVVqjs&XH;Rj&fE;6 zf&MUu_ygn@pl?6~3y=abP{WjY^;{oukZWat;mhb75F7+#3;BjSIRR-o=C`15g8=3a JV73p42LRodIBNg^ literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.rsrc/TrapAvail.h b/mac-cpp-source/utils/.rsrc/TrapAvail.h new file mode 100644 index 0000000000000000000000000000000000000000..a296974a98e80d7ccec8a3b6f45baf47e6a5b1c4 GIT binary patch literal 410 zcmZQzU}RumU71Wel9-uSY{lu8pOcbWq~M#Fmzd5SQj}QW zSeBTXqnE+Nz{C*Z8WG|g?&-=1G6#q-MS!NFfV;=4rU3XeqLg7K8iC@IZO;J4B3oVm>F1%Vf5W&)hi+X0Qm*%c?O^=SU@0!Df8;N qJ|Z80N@N(^7#Mv6f`fo;A>VK(Cm=1y{PzEUAPol0AHZxM5C;HSHC0Fe literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/.rsrc/pstring.h b/mac-cpp-source/utils/.rsrc/pstring.h new file mode 100644 index 0000000000000000000000000000000000000000..dcb17c372786871a4ab7aa8093e9d6df3ced50f4 GIT binary patch literal 410 zcmZQzU}RumU5_XA{bbh-ZCY_=)1>SzXAQR4uXNc0jXvIQa}cXjR;fb)pLDhS%5+^ j!0=`C4G0bbvW0xZot%KQ9P``%|A90ZFn<8EeLx%lJ9<1T literal 0 HcmV?d00001 diff --git a/mac-cpp-source/utils/FileLib.c b/mac-cpp-source/utils/FileLib.c new file mode 100644 index 0000000..e8578ec --- /dev/null +++ b/mac-cpp-source/utils/FileLib.c @@ -0,0 +1,184 @@ +/* + * File Utilities (System 7 and above) + * + * by Thomas Tempelmann, macdev@tempel.org + */ + + +#include +#include +#include +#include +#include +#include +#include +//#include + +#define CALL_NOT_IN_CARBON 1 // for Universal Headers 3.3 +#include + +#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 diff --git a/mac-cpp-source/utils/FileLib.h b/mac-cpp-source/utils/FileLib.h new file mode 100644 index 0000000..754c10a --- /dev/null +++ b/mac-cpp-source/utils/FileLib.h @@ -0,0 +1,27 @@ +/* + * File Utilities (System 7 and above) + * + * by Thomas Tempelmann, macdev@tempel.org + */ + +#include + +#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 diff --git a/mac-cpp-source/utils/LaunchLib.c b/mac-cpp-source/utils/LaunchLib.c new file mode 100644 index 0000000..2874f72 --- /dev/null +++ b/mac-cpp-source/utils/LaunchLib.c @@ -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: + */ + + +//#include +#include +#include +#include +#include +#include +#include +#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<= 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:, 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 diff --git a/mac-cpp-source/utils/LaunchLib.h b/mac-cpp-source/utils/LaunchLib.h new file mode 100644 index 0000000..6e8ac2f --- /dev/null +++ b/mac-cpp-source/utils/LaunchLib.h @@ -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: + */ + +#pragma once + +#include + +#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 diff --git a/mac-cpp-source/utils/PascalLib.c b/mac-cpp-source/utils/PascalLib.c new file mode 100644 index 0000000..da92221 --- /dev/null +++ b/mac-cpp-source/utils/PascalLib.c @@ -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 + +#include +#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 diff --git a/mac-cpp-source/utils/PascalLib.h b/mac-cpp-source/utils/PascalLib.h new file mode 100644 index 0000000..ebfd270 --- /dev/null +++ b/mac-cpp-source/utils/PascalLib.h @@ -0,0 +1,27 @@ +/* + * Library for handling Pascal-Strings + * + * by Thomas Tempelmann, macdev@tempel.org + */ + +#pragma push +#pragma cplusplus on + +//#include + +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 diff --git a/mac-cpp-source/utils/TrapAvail.c b/mac-cpp-source/utils/TrapAvail.c new file mode 100644 index 0000000..c30cf73 --- /dev/null +++ b/mac-cpp-source/utils/TrapAvail.c @@ -0,0 +1,43 @@ +/* + * TrapAvail.c + * by Thomas Tempelmann, macdev@tempel.org + */ + +#include +#include +#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 diff --git a/mac-cpp-source/utils/TrapAvail.h b/mac-cpp-source/utils/TrapAvail.h new file mode 100644 index 0000000..f539703 --- /dev/null +++ b/mac-cpp-source/utils/TrapAvail.h @@ -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