uuUndo/DSUserProcs.c
2015-02-06 00:56:41 -08:00

1 line
29 KiB
C
Raw Blame History

/******************************************************************************
**
** Project Name: DropShell
** File Name: DSUserProcs.c
**
** Description: Specific AppleEvent handlers used by the DropBox
**
*******************************************************************************
** A U T H O R I D E N T I T Y
*******************************************************************************
**
** Initials Name
** -------- -----------------------------------------------
** LDR Leonard Rosenthol
** MTC Marshall Clow
** SCS Stephan Somogyi
**
*******************************************************************************
** R E V I S I O N H I S T O R Y
*******************************************************************************
**
** Date Time Author Description
** -------- ----- ------ ---------------------------------------------
** 01/25/92 LDR Removed the use of const on the userDataHandle
** 12/09/91 LDR Added the new SelectFile userProc
** Added the new Install & DisposeUserGlobals procs
** Modified PostFlight to only autoquit on odoc, not pdoc
** 11/24/91 LDR Added the userProcs for pdoc handler
** Cleaned up the placement of braces
** Added the passing of a userDataHandle
** 10/29/91 SCS Changes for THINK C 5
** 10/28/91 LDR Officially renamed DropShell (from QuickShell)
** Added a bunch of comments for clarification
** 10/06/91 00:02 MTC Converted to MPW C
** 04/09/91 00:02 LDR Added to Projector
**
******************************************************************************/
#include "DSGlobals.h"
#include "DSUserProcs.h"
#include "DSDialogs.h"
#include "DSUtilsASG.h"
#include <Folders.h>
#include <GestaltEqu.h>
#include <ImageCompression.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
//==================================================================================================================================
// Globals
//==================================================================================================================================
typedef struct odocQueue {
struct odocQueue *next;
FSSpec spec;
Handle data;
} odocQueue, *odocQueuePtr;
enum {
cacheData = 0x10,
dontCache = 0x20
};
static Boolean gAborted = false;
static char *gInputBuffer = nil, *gOutputBuffer = nil;
static char *gInputBufferBase = nil, *gOutputBufferBase = nil;
static char *gInputBufferPtr = nil, *gOutputBufferPtr = nil;
static ParamBlockRec gInputPB1, gInputPB2;
static ParamBlockRec gOutputPB1, gOutputPB2;
static HParamBlockRec gCloseOutputPB;
static HParamBlockRec gOpenOutputPB;
static HParamBlockRec gDeleteInputPB;
static short gInputRefNum = 0, gOutputRefNum = 0;
static Size gInputBufferLeft = 0, gOutputBufferCount = 0;
static Size gTotalSize = 0, gBytesRead = 0, gLinesProcessed = 0;
static Boolean gLastInputBuffer = false, gFoundEndCode = false;
static odocQueuePtr godocQueue = nil;
static IOCompletionUPP gGenericCompletion = nil;
Boolean gProcessing = false, gHasCQD = false;
enum {
kInputBufferSize = 32L * 1024L,
kOutputBufferSize = 32L * 1024L,
kExtensionMapType = 'E2Ty',
kExtensionMapID = 0
};
static OSErr OpenInputFile(FSSpecPtr theSpec);
static OSErr FillInputBuffer(void);
static OSErr CloseInputFile(FSSpecPtr theSpec);
static char *GetNextInputLine(Size *length, Boolean *badUU);
static char *GetNextUUInputLine(void);
static OSErr OpenOutputFile(FSSpecPtr inSpec, FSSpecPtr outSpec, char *outName);
static OSErr CreateOutputFile(FSSpecPtr outSpec, char *outName, OSType creator, OSType type);
static void MapOutputExtension(char *outname, OSType *creator, OSType *type);
static OSErr FlushOutputBuffer(void);
static OSErr CloseOutputFile(FSSpecPtr theSpec);
static OSErr DecodeUULine(char *line);
static void AddToQueue(FSSpec *theSpec, Handle userData);
static void ProcessQueue(void);
static void DisableMenus(void);
static void EnableMenus(void);
#if defined(powerc) || defined(__powerc)
static pascal void GenericCompletion(ParmBlkPtr paramBlock);
#else
static pascal void GenericCompletion(void);
#endif
//==================================================================================================================================
// This routine is called during init time.
//
// It allows you to install more AEVT Handlers beyond the standard four
//==================================================================================================================================
#pragma segment Main
pascal void InstallOtherEvents(void)
{
}
//==================================================================================================================================
// This routine is called when an OAPP event is received.
//
// Currently, all it does is set the gOApped flag, so you know that
// you were called initally with no docs, and therefore you shouldn't
// quit when done processing any following odocs.
//==================================================================================================================================
#pragma segment Main
pascal void OpenApp(void)
{
gOApped = true;
}
//==================================================================================================================================
// This routine is called when an QUIT event is received.
// We simply set the global done flag so that the main event loop can
// gracefully exit. We DO NOT call ExitToShell for two reasons:
// 1) It is a pretty ugly thing to do, but more importantly
// 2) The Apple event manager will get REAL upset!
//==================================================================================================================================
#pragma segment Main
pascal void QuitApp(void)
{
gDone = true;
}
//==================================================================================================================================
// This routine is the first one called when an ODOC or PDOC event is received.
// In this routine you would place code used to setup structures, etc.
// which would be used in a 'for all docs' situation (like "Archive all
// dropped files")
//
// Obviously, the opening boolean tells you whether you should be opening
// or printing these files based on the type of event recieved.
//
// userDataHandle is a handle that you can create & use to store your own
// data structs. This dataHandle will be passed around to the other
// odoc/pdoc routines so that you can get at your data without using
// globals - just like the new StandardFile.
//
// We also return a boolean to tell the caller if you support this type
// of event. By default, our dropboxes don't support the pdoc, so when
// opening is FALSE, we return FALSE to let the caller send back the
// proper error code to the AEManager.
//==================================================================================================================================
#pragma segment Main
pascal Boolean PreFlightDocs(Boolean opening, Handle *userDataHandle)
{
if (!opening) return false;
if (gProcessing) return true;
gAborted = false;
ParamText("\p", "\p", "\p", "\p");
if (GenericProgress(codecProgressOpen, 0, 0) == codecAbortErr) return false;
DisableMenus();
return true; // we support opening, but not printing - see above
}
//==================================================================================================================================
// This routine is called for each file passed in the ODOC event.
//
// In this routine you would place code for processing each file/folder/disk that
// was dropped on top of you.
//==================================================================================================================================
#pragma segment Main
pascal void OpenDoc(FSSpecPtr myFSSPtr, Boolean opening, Handle userDataHandle)
{
FSSpec outFile;
OSErr theErr;
char *line;
if (gAborted) return;
if (gProcessing) {
AddToQueue(myFSSPtr, userDataHandle);
return;
}
ParamText("\p", "\p", "\p", "\p");
UpdateDialogItem(FrontWindow(), progressText2);
GenericProgress(codecProgressForceUpdatePercent, 0, 0);
theErr = OpenInputFile(myFSSPtr);
if (theErr == noErr) {
gLinesProcessed = 0;
do {
Size length;
Boolean bad;
line = GetNextInputLine(&length, &bad);
if (!(++gLinesProcessed & 0x3f))
if (GenericProgress(codecProgressUpdatePercent, FixRatio((gBytesRead - gInputBufferLeft) >> 8, gTotalSize >> 8), 0) == codecAbortErr) {
gAborted = true;
line = nil;
break;
}
} while (line && (line[0] != 'b' || line[1] != 'e' || line[2] != 'g' || line[3] != 'i' ||
line[4] != 'n' || line[5] != ' '));
if (line) {
theErr = OpenOutputFile(myFSSPtr, &outFile, &line[10]);
if (theErr == noErr) {
do {
line = GetNextUUInputLine();
if (line) theErr = DecodeUULine(line);
} while (theErr == noErr && line);
if (theErr != codecAbortErr) FlushOutputBuffer();
else gAborted = true;
CloseOutputFile(&outFile);
}
GenericProgress(codecProgressForceUpdatePercent, 0x10000, 0);
}
CloseInputFile(myFSSPtr);
ForceFolderUpdate(outFile.vRefNum, outFile.parID);
}
}
//==================================================================================================================================
// This routine is the last routine called as part of an ODOC event.
//
// In this routine you would place code to process any structures, etc.
// that you setup in the PreflightDocs routine.
//
// If you created a userDataHandle in the PreFlightDocs routines, this is
// the place to dispose of it since the Shell will NOT do it for you!
//==================================================================================================================================
#pragma segment Main
pascal void PostFlightDocs(Boolean opening, Handle userDataHandle)
{
if (gProcessing) return;
ProcessQueue();
GenericProgress(codecProgressClose, 0, 0);
EnableMenus();
if (opening && !gOApped) gDone = true;
}
//==================================================================================================================================
// This routine is called when the user chooses "Select File<6C>" from the
// File Menu.
//
// Currently it simply calls the new StandardGetFile routine to have the
// user select a single file (any type, numTypes = -1) and then calls the
// SendODOCToSelf routine in order to process it.
//
// The reason we send an odoc to ourselves is two fold: 1) it keeps the code
// cleaner as all file openings go through the same process, and 2) if events
// are ever recordable, the right things happen (this is called Factoring!)
//
// Modification of this routine to only select certain types of files, selection
// of multiple files, and/or handling of folder & disk selection is left
// as an exercise to the reader.
//==================================================================================================================================
pascal void SelectFile(void)
{
StandardFileReply stdReply;
SFTypeList theTypeList;
UserDialogActivate(FrontWindow(), false);
StandardGetFile(NULL, -1, theTypeList, &stdReply);
UserDialogActivate(FrontWindow(), true);
if (stdReply.sfGood) SendODOCToSelf(&stdReply.sfFile);
}
//==================================================================================================================================
// This routine is called during the program's initialization and gives you
// a chance to allocate or initialize any of your own globals that your
// dropbox needs.
//
// You return a boolean value which determines if you were successful.
// Returning false will cause DropShell to exit immediately.
//==================================================================================================================================
pascal Boolean InitUserGlobals(void)
{
long resp;
if (Gestalt(gestaltQuickdrawVersion, &resp) == noErr && resp) gHasCQD = true;
gInputBufferBase = gInputBuffer = (char *)NewPtr(kInputBufferSize * 2);
if (!gInputBuffer) return false;
gOutputBufferBase = gOutputBuffer = (char *)NewPtr(kOutputBufferSize * 2);
if (!gOutputBuffer) return false;
gInputPB1.ioParam.ioBuffer = gInputBufferBase + 256;
gInputPB1.ioParam.ioReqCount = kInputBufferSize - 512;
gInputPB1.ioParam.ioCompletion = gGenericCompletion;
gInputPB1.ioParam.ioPosMode = fsAtMark + dontCache;
gInputPB1.ioParam.ioPosOffset = 0;
gInputPB2.ioParam.ioBuffer = gInputBufferBase + kInputBufferSize + 256;
gInputPB2.ioParam.ioReqCount = kInputBufferSize - 512;
gInputPB2.ioParam.ioCompletion = gGenericCompletion;
gInputPB2.ioParam.ioPosMode = fsAtMark + dontCache;
gInputPB2.ioParam.ioPosOffset = 0;
gOutputPB1.ioParam.ioBuffer = gOutputBufferBase;
gOutputPB1.ioParam.ioCompletion = gGenericCompletion;
gOutputPB1.ioParam.ioPosMode = fsAtMark + dontCache;
gOutputPB1.ioParam.ioPosOffset = 0;
gOutputPB2.ioParam.ioBuffer = gOutputBufferBase + kOutputBufferSize;
gOutputPB2.ioParam.ioCompletion = gGenericCompletion;
gOutputPB2.ioParam.ioPosMode = fsAtMark + dontCache;
gOutputPB2.ioParam.ioPosOffset = 0;
gDeleteInputPB.ioParam.ioResult = 0;
LoadPrefs();
return true;
}
//==================================================================================================================================
// This routine is called during the program's cleanup and gives you
// a chance to deallocate any of your own globals that you allocated
// in the above routine.
//==================================================================================================================================
pascal void DisposeUserGlobals(void)
{
if (gInputBuffer) DisposePtr(gInputBuffer);
if (gOutputBuffer) DisposePtr(gOutputBuffer);
CloseUserDialog(FrontWindow());
SavePrefs();
}
//==================================================================================================================================
//==================================================================================================================================
//==================================================================================================================================
//==================================================================================================================================
//==================================================================================================================================
//==================================================================================================================================
pascal void HandleFileMenu(short id)
{
if (id == 2) CloseUserDialog(FrontWindow());
else if (id == 4) OpenUserDialog(0, id);
}
OSErr OpenInputFile(FSSpecPtr theSpec)
{
static HParamBlockRec openPB;
static ParamBlockRec eofPB;
OSErr theErr;
// set up the local parameter block to do an asynchronous open
openPB.fileParam.ioCompletion = gGenericCompletion;
openPB.fileParam.ioNamePtr = theSpec->name;
openPB.fileParam.ioVRefNum = theSpec->vRefNum;
openPB.ioParam.ioPermssn = fsRdPerm;
openPB.fileParam.ioDirID = theSpec->parID;
openPB.fileParam.ioResult = 1;
theErr = PBHOpenDFAsync(&openPB);
// give time to other applications as this is happening
while (openPB.fileParam.ioResult == 1) GiveTime();
theErr = openPB.fileParam.ioResult;
// save the resulting reference number in a global
gInputPB1.ioParam.ioRefNum = gInputPB2.ioParam.ioRefNum = gInputRefNum = openPB.ioParam.ioRefNum;
if (theErr == noErr) {
// set up the other local parameter block to do an asychronous GetEOF
eofPB.ioParam.ioCompletion = gGenericCompletion;
eofPB.ioParam.ioRefNum = gInputRefNum;
eofPB.ioParam.ioResult = 1;
theErr = PBGetEOFAsync(&eofPB);
// again, give up time to other apps while this happens
while (eofPB.ioParam.ioResult == 1) GiveTime();
theErr = eofPB.ioParam.ioResult;
if (theErr == noErr) {
// if everything went ok, store the size in a global, and reset the input reading parameter blocks
gTotalSize = (long)eofPB.ioParam.ioMisc;
gBytesRead = gLinesProcessed = 0;
gLastInputBuffer = gFoundEndCode = false;
gInputBufferLeft = 0;
gInputPB1.ioParam.ioResult = gInputPB2.ioParam.ioResult = 0;
gInputPB1.ioParam.ioActCount = gInputPB2.ioParam.ioActCount = 0;
// fill the two input buffers right away
return FillInputBuffer();
}
}
return theErr;
}
OSErr FillInputBuffer(void)
{
Boolean buffer1 = (!gBytesRead || gInputBufferPtr < gInputBufferBase + kInputBufferSize);
Boolean firstTime = !gBytesRead;
static ParmBlkPtr pb, oppPB;
OSErr theErr = noErr;
// get pointers to the parameter block for this buffer and for the opposite buffer
pb = (buffer1) ? &gInputPB1 : &gInputPB2;
oppPB = (buffer1) ? &gInputPB2 : &gInputPB1;
// copy remaining bytes in this buffer to beginning of next buffer
if (gInputBufferLeft) BlockMove(gInputBufferPtr, oppPB->ioParam.ioBuffer - gInputBufferLeft, gInputBufferLeft);
gInputBufferPtr = oppPB->ioParam.ioBuffer - gInputBufferLeft;
// wait for next buffer to finish, if necessary
while (oppPB->ioParam.ioResult == 1) GiveTime();
if (!firstTime && oppPB->ioParam.ioResult == eofErr && !oppPB->ioParam.ioActCount) gLastInputBuffer = true;
// adjust the count of bytes left and bytes read
gInputBufferLeft += oppPB->ioParam.ioActCount;
gBytesRead += oppPB->ioParam.ioActCount;
// now begin loading into the buffer we just skipped out of
pb->ioParam.ioResult = 1;
theErr = PBReadAsync(pb);
if (theErr == eofErr) theErr = noErr;
// if this is the first time reading, then we wait for this buffer to load, and load in a second buffer
if (firstTime) {
gInputBufferPtr = pb->ioParam.ioBuffer;
while (pb->ioParam.ioResult == 1) GiveTime();
gInputBufferLeft = pb->ioParam.ioActCount;
gBytesRead = pb->ioParam.ioActCount;
oppPB->ioParam.ioResult = 1;
theErr = PBReadAsync(oppPB);
if (theErr == eofErr) theErr = noErr;
}
return theErr;
}
OSErr CloseInputFile(FSSpecPtr theSpec)
{
static Boolean first = true;
static HParamBlockRec pb;
static CMovePBRec cpb;
OSErr theErr;
if (!first) while (pb.ioParam.ioResult == 1) GiveTime();
else first = false;
pb.ioParam.ioCompletion = gGenericCompletion;
pb.ioParam.ioRefNum = gInputRefNum;
pb.ioParam.ioResult = 1;
theErr = PBCloseAsync((ParmBlkPtr)&pb);
if (gFoundEndCode) {
if ((*gPrefs)->trashSource == kTrashSource) {
while (pb.ioParam.ioResult == 1) GiveTime();
FSSpec destSpec = *theSpec;
theErr = FindFolder(theSpec->vRefNum, kTrashFolderType,
kCreateFolder, &destSpec.vRefNum, &destSpec.parID);
if (theErr == noErr) {
short count = 1;
Str63 oldName;
BlockMove(theSpec->name, oldName, *theSpec->name + 1);
do {
cpb.ioCompletion = gGenericCompletion;
cpb.ioNamePtr = theSpec->name;
cpb.ioVRefNum = theSpec->vRefNum;
cpb.ioNewName = nil;
cpb.ioNewDirID = destSpec.parID;
cpb.ioDirID = theSpec->parID;
cpb.ioResult = 1;
theErr = PBCatMoveAsync(&cpb);
while (cpb.ioResult == 1) GiveTime();
if (cpb.ioResult == dupFNErr) {
Str63 newName;
if (*theSpec->name < 28) theSpec->name[*theSpec->name + 1] = 0;
else theSpec->name[29] = 0;
sprintf((char *)&newName[1], "%s %d", &oldName[1], ++count);
*newName = strlen((char *)&newName[1]);
pb.fileParam.ioCompletion = gGenericCompletion;
pb.fileParam.ioNamePtr = theSpec->name;
pb.fileParam.ioVRefNum = theSpec->vRefNum;
pb.fileParam.ioDirID = theSpec->parID;
pb.ioParam.ioMisc = (Ptr)newName;
theErr = PBHRenameAsync(&pb);
while (pb.ioParam.ioResult == 1) GiveTime();
BlockMove(newName, theSpec->name, *newName + 1);
}
} while (cpb.ioResult == dupFNErr);
}
} else if ((*gPrefs)->trashSource == kDeleteSource) {
while (pb.ioParam.ioResult == 1) GiveTime();
pb.fileParam.ioCompletion = gGenericCompletion;
pb.fileParam.ioNamePtr = theSpec->name;
pb.fileParam.ioVRefNum = theSpec->vRefNum;
pb.fileParam.ioDirID = theSpec->parID;
theErr = PBHDeleteAsync(&pb);
while (pb.ioParam.ioResult == 1) GiveTime();
}
}
return theErr;
}
char *GetNextInputLine(Size *length, Boolean *badUU)
{
OSErr theErr = noErr;
if (gInputBufferLeft <= 0 && gLastInputBuffer) return nil;
else if (gInputBufferLeft < 256) theErr = FillInputBuffer();
if (theErr == noErr) {
register char *start = gInputBufferPtr;
register char *p = gInputBufferPtr;
register char *end = gInputBufferPtr + gInputBufferLeft;
register char c;
do {
c = *p++;
if (c == 0x0d || c == 0x0a) break;
if (c < ' ' || c > '`') *badUU = true;
} while (p < end);
p[-1] = 0;
*length = p - start - 1;
do {
c = *p++;
} while (c == 0x0d && c == 0x0a && p < end);
p--;
gInputBufferPtr = p;
gInputBufferLeft -= (p - start);
return start;
}
return nil;
}
char *GetNextUUInputLine(void)
{
register char *line;
Boolean bad = false;
Size length;
do {
register int count, min, max;
line = GetNextInputLine(&length, &bad);
if (!line) return nil;
if (line[0] == 'e' && line[1] == 'n' && line[2] == 'd' && line[3] == 0) {
gFoundEndCode = true;
return nil;
}
if (bad) {
bad = false;
continue;
}
count = (line[0] - ' ');
if (count < 0 || count > 45) continue;
min = ((count << 2) + 2) / 3;
max = (((min + 3) >> 2) << 2) + 1;
length--;
if (length < min || length > max) continue;
return line;
} while (line);
return nil;
}
OSErr DecodeUULine(char *line)
{
register int count = (*line++) - ' ';
register int i;
register char *src, *dst;
register char c1, c2;
OSErr theErr = noErr;
if ((gOutputBufferCount + count + 256 + 3) > kOutputBufferSize) theErr = FlushOutputBuffer();
for (i = 0, src = line, dst = gOutputBufferPtr; i < count; i += 3) {
c1 = (*src++ - ' ') & 0x3f;
c2 = (*src++ - ' ') & 0x3f;
*dst++ = ((c1 << 2) | (c2 >> 4)) & 0xff;
c1 = (*src++ - ' ') & 0x3f;
*dst++ = ((c2 << 4) | (c1 >> 2)) & 0xff;
c2 = (*src++ - ' ') & 0x3f;
*dst++ = ((c1 << 6) | c2) & 0xff;
}
gOutputBufferCount += count;
gOutputBufferPtr = dst;
if (!(++gLinesProcessed & 0x3f))
theErr = GenericProgress(codecProgressUpdatePercent, FixRatio((gBytesRead - gInputBufferLeft) >> 8, gTotalSize >> 8), 0);
return theErr;
}
OSErr OpenOutputFile(FSSpecPtr inSpec, FSSpecPtr outSpec, char *outName)
{
register char *p = outName;
register int count = 0;
OSErr theErr = noErr;
OSType creator, type;
register char c;
// first figure out the creator and type based on the output filename (assume the eol is already set up)
MapOutputExtension(outName, &creator, &type);
// now copy the filename into the FSSpec, limiting the length to 31 characters
*outSpec = *inSpec;
outSpec->name[31] = 0;
do {
c = *p++;
} while (c && ++count < 32);
p[-1] = 0;
strncpy((char *)&outSpec->name[1], outName, 30);
*outSpec->name = strlen((char *)&outSpec->name[1]);
ParamText(outSpec->name, "\p", "\p", "\p");
UpdateDialogItem(FrontWindow(), progressText2);
// do the actual creation, avoiding namespace conflicts
theErr = CreateOutputFile(outSpec, outName, creator, type);
// assuming everything else went okay, we finally open the file for writing
if (theErr == noErr) {
gOpenOutputPB.ioParam.ioCompletion = gGenericCompletion;
gOpenOutputPB.fileParam.ioNamePtr = outSpec->name;
gOpenOutputPB.fileParam.ioVRefNum = outSpec->vRefNum;
gOpenOutputPB.ioParam.ioPermssn = fsRdWrPerm;
gOpenOutputPB.fileParam.ioDirID = outSpec->parID;
gOpenOutputPB.ioParam.ioResult = 1;
theErr = PBHOpenDFAsync(&gOpenOutputPB);
}
// reset all the output-related variables, and return
gOutputBufferPtr = gOutputBuffer;
gOutputBufferCount = 0;
gOutputPB1.ioParam.ioResult = gOutputPB2.ioParam.ioResult = 0;
return theErr;
}
#define ASYNC_CREATE 1
OSErr CreateOutputFile(FSSpecPtr outSpec, char *outName, OSType creator, OSType type)
{
static HParamBlockRec createPB;
static HParamBlockRec fInfoPB;
register int count = 0;
OSErr theErr = noErr;
// here begins our loop to find a valid name for the new output file
do {
#if ASYNC_CREATE
// now set up the local parameter block to do an asynchronous create
createPB.ioParam.ioCompletion = gGenericCompletion;
createPB.fileParam.ioNamePtr = outSpec->name;
createPB.fileParam.ioVRefNum = outSpec->vRefNum;
createPB.fileParam.ioDirID = outSpec->parID;
createPB.ioParam.ioResult = 1;
theErr = PBHCreateAsync(&createPB);
// give time to other processes while this happens
while (createPB.ioParam.ioResult == 1) GiveTime();
if (theErr == noErr) theErr = createPB.ioParam.ioResult;
#else
theErr = FSpCreate(outSpec, creator, type, 0);
#endif
// if a duplicate file name error occurred, bump up the last digit
if (theErr == dupFNErr) {
strncpy((char *)&outSpec->name[1], outName, 28);
outSpec->name[29] = 0;
*outSpec->name = strlen((char *)&outSpec->name[1]);
outSpec->name[++*outSpec->name] = '.';
outSpec->name[++*outSpec->name] = '0' + count++;
}
} while (theErr == dupFNErr);
#if ASYNC_CREATE
// now get the default file information from the Finder
if (theErr == noErr) {
fInfoPB.ioParam.ioCompletion = gGenericCompletion;
fInfoPB.fileParam.ioNamePtr = outSpec->name;
fInfoPB.fileParam.ioVRefNum = outSpec->vRefNum;
fInfoPB.fileParam.ioFDirIndex = 0;
fInfoPB.fileParam.ioDirID = outSpec->parID;
fInfoPB.ioParam.ioResult = 1;
theErr = PBHGetFInfoAsync(&fInfoPB);
}
// give time to other processes while this happens
while (fInfoPB.ioParam.ioResult == 1) GiveTime();
if (theErr == noErr) theErr = fInfoPB.ioParam.ioResult;
// then set the type and creator for this file
if (theErr == noErr) {
fInfoPB.fileParam.ioFlFndrInfo.fdCreator = creator;
fInfoPB.fileParam.ioFlFndrInfo.fdType = type;
fInfoPB.fileParam.ioDirID = outSpec->parID;
fInfoPB.ioParam.ioResult = 1;
theErr = PBHSetFInfoAsync(&fInfoPB);
}
// give time to other processes while this happens
while (fInfoPB.ioParam.ioResult == 1) GiveTime();
if (theErr == noErr) theErr = fInfoPB.ioParam.ioResult;
#endif
return theErr;
}
void MapOutputExtension(char *outName, OSType *creator, OSType *type)
{
*creator = '???\?';
*type = '???\?';
if (gMapResource) {
int namelen = strlen(outName);
char *p = *gMapResource;
int count = *(short *)p, i;
p += 2;
while (count--) {
int length = *p++;
for (i = 0; i < length; i++)
if (toupper(outName[namelen - length + i]) != p[i]) break;
if (i == length) {
*type = *(OSType *)&p[5];
*creator = *(OSType *)&p[9];
return;
}
p += 15;
}
}
}
OSErr FlushOutputBuffer(void)
{
Boolean buffer1 = (gOutputBufferPtr <= gOutputBufferBase + kOutputBufferSize);
static ParmBlkPtr pb, oppPB;
OSErr theErr = noErr;
// point to the current parameter block and the opposing one
pb = (buffer1) ? &gOutputPB1 : &gOutputPB2;
oppPB = (buffer1) ? &gOutputPB2 : &gOutputPB1;
// make sure that the asynchronous open of the file finished
while (gOpenOutputPB.ioParam.ioResult == 1) GiveTime();
if (gOpenOutputPB.ioParam.ioResult != noErr) return gOpenOutputPB.ioParam.ioResult;
gOutputRefNum = gOpenOutputPB.ioParam.ioRefNum;
// now set up the parameter block for the write and do it
pb->ioParam.ioRefNum = gOutputRefNum;
pb->ioParam.ioReqCount = gOutputBufferCount;
pb->ioParam.ioResult = 1;
theErr = PBWriteAsync(pb);
// reset the counts and the buffer pointers
gOutputBufferCount = 0;
gOutputBufferPtr = oppPB->ioParam.ioBuffer;
// then make sure that the previous write from the next buffer is all done and return
while (oppPB->ioParam.ioResult == 1) GiveTime();
if (oppPB->ioParam.ioResult != noErr) theErr = oppPB->ioParam.ioResult;
return theErr;
}
OSErr CloseOutputFile(FSSpecPtr theSpec)
{
OSErr theErr;
gCloseOutputPB.ioParam.ioCompletion = gGenericCompletion;
gCloseOutputPB.ioParam.ioRefNum = gOutputRefNum;
theErr = PBCloseAsync((ParmBlkPtr)&gCloseOutputPB);
if (gAborted) {
static Str255 name;
BlockMove(theSpec->name, name, *theSpec->name + 1);
while (gCloseOutputPB.ioParam.ioResult == 1) GiveTime();
gCloseOutputPB.fileParam.ioCompletion = gGenericCompletion;
gCloseOutputPB.fileParam.ioNamePtr = name;
gCloseOutputPB.fileParam.ioVRefNum = theSpec->vRefNum;
gCloseOutputPB.fileParam.ioDirID = theSpec->parID;
gCloseOutputPB.ioParam.ioResult = 1;
theErr = PBHDeleteAsync(&gCloseOutputPB);
}
return theErr;
}
void AddToQueue(FSSpec *theSpec, Handle userData)
{
odocQueuePtr odoc = (odocQueuePtr)NewPtrClear(sizeof(odocQueue)), o;
if (odoc) {
if (godocQueue) {
for (o = godocQueue; o->next; o = o->next);
if (o) o->next = odoc;
} else godocQueue = odoc;
odoc->spec = *theSpec;
odoc->data = userData;
}
}
void ProcessQueue(void)
{
odocQueuePtr o;
while (o = godocQueue) {
OpenDoc(&o->spec, true, o->data);
godocQueue = o->next;
DisposePtr((Ptr)o);
}
}
void DisableMenus(void)
{
MenuHandle theMenu = GetMHandle(kAppleNum);
DisableItem(theMenu, 1);
theMenu = GetMHandle(kFileNum);
DisableItem(theMenu, 0);
DrawMenuBar();
}
void EnableMenus(void)
{
MenuHandle theMenu = GetMHandle(kAppleNum);
EnableItem(theMenu, 1);
theMenu = GetMHandle(kFileNum);
EnableItem(theMenu, 0);
DrawMenuBar();
}
#if defined(powerc) || defined(__powerc)
pascal void GenericCompletion(ParmBlkPtr paramBlock)
#else
pascal void GenericCompletion(void)
#endif
{
}