mirror of
https://github.com/depp/syncfiles.git
synced 2024-12-17 16:29:29 +00:00
Rework error handling
Previously, various error handling functions were defined, but not all of them were even used. The new error handling functions handle the most common cases: - Assertions. These can be handled with `ASSERT()`, which gives the error location for debugging. - Errors we don't know how to handle, like GetNewWindow returning NULL. These can be handled with `EXIT_INTERNAL()`, which gives the error location for debugging. - Out of memory conditions. These can be handled with `ShowMemError()`. - System errors in response to user operations. These can be handled with `ShowError()`.
This commit is contained in:
parent
56a3983129
commit
b1bcae531b
@ -47,7 +47,8 @@ static void SelectCurrentDirectory(struct ChooseDirReply *reply)
|
||||
ci.dirInfo.ioDrDirID = LMGetCurDirStore();
|
||||
err = PBGetCatInfoSync(&ci);
|
||||
if (err != 0) {
|
||||
ExitErrorOS(kErrUnknown, err);
|
||||
ShowError(kErrNone, kErrNone, err, NULL);
|
||||
return;
|
||||
}
|
||||
directory = reply->directory;
|
||||
directory->vRefNum = ci.dirInfo.ioVRefNum;
|
||||
@ -99,10 +100,10 @@ Boolean ChooseDirectory(FSSpec *directory)
|
||||
switch (cdreply.status) {
|
||||
case kCDChild:
|
||||
BlockMoveData(&sfreply.sfFile, directory, sizeof(FSSpec));
|
||||
return 1;
|
||||
return true;
|
||||
case kCDCurrent:
|
||||
return 1;
|
||||
return true;
|
||||
default:
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
127
macos/error.c
127
macos/error.c
@ -3,73 +3,120 @@
|
||||
// Mozilla Public License, version 2.0. See LICENSE.txt for details.
|
||||
#include "macos/error.h"
|
||||
|
||||
#include "lib/defs.h"
|
||||
#include "macos/main.h"
|
||||
#include "macos/pstrbuilder.h"
|
||||
#include "macos/resources.h"
|
||||
#include "macos/strutil.h"
|
||||
|
||||
#include <Dialogs.h>
|
||||
#include <TextUtils.h>
|
||||
|
||||
void ExitError(ErrorCode errCode)
|
||||
enum {
|
||||
// OK
|
||||
kStrOK = 1,
|
||||
// Quit
|
||||
kStrQuit,
|
||||
// An error of type ^2 occurred.
|
||||
kStrErrorCode,
|
||||
// Error at: ^1:^2
|
||||
kStrErrorAt,
|
||||
// Assertion: ^1
|
||||
kStrAssertion,
|
||||
// An internal error occurred.
|
||||
kStrInternal,
|
||||
// An unknown error occurred.
|
||||
kStrUnknown,
|
||||
// (Base value for error messages.)
|
||||
kStrMessageBase
|
||||
};
|
||||
|
||||
static void AppendErrorArray(struct PStrBuilder *str, int sep, int strNum,
|
||||
int paramCount, const unsigned char *const *params)
|
||||
{
|
||||
Str255 message;
|
||||
|
||||
GetIndString(message, rSTRS_Errors, errCode);
|
||||
if (message[0] == 0) {
|
||||
GetIndString(message, rSTRS_Errors, kErrUnknown);
|
||||
if (str->data[0] > 0 && sep != 0) {
|
||||
PStrAppendChar(str, sep);
|
||||
}
|
||||
GetIndString(message, rSTRS_Errors, strNum);
|
||||
if (message[0] == 0) {
|
||||
PStrAppendChar(str, '?');
|
||||
} else {
|
||||
PStrAppendSubstitute(str, message, paramCount, params);
|
||||
}
|
||||
ParamText(message, NULL, NULL, NULL);
|
||||
Alert(rAlrtError, NULL);
|
||||
QuitApp();
|
||||
}
|
||||
|
||||
void ExitErrorOS(ErrorCode errCode, short osErr)
|
||||
static void AppendError0(struct PStrBuilder *str, int sep, int strNum)
|
||||
{
|
||||
Str255 message;
|
||||
|
||||
GetIndString(message, rSTRS_Errors, errCode);
|
||||
if (message[0] == 0) {
|
||||
GetIndString(message, rSTRS_Errors, kErrUnknown);
|
||||
}
|
||||
StrAppendFormat(message, "\p\rError code: %d", osErr);
|
||||
ParamText(message, NULL, NULL, NULL);
|
||||
Alert(rAlrtError, NULL);
|
||||
QuitApp();
|
||||
AppendErrorArray(str, sep, strNum, 0, NULL);
|
||||
}
|
||||
|
||||
void ExitMemError(void)
|
||||
static void AppendError1(struct PStrBuilder *str, int sep, int strNum,
|
||||
const unsigned char *strParam)
|
||||
{
|
||||
ExitErrorOS(kErrOutOfMemory, MemError());
|
||||
AppendErrorArray(str, sep, strNum, 1, &strParam);
|
||||
}
|
||||
|
||||
static void AppendError2(struct PStrBuilder *str, int sep, int strNum,
|
||||
const unsigned char *strParam, int intParam)
|
||||
{
|
||||
unsigned char num[16];
|
||||
const unsigned char *params[2];
|
||||
|
||||
params[0] = strParam;
|
||||
NumToString(intParam, num);
|
||||
params[1] = num;
|
||||
AppendErrorArray(str, sep, strNum, 2, params);
|
||||
}
|
||||
|
||||
static void ShowErrorAlert(const unsigned char *message, int button)
|
||||
{
|
||||
Str255 buttonText;
|
||||
|
||||
GetIndString(buttonText, rSTRS_Errors, button);
|
||||
ParamText(message, buttonText, NULL, NULL);
|
||||
Alert(rAlrtError, NULL);
|
||||
}
|
||||
|
||||
void ExitAssert(const unsigned char *file, int line,
|
||||
const unsigned char *message)
|
||||
const unsigned char *assertion)
|
||||
{
|
||||
Str255 dmessage;
|
||||
struct PStrBuilder str;
|
||||
|
||||
GetIndString(dmessage, rSTRS_Errors, kErrInternal);
|
||||
StrAppendFormat(dmessage, "\p\rError at: %S:%d", file, line);
|
||||
if (message != NULL) {
|
||||
StrAppendFormat(dmessage, "\p: %S", message);
|
||||
PStrInit(&str);
|
||||
AppendError0(&str, 0, kStrInternal);
|
||||
if (file != NULL) {
|
||||
AppendError2(&str, '\r', kStrErrorAt, file, line);
|
||||
}
|
||||
ParamText(dmessage, NULL, NULL, NULL);
|
||||
Alert(rAlrtError, NULL);
|
||||
if (assertion != NULL) {
|
||||
AppendError1(&str, '\r', kStrAssertion, assertion);
|
||||
}
|
||||
ShowErrorAlert(str.data, kStrQuit);
|
||||
QuitApp();
|
||||
}
|
||||
|
||||
void ShowError(const struct ErrorParams *p)
|
||||
void ShowError(ErrorCode err1, ErrorCode err2, short osErr,
|
||||
const unsigned char *strParam)
|
||||
{
|
||||
Str255 message;
|
||||
struct PStrBuilder str;
|
||||
|
||||
GetIndString(message, rSTRS_Errors, p->err);
|
||||
if (message[0] == 0) {
|
||||
GetIndString(message, rSTRS_Errors, kErrUnknown);
|
||||
} else if (p->strParam != NULL) {
|
||||
StrSubstitute(message, p->strParam);
|
||||
PStrInit(&str);
|
||||
if (err1 != kErrNone) {
|
||||
AppendError1(&str, ' ', kStrMessageBase - 1 + err1, strParam);
|
||||
}
|
||||
if (p->osErr != NULL) {
|
||||
StrAppendFormat(message, "\p\rError code: %d", p->osErr);
|
||||
if (err2 != kErrNone) {
|
||||
AppendError1(&str, ' ', kStrMessageBase - 1 + err2, strParam);
|
||||
}
|
||||
ParamText(message, NULL, NULL, NULL);
|
||||
Alert(rAlrtError, NULL);
|
||||
if (osErr != 0) {
|
||||
AppendError2(&str, ' ', kStrErrorCode, NULL, osErr);
|
||||
}
|
||||
if (str.data[0] == 0) {
|
||||
AppendError0(&str, ' ', kStrUnknown);
|
||||
}
|
||||
ShowErrorAlert(str.data, kStrOK);
|
||||
}
|
||||
|
||||
void ShowMemError(void)
|
||||
{
|
||||
ShowError(kErrOutOfMemory, kErrNone, MemError(), NULL);
|
||||
}
|
||||
|
@ -6,32 +6,34 @@
|
||||
|
||||
// Error codes, corresponding to messages in a STR# resource. This should be
|
||||
// kept in sync with STR# rSTRS_Errors in resources.r.
|
||||
typedef enum {
|
||||
// An unknown error occurred.
|
||||
kErrUnknown = 1,
|
||||
// An internal error occurred.
|
||||
kErrInternal,
|
||||
typedef enum ErrorCode {
|
||||
// (no error)
|
||||
kErrNone,
|
||||
// Out of memory.
|
||||
kErrOutOfMemory,
|
||||
// Could not save project "^1".
|
||||
kErrCouldNotSaveProject,
|
||||
// Could not read project "^1".
|
||||
kErrCouldNotReadProject,
|
||||
// The project file is damaged.
|
||||
kErrProjectDamaged,
|
||||
// The project file is from an unknown version of SyncFiles.
|
||||
kErrProjectUnknownVersion,
|
||||
// Could not query volume parameters.
|
||||
kErrVolumeQuery,
|
||||
// Could not create alias.
|
||||
kErrAlias,
|
||||
// Could not get directory path.
|
||||
kErrDirPath
|
||||
} ErrorCode;
|
||||
|
||||
// ExitError shows an error dialog with the given error message, then quits the
|
||||
// program.
|
||||
void ExitError(ErrorCode errCode);
|
||||
|
||||
// ExitErrorOS shows an error dialog with the given error message and an OS
|
||||
// error code, then quits the program.
|
||||
void ExitErrorOS(ErrorCode errCode, short osErr);
|
||||
|
||||
// ExitMemError shows an out of memory error and quits the program.
|
||||
void ExitMemError(void);
|
||||
|
||||
// ExitAssert shows an assertion error and quits the program. The message may be
|
||||
// NULL.
|
||||
// ExitAssert shows an assertion error and quits the program. Either the file or
|
||||
// the assertion may be NULL.
|
||||
void ExitAssert(const unsigned char *file, int line,
|
||||
const unsigned char *message);
|
||||
const unsigned char *assertion);
|
||||
|
||||
// EXIT_INTERNAL shows an internal error message and quits the program.
|
||||
#define EXIT_INTERNAL() ExitAssert("\p" __FILE__, __LINE__, NULL)
|
||||
|
||||
// EXIT_ASSERT shows an assertion error and quits the program. The message may
|
||||
// be NULL.
|
||||
@ -45,24 +47,13 @@ void ExitAssert(const unsigned char *file, int line,
|
||||
ExitAssert("\p" __FILE__, __LINE__, "\p" #p); \
|
||||
} while (0)
|
||||
|
||||
// An ErrorParams contains the parameters for displaying en error alert window.
|
||||
// This structure should be zeroed before use, in case additional fields are
|
||||
// added.
|
||||
struct ErrorParams {
|
||||
// The application error code. If this is zero, it will be treated as
|
||||
// kErrInternal.
|
||||
ErrorCode err;
|
||||
// ShowMemError shows an out of memory error to the user.
|
||||
void ShowMemError(void);
|
||||
|
||||
// The OS error code. This is displayed at the end of the error message,
|
||||
// unless it is zero.
|
||||
short osErr;
|
||||
|
||||
// If the error messages contain any string substitutions like "^1", those
|
||||
// substitutions are replaced with this string.
|
||||
const unsigned char *strParam;
|
||||
};
|
||||
|
||||
// ShowError shows an error alert window to the user.
|
||||
void ShowError(const struct ErrorParams *p);
|
||||
// ShowError shows an error alert window to the user. The error codes are
|
||||
// displayed if they are not 0. If osErr is not 0, then it is displayed as well.
|
||||
// Any ^1 parameters in the error messages are replaced with strParam.
|
||||
void ShowError(ErrorCode err1, ErrorCode err2, short osErr,
|
||||
const unsigned char *strParam);
|
||||
|
||||
#endif
|
||||
|
@ -130,11 +130,11 @@ void ProjectNew(void)
|
||||
|
||||
project = (ProjectHandle)NewHandle(sizeof(struct Project));
|
||||
if (project == NULL) {
|
||||
EXIT_ASSERT(NULL);
|
||||
EXIT_INTERNAL();
|
||||
}
|
||||
window = GetNewCWindow(rWIND_Project, NULL, (WindowPtr)-1);
|
||||
if (window == NULL) {
|
||||
EXIT_ASSERT(NULL);
|
||||
EXIT_INTERNAL();
|
||||
}
|
||||
windowWidth = window->portRect.right - window->portRect.left;
|
||||
SetWRefCon(window, (long)project);
|
||||
@ -145,7 +145,7 @@ void ProjectNew(void)
|
||||
for (i = 0; i < 2; i++) {
|
||||
control = GetNewControl(rCNTL_ChooseFolder, window);
|
||||
if (control == NULL) {
|
||||
EXIT_ASSERT(NULL);
|
||||
EXIT_INTERNAL();
|
||||
}
|
||||
controlWidth =
|
||||
(*control)->contrlRect.right - (*control)->contrlRect.left;
|
||||
@ -453,7 +453,6 @@ static void ProjectSave(WindowRef window, ProjectHandle project,
|
||||
Str255 name;
|
||||
StandardFileReply reply;
|
||||
OSErr err;
|
||||
struct ErrorParams errp;
|
||||
FSSpec spec;
|
||||
ScriptCode script;
|
||||
|
||||
@ -483,11 +482,7 @@ static void ProjectSave(WindowRef window, ProjectHandle project,
|
||||
return;
|
||||
|
||||
error:
|
||||
memset(&errp, 0, sizeof(errp));
|
||||
errp.err = kErrCouldNotSaveProject;
|
||||
errp.osErr = err;
|
||||
errp.strParam = reply.sfFile.name;
|
||||
ShowError(&errp);
|
||||
ShowError(kErrCouldNotSaveProject, kErrNone, err, reply.sfFile.name);
|
||||
}
|
||||
|
||||
void ProjectCommand(WindowRef window, ProjectHandle project, int menuID,
|
||||
@ -569,7 +564,8 @@ static Boolean VolumeDoesSupportIDs(short vRefNum)
|
||||
hb.ioParam.ioReqCount = sizeof(parms);
|
||||
err = PBHGetVolParms(&hb, false);
|
||||
if (err != noErr) {
|
||||
ExitErrorOS(kErrUnknown, err);
|
||||
ShowError(kErrVolumeQuery, kErrNone, err, NULL);
|
||||
return false;
|
||||
}
|
||||
return (parms.vMAttrib & (1ul << bHasFileIDs)) != 0;
|
||||
}
|
||||
@ -591,15 +587,21 @@ static void ProjectChooseDir(WindowRef window, ProjectHandle project,
|
||||
if (VolumeDoesSupportIDs(directory.vRefNum)) {
|
||||
err = NewAlias(NULL, &directory, &alias);
|
||||
if (err != noErr) {
|
||||
ExitErrorOS(kErrUnknown, err);
|
||||
ShowError(kErrAlias, kErrNone, err, NULL);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
alias = NULL;
|
||||
}
|
||||
err = GetDirPath(&directory, &pathLength, &path);
|
||||
if (err != noErr) {
|
||||
ExitErrorOS(kErrUnknown, err);
|
||||
ShowError(kErrDirPath, kErrNone, err, NULL);
|
||||
if (alias != NULL) {
|
||||
DisposeHandle((Handle)alias);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
projectp = *project;
|
||||
dirp = &projectp->dirs[whichDir];
|
||||
if (dirp->path != NULL) {
|
||||
|
@ -5,6 +5,12 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void PStrInit(struct PStrBuilder *buf)
|
||||
{
|
||||
buf->data[0] = 0;
|
||||
buf->truncated = 0;
|
||||
}
|
||||
|
||||
static void PStrAppendMem(struct PStrBuilder *buf, const unsigned char *src,
|
||||
int slen)
|
||||
{
|
||||
@ -35,6 +41,11 @@ static void PStrAppendMem(struct PStrBuilder *buf, const unsigned char *src,
|
||||
buf->data[0] = dlen + slen;
|
||||
}
|
||||
|
||||
void PStrAppendChar(struct PStrBuilder *buf, unsigned char c)
|
||||
{
|
||||
PStrAppendMem(buf, &c, 1);
|
||||
}
|
||||
|
||||
void PStrAppend(struct PStrBuilder *buf, const unsigned char *src)
|
||||
{
|
||||
PStrAppendMem(buf, src + 1, src[0]);
|
||||
|
@ -29,6 +29,12 @@ struct PStrBuilder {
|
||||
Boolean truncated;
|
||||
};
|
||||
|
||||
// PStrInit initializes a string buffer.
|
||||
void PStrInit(struct PStrBuilder *buf);
|
||||
|
||||
// PStrAppendChar appends a single character to the buffer.
|
||||
void PStrAppendChar(struct PStrBuilder *buf, unsigned char c);
|
||||
|
||||
// PStrAppend appends a string to the buffer.
|
||||
void PStrAppend(struct PStrBuilder *buf, const unsigned char *src);
|
||||
|
||||
|
@ -119,10 +119,21 @@ resource 'BNDL' (128, purgeable) {
|
||||
};
|
||||
|
||||
resource 'STR#' (rSTRS_Errors) {{
|
||||
"An unknown error occurred.",
|
||||
"OK",
|
||||
"Quit",
|
||||
"An error of type ^2 occurred.",
|
||||
"Error at: ^1:^2",
|
||||
"Assertion: ^1",
|
||||
"An internal error occurred.",
|
||||
"An unknown error occurred.",
|
||||
"Out of memory.",
|
||||
"Could not save project “^1”.",
|
||||
"Could not read project “^1”.",
|
||||
"The project file is damaged.",
|
||||
"The project file is from an unknown version of SyncFiles.",
|
||||
"Could not query volume parameters.",
|
||||
"Could not create alias.",
|
||||
"Could not get directory path.",
|
||||
}};
|
||||
|
||||
resource 'WIND' (rWIND_Project, preload, purgeable) {
|
||||
|
Loading…
Reference in New Issue
Block a user