Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
G4Prefs.c
/* |
File: G4Prefs.c |
Contains: xxx put contents here xxx |
Version: xxx put version here xxx |
Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
File Ownership: |
DRI: xxx put dri here xxx |
Other Contact: xxx put other contact here xxx |
Technology: xxx put technology here xxx |
Writers: |
(sjb) Steve Bollinger |
Change History (most recent first): |
<2> 7/1/98 sjb Update to CWPro 2 |
*/ |
//============================================================================ |
//---------------------------------------------------------------------------- |
// Prefs.c |
//---------------------------------------------------------------------------- |
//============================================================================ |
// This is a slick little file that I re-use and re-use. I wrote it toÉ |
// seemlessly handle System 6 or System 7 with but a single call. You needÉ |
// to define your own "prefs" struct, but these routines will read and writeÉ |
// it to the System folder. |
#include "G4Externs.h" |
#include <Folders.h> // Needed for creating a folder. |
#include <Gestalt.h> // Needed for the Gestalt() call. |
#include <Script.h> // I can't remember why I needed this. |
#include <ToolUtils.h> |
#include <TextUtils.h> |
#define kPrefCreatorType 'zade' // Change this to reflect your apps creator. |
#define kPrefFileType 'zadP' // Change this to reflect your prefs type. |
#define kPrefFileName "\pGlypha Prefs" // Change this to reflect the name for your prefs. |
#define kDefaultPrefFName "\pPreferences" // Name of prefs folder (System 6 only). |
#define kPrefsStringsID 160 // For easy localization. |
#define kPrefsFNameIndex 1 // This one works with the previous constant. |
Boolean CanUseFindFolder (void); |
Boolean GetPrefsFPath (long *, short *); |
Boolean CreatePrefsFolder (short *); |
Boolean GetPrefsFPath6 (short *); |
Boolean WritePrefs (long *, short *, prefsInfo *); |
Boolean WritePrefs6 (short *, prefsInfo *); |
OSErr ReadPrefs (long *, short *, prefsInfo *); |
OSErr ReadPrefs6 (short *, prefsInfo *); |
Boolean DeletePrefs (long *, short *); |
Boolean DeletePrefs6 (short *); |
//============================================================== Functions |
//-------------------------------------------------------------- CanUseFindFolder |
// Returns TRUE if we can use the FindFolder() call (a System 7 nicety). |
Boolean CanUseFindFolder (void) |
{ |
OSErr theErr; |
long theFeature; |
if (!DoWeHaveGestalt()) // Darn, have to check for Gestalt() first. |
return(FALSE); // If no Gestalt(), probably don't have FindFolder(). |
theErr = Gestalt(gestaltFindFolderAttr, &theFeature); |
if (theErr != noErr) // Use selector for FindFolder() attribute. |
return(FALSE); |
// Now do a bit test specifically for FindFolder(). |
if (!BitTst(&theFeature, 31 - gestaltFindFolderPresent)) |
return(FALSE); |
else |
return(TRUE); |
} |
//-------------------------------------------------------------- GetPrefsFPath |
// This function gets the file path to the Preferences folder (for System 7). |
// It is called only if we can use FindFolder() (see previous function). |
Boolean GetPrefsFPath (long *prefDirID, short *systemVolRef) |
{ |
OSErr theErr; |
// Here's the wiley FindFolder() call. |
theErr = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, |
systemVolRef, prefDirID); // It returns to us the directory and volume ref.É |
if (theErr != noErr) // Assuming it worked at all! |
return(FALSE); |
return(TRUE); |
} |
//-------------------------------------------------------------- CreatePrefsFolder |
// This function won't be necessary for System 7, for System 6 though, it createsÉ |
// a folder ("Preferences") in the System folder and returns whether or not it worked. |
Boolean CreatePrefsFolder (short *systemVolRef) |
{ |
HFileParam fileParamBlock; |
Str255 folderName; |
OSErr theErr; |
// Here's our localization. Rather thanÉ |
// hard-code the name "Preferences" in the codeÉ |
// we pull up the text from a string resource. |
GetIndString(folderName, kPrefsStringsID, kPrefsFNameIndex); |
// Set up a file parameter block. |
fileParamBlock.ioVRefNum = *systemVolRef; |
fileParamBlock.ioDirID = 0; |
fileParamBlock.ioNamePtr = folderName; |
fileParamBlock.ioCompletion = 0L; |
// And create a directory (folder). |
theErr = PBDirCreate((HParmBlkPtr)&fileParamBlock, FALSE); |
if (theErr != noErr) // See that it worked. |
{ |
RedAlert("\pPrefs Creation Error"); |
return(FALSE); |
} |
return(TRUE); |
} |
//-------------------------------------------------------------- GetPrefsFPath6 |
// If ever there was a case to drop support for System 6 (and require System 7),É |
// this is it. Look at how insidious handling System 6 files can be. The followingÉ |
// function is the "System 6 pedigree" of the above GetPrefsFPath() function. NoteÉ |
// that the GetPrefsFPath() function was ONE CALL! TWO LINES OF CODE! The belowÉ |
// function is like a page or so. Anyway, this function is called if Glypha isÉ |
// running under System 6 and essentially returns a volume reference pointing toÉ |
// the preferences folder. |
Boolean GetPrefsFPath6 (short *systemVolRef) |
{ |
Str255 folderName, whoCares; |
SysEnvRec thisWorld; |
CInfoPBRec catalogInfoPB; |
DirInfo *directoryInfo = (DirInfo *) &catalogInfoPB; |
HFileInfo *fileInfo = (HFileInfo *) &catalogInfoPB; |
WDPBRec workingDirPB; |
long prefDirID; |
OSErr theErr; |
// Yokelization. |
GetIndString(folderName, kPrefsStringsID, kPrefsFNameIndex); |
// SysEnvirons() for System folder volRef. |
theErr = SysEnvirons(2, &thisWorld); |
if (theErr != noErr) |
return(FALSE); |
// Okay, here's the volume reference. |
*systemVolRef = thisWorld.sysVRefNum; |
fileInfo->ioVRefNum = *systemVolRef; // Set up another parameter block. |
fileInfo->ioDirID = 0; // Ignored. |
fileInfo->ioFDirIndex = 0; // Irrelevant. |
fileInfo->ioNamePtr = folderName; // Directory we're looking for. |
fileInfo->ioCompletion = 0L; |
theErr = PBGetCatInfo(&catalogInfoPB, FALSE); |
if (theErr != noErr) // Did we fail to find Prefs folder? |
{ |
if (theErr != fnfErr) // If it WASN'T a file not found errorÉ |
{ // then something more sinister is afoot. |
RedAlert("\pPrefs Filepath Error"); |
} // Otherwise, need to create prefs folder. |
if (!CreatePrefsFolder(systemVolRef)) |
return(FALSE); |
// Again - can we find the prefs folder? |
directoryInfo->ioVRefNum = *systemVolRef; |
directoryInfo->ioFDirIndex = 0; |
directoryInfo->ioNamePtr = folderName; |
theErr = PBGetCatInfo(&catalogInfoPB, FALSE); |
if (theErr != noErr) |
{ |
RedAlert("\pPrefs GetCatInfo() Error"); |
return(FALSE); |
} |
} |
prefDirID = directoryInfo->ioDrDirID; // Alright, the dir. ID for prefs folder. |
workingDirPB.ioNamePtr = whoCares; // Now convert working dir. into a "real"É |
workingDirPB.ioVRefNum = *systemVolRef; // dir. ID so we can get volume number. |
workingDirPB.ioWDIndex = 0; |
workingDirPB.ioWDProcID = 0; |
workingDirPB.ioWDVRefNum = 0; |
workingDirPB.ioCompletion = 0L; |
theErr = PBGetWDInfo(&workingDirPB, FALSE); |
if (theErr != noErr) |
{ |
RedAlert("\pPrefs PBGetWDInfo() Error"); |
} |
// The volume where directory is located. |
*systemVolRef = workingDirPB.ioWDVRefNum; |
workingDirPB.ioNamePtr = whoCares; |
workingDirPB.ioWDDirID = prefDirID; // Okay, finally, with a directory ID, É |
workingDirPB.ioVRefNum = *systemVolRef; // and a "hard" volume numberÉ |
workingDirPB.ioWDProcID = 0; // É |
workingDirPB.ioCompletion = 0L; // É |
theErr = PBOpenWD(&workingDirPB, FALSE); // we can create a working directoryÉ |
if (theErr != noErr) // control block with which to accessÉ |
{ // files in the prefs folder. |
RedAlert("\pPrefs PBOpenWD() Error"); |
} |
*systemVolRef = workingDirPB.ioVRefNum; |
return(TRUE); |
} |
//-------------------------------------------------------------- WritePrefs |
// This is the System 7 version that handles all the above functions when youÉ |
// want to write out the preferences file. It is called by SavePrefs() belowÉ |
// if we're running under System 7. It creates an FSSpec record to holdÉ |
// information about where the preferences file is located, creates Glypha'sÉ |
// preferences if they are not found, opens the prefences file, writes outÉ |
// the preferences, and the closes the prefs. Bam, bam, bam. |
Boolean WritePrefs (long *prefDirID, short *systemVolRef, prefsInfo *thePrefs) |
{ |
OSErr theErr; |
short fileRefNum; |
long byteCount; |
FSSpec theSpecs; |
Str255 fileName = kPrefFileName; |
// Create FSSpec record from volume ref and dir ID. |
theErr = FSMakeFSSpec(*systemVolRef, *prefDirID, fileName, &theSpecs); |
if (theErr != noErr) // See if it failed. |
{ // An fnfErr means file not found error (no prefs). |
if (theErr != fnfErr) // If that weren't the problem, we're cooked. |
RedAlert("\pPrefs FSMakeFSSpec() Error"); |
// If it was an fnfErr, create the prefs. |
theErr = FSpCreate(&theSpecs, kPrefCreatorType, kPrefFileType, smSystemScript); |
if (theErr != noErr) // If we fail to create the prefs, bail. |
RedAlert("\pPrefs FSpCreate() Error"); |
} // Okay, we either found or made a pref file, open it. |
theErr = FSpOpenDF(&theSpecs, fsRdWrPerm, &fileRefNum); |
if (theErr != noErr) // As per usual, if we fail, bail. |
RedAlert("\pPrefs FSpOpenDF() Error"); |
byteCount = sizeof(*thePrefs); // Get number of bytes to write (your prefs struct). |
// And, write out the preferences. |
theErr = FSWrite(fileRefNum, &byteCount, thePrefs); |
if (theErr != noErr) // Say no more. |
RedAlert("\pPrefs FSWrite() Error"); |
theErr = FSClose(fileRefNum); // Close the prefs file. |
if (theErr != noErr) // Tic, tic. |
RedAlert("\pPrefs FSClose() Error"); |
return(TRUE); |
} |
//-------------------------------------------------------------- WritePrefs6 |
// This is the System 6 equivalent of the above function. It handles prefsÉ |
// opening, writing and closing for System 6. |
Boolean WritePrefs6 (short *systemVolRef, prefsInfo *thePrefs) |
{ |
OSErr theErr; |
short fileRefNum; |
long byteCount; |
Str255 fileName = kPrefFileName; |
// Attempt to open prefs file. |
theErr = FSOpen(fileName, *systemVolRef, &fileRefNum); |
if (theErr != noErr) // If it failed, maybe the prefs don't exist. |
{ // An fnfErr means file not found. |
if (theErr != fnfErr) // See if in fact that WASN'T the reason. |
RedAlert("\pPrefs FSOpen() Error"); |
// If fnfErr WAS the problem, create the prefs. |
theErr = Create(fileName, *systemVolRef, kPrefCreatorType, kPrefFileType); |
if (theErr != noErr) |
RedAlert("\pPrefs Create() Error"); |
// Open the prefs file. |
theErr = FSOpen(fileName, *systemVolRef, &fileRefNum); |
if (theErr != noErr) |
RedAlert("\pPrefs FSOpen() Error"); |
} |
byteCount = sizeof(*thePrefs); // Get number of bytes to write out. |
// Write the prefs out. |
theErr = FSWrite(fileRefNum, &byteCount, thePrefs); |
if (theErr != noErr) |
RedAlert("\pPrefs FSWrite() Error"); |
// And close the prefs file. |
theErr = FSClose(fileRefNum); |
if (theErr != noErr) |
RedAlert("\pPrefs FSClose() Error"); |
return(TRUE); |
} |
//-------------------------------------------------------------- SavePrefs |
// This is the single function called externally to save the preferences. |
// You pass it a pointer to your preferences struct and a version number. |
// One of the fields in your preferences struct should be a version numberÉ |
// (short prefVersion). This function determines if we're on System 6 or 7É |
// and then calls the appropriate routines. It returns TRUE if all went wellÉ |
// or FALSE if any step failed. |
Boolean SavePrefs (prefsInfo *thePrefs, short versionNow) |
{ |
long prefDirID; |
short systemVolRef; |
Boolean canUseFSSpecs; |
thePrefs->prefVersion = versionNow; // Set prefVersion to versionNow. |
canUseFSSpecs = CanUseFindFolder(); // See if we can use FindFolder(). |
if (canUseFSSpecs) // If so (System 7) take this route. |
{ // Get a path to Preferences folder. |
if (!GetPrefsFPath(&prefDirID, &systemVolRef)) |
return(FALSE); |
} |
else // Here's the System 6 version. |
{ |
if (!GetPrefsFPath6(&systemVolRef)) |
return(FALSE); |
} |
if (canUseFSSpecs) // Write out the preferences. |
{ |
if (!WritePrefs(&prefDirID, &systemVolRef, thePrefs)) |
return(FALSE); |
} |
else |
{ |
if (!WritePrefs6(&systemVolRef, thePrefs)) |
return(FALSE); |
} |
return(TRUE); |
} |
//-------------------------------------------------------------- ReadPrefs |
// This is the System 7 version for reading in the preferences. It handlesÉ |
// opening the prefs, reading in the data to your prefs struct and closingÉ |
// the file. |
OSErr ReadPrefs (long *prefDirID, short *systemVolRef, prefsInfo *thePrefs) |
{ |
OSErr theErr; |
short fileRefNum; |
long byteCount; |
FSSpec theSpecs; |
Str255 fileName = kPrefFileName; |
// Get an FSSpec record to the prefs file. |
theErr = FSMakeFSSpec(*systemVolRef, *prefDirID, fileName, &theSpecs); |
if (theErr != noErr) |
{ |
if (theErr == fnfErr) // If it doesn't exist, return - we'll use defaults. |
return(theErr); |
else // If some other file error occured, bail. |
RedAlert("\pPrefs FSMakeFSSpec() Error"); |
} |
// Open the prefs file. |
theErr = FSpOpenDF(&theSpecs, fsRdWrPerm, &fileRefNum); |
if (theErr != noErr) |
RedAlert("\pPrefs FSpOpenDF() Error"); |
byteCount = sizeof(*thePrefs); // Determine the number of bytes to read in. |
// Read 'em into your prefs struct. |
theErr = FSRead(fileRefNum, &byteCount, thePrefs); |
if (theErr != noErr) // If there was an error reading the fileÉ |
{ // close the file and we'll revert to defaults. |
if (theErr == eofErr) |
theErr = FSClose(fileRefNum); |
else // If closing failed, bail. |
RedAlert("\pPrefs FSRead() Error"); |
return(theErr); |
} |
theErr = FSClose(fileRefNum); // Close the prefs file. |
if (theErr != noErr) |
RedAlert("\pPrefs FSClose() Error"); |
return(theErr); |
} |
//-------------------------------------------------------------- ReadPrefs6 |
// This is the System 6 version of the above function. It's basically the same,É |
// but doesn't have the luxury of using FSSpec records. |
OSErr ReadPrefs6 (short *systemVolRef, prefsInfo *thePrefs) |
{ |
OSErr theErr; |
short fileRefNum; |
long byteCount; |
Str255 fileName = kPrefFileName; |
// Attempt to open the prefs file. |
theErr = FSOpen(fileName, *systemVolRef, &fileRefNum); |
if (theErr != noErr) // Did opening the file fail? |
{ |
if (theErr == fnfErr) // It did - did it fail because it doesn't exist? |
return(theErr); // Okay, then we'll revert to default settings. |
else // Otherwise, we have a more serious problem. |
RedAlert("\pPrefs FSOpen() Error"); |
} |
// Get number of bytes to read in. |
byteCount = sizeof(*thePrefs); |
// Read in the stream of data into prefs struct. |
theErr = FSRead(fileRefNum, &byteCount, thePrefs); |
if (theErr != noErr) // Did the read fail? |
{ // Maybe we're reading too much data (new prefs vers). |
if (theErr == eofErr) // That's okay, we'll use defaults for now. |
theErr = FSClose(fileRefNum); |
else |
RedAlert("\pPrefs FSRead() Error"); |
return(theErr); |
} |
// Close the prefs file. |
theErr = FSClose(fileRefNum); |
if (theErr != noErr) |
RedAlert("\pPrefs FSClose() Error"); |
return(theErr); |
} |
//-------------------------------------------------------------- DeletePrefs |
// It can happen that you introduce a game with only a few preference settingsÉ |
// but then later update your game and end up having to add additional settingsÉ |
// to be stored in your games preferences. In this case, the size of the oldÉ |
// prefs won't match the size of the new. Or even if the size is the same, youÉ |
// may have re-ordered the prefs and attempting to load the old prefs will resultÉ |
// in garbage. It is for this reason that I use the "versionNeed" variable andÉ |
// the "prefVersion" field in the prefs struct. In such a case, the below functionÉ |
// will be called to delte the old prefs. When the prefs are then written out, aÉ |
// new pref file will be created. This particular function is the System 7 versionÉ |
// for deleting the old preferences. |
Boolean DeletePrefs (long *dirID, short *volRef) |
{ |
FSSpec theSpecs; |
Str255 fileName = kPrefFileName; |
OSErr theErr; |
// Create an FSSec record. |
theErr = FSMakeFSSpec(*volRef, *dirID, fileName, &theSpecs); |
if (theErr != noErr) // Test to see if it worked. |
return(FALSE); |
else // If it workedÉ |
theErr = FSpDelete(&theSpecs); // delete the file. |
if (theErr != noErr) |
return(FALSE); |
return(TRUE); |
} |
//-------------------------------------------------------------- DeletePrefs6 |
// This is the System 6 version for deleting a preferences file (see above function). |
Boolean DeletePrefs6 (short *volRef) |
{ |
Str255 fileName = kPrefFileName; |
OSErr theErr; |
theErr = FSDelete(fileName, *volRef); // Delete the prefs file. |
if (theErr != noErr) |
return(FALSE); |
return(TRUE); |
} |
//-------------------------------------------------------------- LoadPrefs |
// Here is the single call for loading in preferences. It handles all theÉ |
// above function onvolved with opening and reading in preferences. ItÉ |
// determines whether we are on System 6 or 7 (FSSpecs) and makes the rightÉ |
// calls. |
Boolean LoadPrefs (prefsInfo *thePrefs, short versionNeed) |
{ |
long prefDirID; |
OSErr theErr; |
short systemVolRef; |
Boolean canUseFSSpecs, noProblems; |
canUseFSSpecs = CanUseFindFolder(); // See if we can use FSSpecs (System 7). |
if (canUseFSSpecs) |
{ // Get a path to the prefs file. |
noProblems = GetPrefsFPath(&prefDirID, &systemVolRef); |
if (!noProblems) |
return(FALSE); |
} |
else |
{ // Gets path to prefs file (System 6). |
noProblems = GetPrefsFPath6(&systemVolRef); |
if (!noProblems) |
return(FALSE); |
} |
if (canUseFSSpecs) |
{ // Attempt to read prefs. |
theErr = ReadPrefs(&prefDirID, &systemVolRef, thePrefs); |
if (theErr == eofErr) // Fail the read? Maybe an old prefs version. |
{ // Delete it - we'll create a new one later. |
noProblems = DeletePrefs(&prefDirID, &systemVolRef); |
return(FALSE); // Meanwhile, we'll use defaults. |
} |
else if (theErr != noErr) |
return(FALSE); |
} |
else |
{ // Attempt to read prefs (System 6). |
theErr = ReadPrefs6(&systemVolRef, thePrefs); |
if (theErr == eofErr) // Fail the read? Maybe an old prefs version. |
{ // Delete it - we'll create a new one later. |
noProblems = DeletePrefs6(&systemVolRef); |
return(FALSE); // Meanwhile, we'll use defaults. |
} |
else if (theErr != noErr) |
return(FALSE); |
} |
// Okay, maybe the read worked, but we stillÉ |
// need to check the version number to seeÉ |
// if it's current. |
if (thePrefs->prefVersion != versionNeed) |
{ // We'll delete the file if old version. |
if (canUseFSSpecs) |
{ |
noProblems = DeletePrefs(&prefDirID, &systemVolRef); |
return(FALSE); |
} |
else |
{ |
noProblems = DeletePrefs6(&systemVolRef); |
return(FALSE); |
} |
} |
return(TRUE); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14