mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-22 23:29:27 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1074 lines
26 KiB
C
1074 lines
26 KiB
C
/*
|
|
File: ROM_EM.c
|
|
|
|
Contains: xxx put contents here xxx
|
|
|
|
Written by: xxx put writers here xxx
|
|
|
|
Copyright: © 1992 by Apple Computer, Inc., all rights reserved.
|
|
|
|
Change History (most recent first):
|
|
|
|
<1> 11/5/92 RB first checked in
|
|
|
|
*/
|
|
|
|
/*
|
|
© 1990-1992 Apple Computer, Inc. By Ricardo Batista
|
|
|
|
This file is a ROM version of Extensions Manager based on Extensions Manager 1.8
|
|
The ROM version provides minimal functionality and looks for resources in the system
|
|
file first, so that it can be localized if nessesary. To invoke it the user needs to press
|
|
the space bar and Command keys while booting. We get called by the InstallMgr routine
|
|
in StartBoot.a, InstallMgr gets called from the SuperMario Gibbly, just before extensions
|
|
are loaded.
|
|
|
|
We first test for space-Cmd down, and if it is then we initialize enough
|
|
of the tollbox so that we are able to make windows and dialogs. We then call the
|
|
pseudo-cdev code, make our dialog and pretend that we are the control panel until the user
|
|
clicks on the close box of our window. This code comes from a Control Panel, so hang on...
|
|
|
|
Notice that we do use GetNextEvent and routines like it because those routines do
|
|
a lot of work in the background, the least we use the toolbox the more compatible
|
|
that we will be in this case. (The state of the toolbox managers at startup
|
|
varies with machines and system releases).
|
|
|
|
SPECIAL INSTRUCTIONS:
|
|
|
|
Compiled with MPW 3.2
|
|
|
|
|
|
HISTORY:
|
|
|
|
11/5/92 RB Copied some code from Extensions Manager 1.8 and made it work in ROM.
|
|
Look for resources in the system file first, then in ROM so that someone
|
|
can localize this code for other countries.
|
|
Got rid of all the sets and other functionality which is no part of my
|
|
idea of a minimal EM, such as old type INITs, menus, etc.
|
|
|
|
*/
|
|
|
|
#define SystemSixOrLater 1
|
|
#define SystemSevenOrLater true
|
|
|
|
#include <Types.h>
|
|
#include <QuickDraw.h>
|
|
#include <Files.h>
|
|
#include <Folders.h>
|
|
#include <Dialogs.h>
|
|
#include <Lists.h>
|
|
#include <Memory.h>
|
|
#include <Devices.h>
|
|
#include <Resources.h>
|
|
#include <ToolUtils.h>
|
|
#include <Events.h>
|
|
#include <SysEqu.h>
|
|
#include <Menus.h>
|
|
#include <TextEdit.h>
|
|
#include <Fonts.h>
|
|
#include <Packages.h>
|
|
#include <Traps.h>
|
|
#include <Aliases.h>
|
|
#include <ShutDown.h>
|
|
#include <TextUtils.h>
|
|
#include <SysEqu.h>
|
|
|
|
|
|
|
|
|
|
/*
|
|
This is a copy of the quickdraw globals that MPW usually allocates for us
|
|
under a5, to be really safe and compatible with the future we need to add space
|
|
for the a5 reference (tempA5) and set a5 to point there before calling InitGraf
|
|
once InitGraf is called we can initialize some of the toolbox managers and make
|
|
windows and dialogs.
|
|
*/
|
|
|
|
|
|
typedef struct {
|
|
char privates[76];
|
|
long randSeed;
|
|
BitMap screenBits;
|
|
Cursor arrow;
|
|
Pattern dkGray;
|
|
Pattern ltGray;
|
|
Pattern gray;
|
|
Pattern black;
|
|
Pattern white;
|
|
GrafPtr thePort;
|
|
long tempA5;
|
|
} qdGlob;
|
|
|
|
|
|
|
|
typedef struct {
|
|
char fileName[40];
|
|
long enabledDirID;
|
|
long disabledDirID;
|
|
short vRefNum; // must be kept for each, because next system may
|
|
Boolean enabled; // have special folders in different volumes
|
|
char filler;
|
|
long creator;
|
|
} InitInfo, *InitInfoPtr, **InitInfoH;
|
|
|
|
|
|
typedef struct {
|
|
ListHandle list;
|
|
InitInfoH files;
|
|
} cdev_data, **cdev_dataH;
|
|
|
|
|
|
|
|
|
|
// PROTOTYPES
|
|
|
|
|
|
|
|
|
|
void ShowExtensions(void);
|
|
pascal void mySetA5(long) = 0x2A5F; // move.l (sp)+,a5
|
|
extern pascal void ROM_EM_OSDISPATCH(void *);
|
|
pascal void ROM_EM(void);
|
|
|
|
cdev_dataH EM_cdev(short message, short item, short numItems, short CPanelID,
|
|
EventRecord *theEvent, cdev_dataH cdevStorage, DialogPtr CPDialog);
|
|
|
|
|
|
void ReadFiles(ListHandle list,InitInfoH files);
|
|
void SaveInfo(ListHandle list,InitInfoH files);
|
|
void RevertInfo(ListHandle list,InitInfoH files);
|
|
void AddFolder(InitInfoH files, long GoodFolder, long DisFolder, Boolean useEnabledF);
|
|
void AllInfo(ListHandle list,InitInfoH files, Boolean on);
|
|
void Add7Folders(void);
|
|
Boolean HasINIT(CInfoPBRec *info);
|
|
void ErrDlg(short id);
|
|
void Sort(InitInfoH files, long folder);
|
|
pascal Boolean UpdateFilter(DialogPtr theDialog, EventRecord *theEvent,
|
|
short *item);
|
|
void myBlockMove(void *source, void *destination, long count);
|
|
Boolean MyCompare(unsigned char *a, unsigned char *b);
|
|
|
|
|
|
#define gTime 0x020C
|
|
#define spaceK 0x00000200L
|
|
#define enterK 0x00100000L
|
|
#define returnK 0x10000000L
|
|
#define gCommandK 0x00008000L
|
|
|
|
#define bOK 1
|
|
|
|
#define bRevert 1
|
|
#define bList 2
|
|
#define bAllOff 3
|
|
#define bAllOn 4
|
|
|
|
|
|
|
|
#define kUseDisabledFolder false
|
|
#define kUseEnabledFolder true
|
|
|
|
#define okItem 1
|
|
#define cancelItem 2
|
|
|
|
// if you change these id's, change them also in ROM_EM.r
|
|
|
|
#define kEMID -15020
|
|
|
|
#define kEM_Dialog -15020
|
|
|
|
#define kNeedINITID -15020
|
|
#define kNeedNoINITID -15021
|
|
#define duplicateDlg -15021
|
|
|
|
|
|
#define kUpdateCode 1898
|
|
|
|
|
|
/*
|
|
This is the entry point of the ROM version of EM, we test for the Cmd-space bar down and if it is down
|
|
we initialize enough of the tollbox to make dialogs, then call the code that will
|
|
look like a cdev and cleanup. We also replace _OSDispatch tenmporarily, because the Process Manager
|
|
is not fully functinal yet.
|
|
*/
|
|
|
|
pascal void ROM_EM(void)
|
|
{
|
|
qdGlob myQuick;
|
|
GrafPort myPort;
|
|
KeyMap keys;
|
|
char copyright[] = {"\p© 1990-1992 Apple Computer, Inc. By Ricardo Batista"};
|
|
long oldOSDispatch;
|
|
long oldCurrentA5, oldA5;
|
|
|
|
GetKeys(&keys[0]);
|
|
if (((keys[1] & spaceK) == 0) || ((keys[1] & gCommandK) == 0)) // Cmd-space bar down ?
|
|
return;
|
|
oldCurrentA5 = *((long*) CurrentA5);
|
|
myQuick.tempA5 = (long) &myQuick.thePort;
|
|
oldA5 = SetA5((long) &myQuick.tempA5); // INIT 31 restores A5
|
|
InitGraf(&myQuick.thePort);
|
|
*(long*) CurrentA5 = (long) &myQuick.tempA5;
|
|
OpenPort(&myPort);
|
|
InitFonts();
|
|
InitWindows(); // calls InitMenus and DrawMenuBar
|
|
InitMenus();
|
|
TEInit();
|
|
InitDialogs(0L);
|
|
InitAllPacks();
|
|
InitCursor();
|
|
*((long*)DeskHook) = 0L;
|
|
*((long*)DragHook) = 0L;
|
|
*((long*)GhostWindow) = 0L;
|
|
TextFont(0);
|
|
TextSize(12);
|
|
DrawMenuBar();
|
|
oldOSDispatch = GetTrapAddress(0x8F);
|
|
SetTrapAddress((long) ROM_EM_OSDISPATCH, 0x8F);
|
|
ShowExtensions();
|
|
SetTrapAddress(oldOSDispatch, 0x8F);
|
|
ClosePort(&myPort);
|
|
*(long*)CurrentA5 = oldCurrentA5;
|
|
SetA5(oldA5);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
This function loads a dialog similar to the control panel, then calls our cdev-like code
|
|
as if we were the control panel. We close our dialog when the user
|
|
presses the closes our window. Errors are checked from the dialog, cdev code and exec of
|
|
the cdev code.
|
|
*/
|
|
|
|
void ShowExtensions()
|
|
{
|
|
|
|
DialogPtr cpDialog, theDialog;
|
|
DialogRecord dr;
|
|
long result;
|
|
EventRecord event;
|
|
GrafPtr savePort;
|
|
Boolean quit = false;
|
|
short item = 0;
|
|
Boolean dEvent;
|
|
short part;
|
|
WindowPtr w;
|
|
char theChar;
|
|
short mask = keyDownMask + mDownMask + updateMask + mUpMask + keyUpMask;
|
|
|
|
GetPort(&savePort);
|
|
cpDialog = GetNewDialog(kEM_Dialog, (Ptr) &dr, (WindowPtr) -1L);
|
|
if (!cpDialog)
|
|
return;
|
|
ShowWindow(cpDialog);
|
|
SetPort(cpDialog);
|
|
SetOrigin(89,0);
|
|
TextFont(1);
|
|
TextSize(9);
|
|
BeginUpdate(cpDialog);
|
|
DrawDialog(cpDialog);
|
|
EndUpdate(cpDialog);
|
|
result = EM_cdev(initDev, 0, 0, kEM_Dialog, &event, (cdev_dataH) 2L, cpDialog);
|
|
if (result == 1L)
|
|
SysBeep(1);
|
|
if (result > 3L) {
|
|
result = EM_cdev(updateDev, 0, 0, kEM_Dialog, &event, (cdev_dataH) result, cpDialog);
|
|
result = EM_cdev(activDev, 0, 0, kEM_Dialog, &event, (cdev_dataH) result, cpDialog);
|
|
while (!quit) {
|
|
SetPort(cpDialog);
|
|
InitCursor(); // avoid disk insert events
|
|
if (GetNextEvent(mask, &event)) {
|
|
if (event.what == updateEvt) {
|
|
BeginUpdate(cpDialog);
|
|
result = EM_cdev(updateDev, 0, 0, kEM_Dialog, &event, (cdev_dataH) result, cpDialog);
|
|
EndUpdate(cpDialog);
|
|
}
|
|
if (event.what == mouseDown) {
|
|
part = FindWindow(event.where, &w);
|
|
if (part == inGoAway) {
|
|
TrackGoAway(cpDialog, event.where);
|
|
quit = true;
|
|
}
|
|
if (part == inContent) {
|
|
dEvent = IsDialogEvent(&event);
|
|
if (DialogSelect(&event, &theDialog, &item)) {
|
|
result = EM_cdev(hitDev, item, 0, kEM_Dialog, &event, (cdev_dataH) result, cpDialog);
|
|
}
|
|
}
|
|
}
|
|
if (event.what == keyDown) {
|
|
theChar = event.message & charCodeMask;
|
|
item = theChar;
|
|
result = EM_cdev(keyEvtDev, item, 0, kEM_Dialog, &event, (cdev_dataH) result, cpDialog);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (result > 3L)
|
|
result = EM_cdev(closeDev, 0, 0, kEM_Dialog, &event, (cdev_dataH) result, cpDialog);
|
|
CloseDialog(cpDialog);
|
|
SetPort(savePort);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
This is the main entry point of the cdev code, the Control Panel calls us
|
|
giving us a message with the action to do. When initializing we have to create
|
|
a list and add to it all the files that could have INITs.
|
|
From then on we will get called with messages like hit or key pressed, on close
|
|
we dispose from our list.
|
|
*/
|
|
|
|
|
|
cdev_dataH EM_cdev(short message, short item, short numItems, short CPanelID,
|
|
EventRecord *theEvent, cdev_dataH cdevStorage, DialogPtr CPDialog)
|
|
{
|
|
cdev_dataH myData = 0L;
|
|
short type;
|
|
Handle H;
|
|
Rect box;
|
|
short myItem;
|
|
Point cell;
|
|
Rect bounds;
|
|
ListHandle list = 0L;
|
|
InitInfoH files = 0L;
|
|
KeyMap keys;
|
|
|
|
if (cdevStorage == 0L)
|
|
return(0L);
|
|
myData = 0L;
|
|
if (message == initDev) {
|
|
SetCursor(*(GetCursor(watchCursor)));
|
|
TextFont(1);
|
|
myData = (cdev_dataH) NewHandle(sizeof(cdev_data));
|
|
if (myData == 0L)
|
|
return((cdev_dataH) 1L); // bail out
|
|
HLock((Handle) myData);
|
|
files = (InitInfoH) NewHandle(0L);
|
|
if (files == 0L)
|
|
return((cdev_dataH) 1L); // bail out
|
|
(**myData).files = files;
|
|
GetDItem(CPDialog,numItems + bList,&type,&H,&box);
|
|
box.right -= 15;
|
|
SetRect(&bounds,0,0,1,0);
|
|
cell.h = cell.v = 0;
|
|
list = LNew(&box,&bounds,cell,0,CPDialog,false,false,false,true);
|
|
if (list == 0L)
|
|
return((cdev_dataH) 1L); // bail out
|
|
(**myData).list = list;
|
|
(**list).selFlags += lNoExtend + lUseSense;
|
|
ReadFiles(list,files);
|
|
SetResLoad(true);
|
|
InitCursor();
|
|
}
|
|
else {
|
|
myData = cdevStorage; // handle is still locked
|
|
files = (**myData).files;
|
|
list = (**myData).list;
|
|
}
|
|
if (message == hitDev) {
|
|
SetResLoad(true);
|
|
myItem = item - numItems;
|
|
if (myItem == bList) {
|
|
GlobalToLocal(&(theEvent->where));
|
|
LClick(theEvent->where, shiftKey, list);
|
|
cell = LLastClick(list);
|
|
}
|
|
if (myItem == bRevert) {
|
|
RevertInfo(list, files);
|
|
LUpdate(CPDialog->visRgn, list);
|
|
}
|
|
if (myItem == bAllOff) {
|
|
AllInfo(list, files, false);
|
|
LUpdate(CPDialog->visRgn, list);
|
|
}
|
|
if (myItem == bAllOn) {
|
|
AllInfo(list, files, true);
|
|
LUpdate(CPDialog->visRgn, list);
|
|
}
|
|
}
|
|
if (message == closeDev) {
|
|
SaveInfo(list, files);
|
|
DisposHandle((Handle) files);
|
|
LDispose(list);
|
|
HUnlock((Handle) myData);
|
|
DisposHandle((Handle) myData);
|
|
myData = 0L;
|
|
GetKeys(&keys[0]);
|
|
if ((keys[1] & gCommandK) != 0)
|
|
ShutDwnStart();
|
|
}
|
|
if (message == nulDev) {
|
|
}
|
|
if (message == updateDev) {
|
|
if (CPanelID)
|
|
SetPort(CPDialog); // redundant but gets rid of warning !!!
|
|
DrawDialog(CPDialog);
|
|
GetDItem(CPDialog,numItems + bList,&type,&H,&box);
|
|
InsetRect(&box,-1,-1);
|
|
FrameRect(&box);
|
|
LUpdate(CPDialog->visRgn, list);
|
|
}
|
|
if (message == activDev) {
|
|
LActivate(true, list);
|
|
}
|
|
if (message == deactivDev) {
|
|
LActivate(false, list);
|
|
}
|
|
if (message == macDev) {
|
|
myData = (cdev_dataH) 1L;
|
|
}
|
|
return(myData);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This routine determines whether a file should be added to our INIT list
|
|
// or not. If the file is capable of having an INIT then we try to find it,
|
|
// otherwise we display it. (i.e. a Finder extension)
|
|
|
|
|
|
Boolean HasINIT(CInfoPBRec *info)
|
|
{
|
|
short resFile;
|
|
register long type;
|
|
register short counter, typeCount;
|
|
long **InitTypesH, *initType;
|
|
Boolean isValid;
|
|
FSSpec file;
|
|
short err;
|
|
Boolean isFolder, wasAlias;
|
|
short len, ourFile;
|
|
|
|
type = info->hFileInfo.ioFlFndrInfo.fdType;
|
|
if (info->hFileInfo.ioFlFndrInfo.fdCreator == '7INI') // don't disable ourselves
|
|
return(false);
|
|
if (info->hFileInfo.ioFlFndrInfo.fdCreator == 'extE') // don't bother with EM Ext.
|
|
return(true);
|
|
InitTypesH = (long**) GetResource('iNIT',kNeedNoINITID);
|
|
if (!InitTypesH) {
|
|
*((short*) RomMapInsert) = mapTrue;
|
|
InitTypesH = (long**) GetResource('iNIT',kNeedNoINITID);
|
|
}
|
|
if (!InitTypesH)
|
|
return(false);
|
|
LoadResource((Handle) InitTypesH);
|
|
HLock((Handle) InitTypesH);
|
|
initType = *InitTypesH;
|
|
typeCount = GetHandleSize((Handle) InitTypesH) / 4L;
|
|
for (counter = 0; counter < typeCount; counter++) {
|
|
if (type == initType[counter])
|
|
return(true); // these files don't need an INIT, just show them
|
|
}
|
|
|
|
InitTypesH = (long**) GetResource('iNIT',kNeedINITID);
|
|
InitTypesH = (long**) GetResource('iNIT',kNeedINITID);
|
|
if (!InitTypesH) {
|
|
*((short*) RomMapInsert) = mapTrue;
|
|
InitTypesH = (long**) GetResource('iNIT',kNeedINITID);
|
|
}
|
|
if (!InitTypesH)
|
|
return(false);
|
|
LoadResource((Handle) InitTypesH);
|
|
HLock((Handle) InitTypesH);
|
|
initType = *InitTypesH;
|
|
typeCount = GetHandleSize((Handle) InitTypesH) / 4L;
|
|
isValid = false;
|
|
for (counter = 0; counter < typeCount; counter++) {
|
|
if (type == initType[counter]) {
|
|
isValid = true;
|
|
counter = typeCount + 1; // these files need an INIT
|
|
}
|
|
}
|
|
if (isValid == false)
|
|
return(false); // not a valid file
|
|
file.vRefNum = info->hFileInfo.ioVRefNum;
|
|
file.parID = info->hFileInfo.ioDirID;
|
|
len = info->hFileInfo.ioNamePtr[0];
|
|
myBlockMove(info->hFileInfo.ioNamePtr, file.name, (long) (len + 1L));
|
|
err = ResolveAliasFile(&file, true, &isFolder, &wasAlias);
|
|
if (err || isFolder)
|
|
return(false); // file not found, or volume not found
|
|
SetResLoad(false);
|
|
ourFile = CurResFile();
|
|
if (info->hFileInfo.ioFRefNum)
|
|
resFile = info->hFileInfo.ioFRefNum;
|
|
else
|
|
resFile = HOpenResFile(file.vRefNum, file.parID,(Str255) file.name, fsCurPerm);
|
|
if (resFile != -1) {
|
|
SetResLoad(false);
|
|
counter = Count1Resources('INIT');
|
|
if (info->hFileInfo.ioFRefNum == 0)
|
|
CloseResFile(resFile);
|
|
SetResLoad(true);
|
|
}
|
|
UseResFile(ourFile);
|
|
SetResLoad(true);
|
|
return(counter);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This is the main routine that can go out looking for new files, it calls the appropiate
|
|
// routines to fill in the list with the right file names.
|
|
|
|
void ReadFiles(ListHandle list,InitInfoH files)
|
|
{
|
|
long **FolderTypesH = 0L;
|
|
register short counter, total;
|
|
Point cell;
|
|
InitInfoPtr pt;
|
|
short len;
|
|
long enabledFolder, disabledFolder;
|
|
Handle H;
|
|
|
|
LDoDraw(false, list);
|
|
len = (**list).dataBounds.bottom;
|
|
if (len) {
|
|
LDelRow(len,0,list);
|
|
SetHandleSize((Handle) files, 0L);
|
|
}
|
|
FolderTypesH = (long**) GetResource('FTyp',kEMID);
|
|
if (!FolderTypesH) {
|
|
*((short*) RomMapInsert) = mapTrue;
|
|
FolderTypesH = (long**) GetResource('FTyp',kEMID);
|
|
}
|
|
if (FolderTypesH) {
|
|
LoadResource((Handle) FolderTypesH);
|
|
HLock((Handle) FolderTypesH);
|
|
Add7Folders();
|
|
total = GetHandleSize((Handle) FolderTypesH) / 4;
|
|
for (counter = 0; counter < total; counter += 2) {
|
|
enabledFolder = (*FolderTypesH)[counter];
|
|
disabledFolder = (*FolderTypesH)[counter + 1];
|
|
AddFolder(files, enabledFolder, disabledFolder,
|
|
kUseEnabledFolder);
|
|
AddFolder(files, enabledFolder, disabledFolder,
|
|
kUseDisabledFolder);
|
|
Sort(files, disabledFolder); // sort before inserting in list
|
|
}
|
|
H = GetResource('iNIT',kNeedNoINITID); // the code to scan a folder
|
|
if (H) { // loaded this resources and
|
|
LoadResource(H); // left them locked, so
|
|
HUnlock(H); // lets release them
|
|
ReleaseResource(H);
|
|
}
|
|
H = GetResource('iNIT',kNeedINITID);
|
|
if (H) {
|
|
LoadResource(H);
|
|
HUnlock(H);
|
|
ReleaseResource(H);
|
|
}
|
|
total = GetHandleSize((Handle) files) / sizeof(InitInfo);
|
|
LAddRow(total,0,list);
|
|
cell.h = cell.v = 0;
|
|
HLock((Handle) files);
|
|
pt = *files;
|
|
for (counter = 0; counter < total; counter++) {
|
|
len = pt->fileName[0];
|
|
LSetCell(&(pt->fileName[1]), len, cell, list);
|
|
if (pt->enabled)
|
|
LSetSelect(true,cell,list);
|
|
cell.v++;
|
|
pt++;
|
|
}
|
|
HUnlock((Handle) files);
|
|
}
|
|
LDoDraw(true, list);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This routine adds all the files in a given folder that have a type
|
|
// included in a list to the INIT list.
|
|
|
|
void AddFolder(InitInfoH files, long GoodFolder, long DisFolder, Boolean useEnabledF)
|
|
{
|
|
register short index;
|
|
short err, vRefNum;
|
|
long EnabledDirID, DisabledDirID;
|
|
CInfoPBRec info;
|
|
InitInfo anInit;
|
|
long offset;
|
|
long testDirID;
|
|
|
|
err = FindFolder(kOnSystemDisk, GoodFolder, kCreateFolder, &vRefNum, &EnabledDirID);
|
|
if (err)
|
|
return;
|
|
err = FindFolder(kOnSystemDisk, DisFolder, kCreateFolder, &vRefNum, &DisabledDirID);
|
|
if (err)
|
|
return;
|
|
if (useEnabledF)
|
|
testDirID = EnabledDirID;
|
|
else
|
|
testDirID = DisabledDirID;
|
|
index = 0;
|
|
info.hFileInfo.ioCompletion = 0L;
|
|
info.hFileInfo.ioNamePtr = (StringPtr) anInit.fileName;
|
|
info.hFileInfo.ioVRefNum = vRefNum;
|
|
anInit.vRefNum = vRefNum;
|
|
anInit.enabledDirID = EnabledDirID;
|
|
anInit.disabledDirID = DisabledDirID;
|
|
anInit.enabled = useEnabledF;
|
|
offset = GetHandleSize((Handle) files);
|
|
while (!err) {
|
|
index++;
|
|
info.hFileInfo.ioFDirIndex = index;
|
|
info.hFileInfo.ioDirID = testDirID;
|
|
info.hFileInfo.ioFlAttrib = 0;
|
|
info.hFileInfo.ioFlFndrInfo.fdFlags = 0;
|
|
info.hFileInfo.ioFRefNum = 0;
|
|
err = PBGetCatInfo(&info,false);
|
|
if (!err) {
|
|
if ((info.hFileInfo.ioFlAttrib & 16) == 0) {
|
|
anInit.creator = info.hFileInfo.ioFlFndrInfo.fdCreator;
|
|
info.hFileInfo.ioDirID = testDirID;
|
|
if (HasINIT(&info)) {
|
|
Munger((Handle) files,offset,(Ptr) 2L,0L,
|
|
(Ptr) &anInit,(long) sizeof(anInit));
|
|
offset += sizeof(anInit);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We make sure that we have our "(Disabled)" folders available, if not we
|
|
// setup the system so we that we can use them.
|
|
// To do that we load our 'fld#' resource and check every folder type and
|
|
// name we have specified. If the folder type is not there
|
|
// then we also need to add it into the system's fld#.
|
|
|
|
void Add7Folders(void)
|
|
{
|
|
short vRefNum;
|
|
long dirID;
|
|
Handle sysH, ourH;
|
|
long sysSize, ourSize, fldSize;
|
|
short err;
|
|
Ptr fldPtr;
|
|
register short counter;
|
|
long folderType;
|
|
Boolean changed = false;
|
|
|
|
sysH = GetResource('fld#', 0);
|
|
ourH = GetResource('fld#', kEMID);
|
|
if (ourH == 0L) {
|
|
*((short*) RomMapInsert) = mapTrue;
|
|
ourH = GetResource('fld#', kEMID);
|
|
}
|
|
if ((sysH == 0L) || (ourH == 0L))
|
|
return;
|
|
LoadResource(sysH);
|
|
LoadResource(ourH);
|
|
HLock(ourH);
|
|
fldSize = GetHandleSize(ourH); // we have to keep track of size
|
|
fldPtr = *ourH;
|
|
sysSize = GetHandleSize(sysH);
|
|
for (counter = 0; counter < fldSize; ) {
|
|
myBlockMove(fldPtr, &folderType, 4L); // get type
|
|
ourSize = 8 + fldPtr[7]; // add type, id, string len
|
|
if (ourSize % 2)
|
|
ourSize++; // string is padded !
|
|
err = FindFolder(kOnSystemDisk, folderType, kCreateFolder, &vRefNum, &dirID);
|
|
if (err) { // need to add our folder
|
|
Munger(sysH, sysSize, (Ptr) 2L, 0L, fldPtr, ourSize);
|
|
sysSize += ourSize;
|
|
changed = true;
|
|
}
|
|
fldPtr += (Ptr) ourSize; // add offset to next fld# entry
|
|
counter += ourSize; // add bytes scanned from fld# entry
|
|
}
|
|
if (changed) {
|
|
ChangedResource(sysH);
|
|
WriteResource(sysH);
|
|
UpdateResFile(0); // update the system
|
|
sysH = GetResource('fld#', 0);
|
|
}
|
|
ReleaseResource(ourH);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This is a very custom sorting rotuine, it takes the disabled folder id to match
|
|
// files agains it, it first finds the start of the folder type so that it can compare
|
|
// the disabled ones with the enabled ones and insert them at the right position.
|
|
// It also knows that it gets called after each folder type insert, so the end of the
|
|
// insert list is always the total number of records.
|
|
|
|
void Sort(InitInfoH files, long folder)
|
|
{
|
|
short startIndex, endIndex, sortStart;
|
|
register short counter, counter2;
|
|
register InitInfoPtr inits;
|
|
InitInfo tempInfo;
|
|
long dirID;
|
|
short vRefNum;
|
|
|
|
if (FindFolder(kOnSystemDisk, folder, kDontCreateFolder, &vRefNum, &dirID))
|
|
return;
|
|
HLock((Handle) files);
|
|
inits = *files;
|
|
endIndex = GetHandleSize((Handle) files) / sizeof(InitInfo);
|
|
for (counter = 0; counter < endIndex; counter++) { // find the start of this folder
|
|
if (inits[counter].disabledDirID == dirID) {
|
|
startIndex = counter;
|
|
break;
|
|
}
|
|
}
|
|
if (counter == endIndex) {
|
|
HUnlock((Handle) files); // there was only one new extension
|
|
return;
|
|
}
|
|
sortStart = startIndex;
|
|
while ((inits[sortStart].enabled) && (sortStart < endIndex))
|
|
sortStart++; // skip enabled
|
|
if (sortStart == endIndex) {
|
|
HUnlock((Handle) files); // there was only enabled extensions
|
|
return;
|
|
}
|
|
while (sortStart < endIndex) {
|
|
for (counter = startIndex; counter < endIndex; counter++) {
|
|
if (sortStart == counter) { // checking against ourselves ?
|
|
startIndex++;
|
|
sortStart++; // we are the end of it.
|
|
break;
|
|
}
|
|
else {
|
|
if (MyCompare((unsigned char*) inits[sortStart].fileName,
|
|
(unsigned char*) inits[counter].fileName)) { // a < b
|
|
tempInfo = inits[sortStart];
|
|
for (counter2 = sortStart; counter2 > counter; counter2--) {
|
|
inits[counter2] = inits[counter2 - 1];
|
|
}
|
|
inits[counter] = tempInfo;
|
|
startIndex++; // skip at least one more from enabled, since it was sorted already
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
sortStart++; // one less from the disabled folder
|
|
}
|
|
HUnlock((Handle) files);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// This routine makes permanent the changes the user has made, we look at the
|
|
// "enabled" flag and compare this with the current higlight state, that way we
|
|
// can tell if the file needs to be moved from one folder to the other.
|
|
|
|
void SaveInfo(ListHandle list,InitInfoH files)
|
|
{
|
|
register short counter, total, err;
|
|
Point cell;
|
|
CMovePBRec info;
|
|
Boolean toggle;
|
|
InitInfo *initPtr;
|
|
|
|
total = GetHandleSize((Handle) files) / sizeof(InitInfo);
|
|
HLock((Handle) files);
|
|
cell.h = cell.v = 0;
|
|
for (counter = 0; counter < total; counter++) {
|
|
cell.v = counter;
|
|
toggle = false;
|
|
if (LGetSelect(false,&cell,list)) {
|
|
if (((*files)[counter]).enabled == false) {
|
|
toggle = true;
|
|
((*files)[counter]).enabled = true;
|
|
}
|
|
}
|
|
else {
|
|
if (((*files)[counter]).enabled) {
|
|
toggle = true;
|
|
((*files)[counter]).enabled = false;
|
|
}
|
|
}
|
|
if (toggle) {
|
|
initPtr = &((*files)[counter]);
|
|
info.ioCompletion = 0L;
|
|
info.ioNamePtr = initPtr->fileName;
|
|
info.ioNewName = 0L;
|
|
info.ioVRefNum = initPtr->vRefNum;
|
|
if (initPtr->enabled) {
|
|
info.ioDirID = initPtr->disabledDirID;
|
|
info.ioNewDirID = initPtr->enabledDirID;
|
|
}
|
|
else {
|
|
info.ioDirID = initPtr->enabledDirID;
|
|
info.ioNewDirID = initPtr->disabledDirID;
|
|
}
|
|
err = PBCatMove(&info,false);
|
|
if (err)
|
|
ErrDlg(duplicateDlg);
|
|
}
|
|
}
|
|
HUnlock((Handle) files);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// This function reverts the higlight state of each file to what the "enabled" flag
|
|
// was, since that flag indicates to us what folder the file comes from.
|
|
|
|
void RevertInfo(ListHandle list,InitInfoH files)
|
|
{
|
|
register short counter, total;
|
|
Point cell;
|
|
|
|
LDoDraw(false, list);
|
|
total = GetHandleSize((Handle) files) / sizeof(InitInfo);
|
|
HLock((Handle) files);
|
|
cell.h = cell.v = 0;
|
|
for (counter = 0; counter < total; counter++) {
|
|
cell.v = counter;
|
|
if (((*files)[counter]).enabled)
|
|
LSetSelect(true,cell,list);
|
|
else
|
|
LSetSelect(false,cell,list);
|
|
}
|
|
HUnlock((Handle) files);
|
|
LDoDraw(true, list);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// This function set all of the files either on or off
|
|
|
|
void AllInfo(ListHandle list,InitInfoH files, Boolean on)
|
|
{
|
|
register short counter, total;
|
|
Point cell;
|
|
|
|
LDoDraw(false, list);
|
|
total = GetHandleSize((Handle) files) / sizeof(InitInfo);
|
|
cell.h = cell.v = 0;
|
|
for (counter = 0; counter < total; counter++) {
|
|
cell.v = counter;
|
|
LSetSelect(on, cell, list);
|
|
}
|
|
LDoDraw(true, list);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
This routine shows a dialog box with the id given to it and waits for the
|
|
user to click the OK button. Mainly to show error dialogs.
|
|
*/
|
|
|
|
|
|
void ErrDlg(id)
|
|
short id;
|
|
{
|
|
GrafPtr savePort;
|
|
DialogPtr aDialog;
|
|
DialogRecord d;
|
|
short item;
|
|
Handle H;
|
|
Rect box;
|
|
|
|
GetPort(&savePort);
|
|
aDialog = GetNewDialog(id, &d, (WindowPtr) -1L);
|
|
if (!aDialog) {
|
|
*((short*) RomMapInsert) = mapTrue;
|
|
aDialog = GetNewDialog(id, &d, (WindowPtr) -1L);
|
|
}
|
|
if (!aDialog) {
|
|
SysBeep(1);
|
|
return;
|
|
}
|
|
SetPort(aDialog);
|
|
|
|
item = kUpdateCode;
|
|
InitCursor();
|
|
while (item != okItem) {
|
|
if (item == kUpdateCode) {
|
|
BeginUpdate(aDialog);
|
|
GetDItem(aDialog,okItem,&item,&H,&box);
|
|
InsetRect(&box,-4,-4);
|
|
DrawDialog(aDialog);
|
|
PenSize(3,3);
|
|
FrameRoundRect(&box,16,16);
|
|
EndUpdate(aDialog);
|
|
}
|
|
ModalDialog(UpdateFilter, &item);
|
|
}
|
|
CloseDialog(aDialog);
|
|
SetPort(savePort);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pascal Boolean UpdateFilter(DialogPtr theDialog,EventRecord *theEvent,short *item)
|
|
{
|
|
char theChar;
|
|
long delayed;
|
|
short type;
|
|
Rect box;
|
|
Handle H;
|
|
|
|
if (theEvent->what == updateEvt) {
|
|
*item = kUpdateCode; /* A special code so I can update screen */
|
|
return(true);
|
|
}
|
|
if ((theEvent->what == keyDown) || (theEvent->what == autoKey)) {
|
|
theChar = theEvent->message & charCodeMask;
|
|
if ((theChar == 13) || (theChar == 3)) {
|
|
*item = okItem; // or default item, one anyway
|
|
GetDItem(theDialog, okItem, &type, &H, &box);
|
|
HiliteControl((ControlHandle) H, 1);
|
|
Delay(8L, &delayed);
|
|
HiliteControl((ControlHandle) H, 0);
|
|
return(true);
|
|
}
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// faster than calling the real blockmove when the data you usually copy
|
|
// is small
|
|
|
|
void myBlockMove(void *source, void *destination, long count)
|
|
{
|
|
register Ptr s, d;
|
|
|
|
s = source;
|
|
d = destination;
|
|
while (count) {
|
|
*d++ = *s++;
|
|
count--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This function returns true if the first string has precedence over the second one
|
|
// otherwise it returns false. Not a very good routine when it comes to International
|
|
|
|
Boolean MyCompare(unsigned char *a, unsigned char *b)
|
|
{
|
|
register short len, counter = 1;
|
|
register char theCharA, theCharB;
|
|
|
|
len = a[0];
|
|
if (len > b[0])
|
|
len = b[0]; // compare up to the smallest common length
|
|
while (len) {
|
|
theCharA = a[counter];
|
|
theCharB = b[counter];
|
|
if ((theCharA >= 'a') && (theCharA <= 'z'))
|
|
theCharA -= 32; // make it lowercase
|
|
if ((theCharB >= 'a') && (theCharB <= 'z'))
|
|
theCharB -= 32; // make it lowercase
|
|
if (theCharA < theCharB)
|
|
return(true);
|
|
if (theCharA > theCharB)
|
|
return(false);
|
|
counter++;
|
|
len--;
|
|
}
|
|
if (a[0] < b[0])
|
|
return(true);
|
|
return(false); // equal strings, or b is longer string
|
|
}
|
|
|