home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula
/
nebula.bin
/
SourceCode
/
Classes
/
SampleClasses
/
ReadConfig.h
< prev
next >
Wrap
Text File
|
1992-08-04
|
18KB
|
311 lines
// -------------------------------------------------------------------------------------
// ReadConfig.m - Read/Execute run-time configuration file.
// Author: Martin D. Flynn, NeXT Computer, Inc.
// Description:
// This class provides a general solution to applications that require run-time
// configuration. A configuration file name can be passed to the method name:
// readConfigFile:target:
// The file will be parsed and interpreted as method names and arguments to send to the
// specified target. Methods requiring no-arguments, or one-argument, are allowed.
// The class also contains some primitive branching controls to provide a simple contol
// language.
// -------------------------------------------------------------------------------------
// Permission is granted to freely redistribute this source code, and to use fragments
// of this code in your own applications if you find them to be useful. This class,
// along with the source code, come with no warranty of any kind, and the user assumes
// all responsibility for its use.
// -------------------------------------------------------------------------------------
// Notes:
// - Do NOT instantiate this object. It will instantiate a temporary copy of itself.
// - Comment lines start with (' ', '\n', '\t', or '/') in the first column.
// - A label is prefaced with a ':' (ie. ':Label').
// - Method return status is 0 for success, error otherwise.
// - Methods prefaced with '!' will skip return status checking for that method.
// - A method with no parameter is allowed.
// - If the target method responds to 'configWillPerform:with:', then this method will
// will be sent to the target prior to each config method sent. If
// 'configWillPerform:with:' returns true, then the config method will also be sent,
// otherwise it will be skipped.
// - Internal methods are prefaced with a '*' (internal methods listed below).
// - The configuration read will be terminated when an error is encountered.
// - [ReadConfig lineNumber] will return the last executed line.
// - '*checkReturn: *NO' must be set prior to using '*ifTrue: lbl' or '*ifFalse: lbl'
// - Method names may end with a '$' followed by any character. This will be stripped
// prior to calling the method. (this is used for updating config files)
// - If time lapse profiling has been activated, then after each config file method
// executed, when ReadConfig regains control, the method 'profileTimeLapse:' will be
// - sent to the global
// - Reserved parameter options:
// *nil = pass a nil pointer to method
// *YES = pass boolean YES to method
// *NO = pass boolean NO to method
// *id = pass id created with *newId to method
// -------------------------------------------------------------------------------------
// Example config:
//
// // -----------------------------------------------------------------------------
// // set ReadConfig modes
// *methodTrace: *YES
// *printError: *YES
// // -----------------------------------------------------------------------------
// // open and recalc data
// *print: openning data file
// myOpenData: data/myData.file
// *print: recalculating info
// *checkReturn: *NO
// recalcInfo *nil
// *ifTrue: returnTrue
// *print: recalcInfo returned False
// *goto: skip
// :returnTrue
// *print: recalcInfo returned True
// showErrorPanel
// :skip
// // -----------------------------------------------------------------------------
// // option selection panel
// *optionPanel: select A or B
// *ifFalse: selectA
// *print: you selected B
// *goto: endSelect
// :selectA
// *print: your selected A
// :endSelect
// // -----------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------
// Example code:
//
// /* read configuration file */
// if (error = [ReadConfig readAppConfig:"cfg/file.cfg" target:self])
// printf("ReadConfig ERROR: %s (line %d)\n", [ReadConfig errorDescription:error],
// [ReadConfig lineNumber]);
//
// -------------------------------------------------------------------------------------
// Internal config methods:
//
// *globalMethodTrace: [ *YES | *NO ] (set global method trace mode)
// *globalPrintError: [ *YES | *NO ] (set global print error mode)
// *globalCheckReturn: [ *YES | *NO ] (set global check error return mode)
//
// *methodTrace: [ *YES | *NO ] (set debug method trace mode)
// *printError: [ *YES | *NO ] (set error message print mode)
// *checkReturn: [ *YES | *NO ] (set method return status check mode)
// *terminateOnError: [ *YES | *NO ] (terminate application on error)
//
// *print: <text string> (print text string)
// *goto: <label> (goto specified label)
// *ifTrue: <label> (if method return==YES, then goto label)
// *ifFalse: <label> (if method return==NO, then goto label)
// *terminate (terminate application)
// *alertPanel: <text string> (display alert panel with message)
// *abortPanel: <text string> (display abort panel with message)
// *optionPanel: <text string> (display A/B option select panel w message)
// *ifOptionA: <label> (if option A selected {False}, goto label)
// *ifOptionB: <label> (if option B selected {True}, goto label)
//
// *endModalPanel (end and remove modal info/stop panel)
// *infoPanel: <text string> (display info panel, no button options)
// *endInfoPanel (see 'endModalPanel')
// *stopPanel: <text string> (display stop status message panel)
// *endStopPanel (see 'endModalPanel')
// *ifStop: <label> (if stop selected, then goto label)
//
// *startProfile (start time lapse profile counter)
// *stopProfile (stop time lapse profile counter)
// *printElapsedTime (print time lapse profile counter)
//
// -------------------------------------------------------------------------------------
#import <appkit/Application.h>
// -------------------------------------------------------------------------------------
// config file macros
#define readCONFIG(F,T) [ReadConfig readAppConfig:F target:T]
#define readCfgSTORAGE(F) [ReadConfig newAppConfigStorage:F];
#define writeCfgSTORAGE(S,F) [ReadConfig writeAppConfigStorage:S toFile:F];
// -------------------------------------------------------------------------------------
#define cfgOK 0 // successful
#define cfgOPEN_ERROR 1 // file not open
#define cfgINVALID_PARMS 2 // invalid cfg parameters
#define cfgNO_METHOD 3 // no selector for method
#define cfgMETHOD_ERROR 4 // method returned error
#define cfgGOTO_LABEL 5 // goto label not found
#define cfgINVALID_CODE 6 // invalid error code specified
#define cfgSINGLE_MODE 7 // invalid format for single record mode
#define cfgBADTARGET 8 // target does not respond to method
#define cfgLAST_ERROR 8 // last error number
// -------------------------------------------------------------------------------------
#define maxLEVEL 10
// -------------------------------------------------------------------------------------
// multi-level vars
typedef struct {
FILE *fNum; // config file handle
int lineNumber; // current line number
} excLEVEL;
// -------------------------------------------------------------------------------------
@interface ReadConfig : Object
{
int level; // recursion level
excLEVEL exc[maxLEVEL]; // recursion data
id mainTarget; // original target object
NXModalSession modalSession; // status message modal session
id modalPanel; // status message modal panel
BOOL methodTrace; // debug method trace mode
BOOL printError; // print error message (if any)
BOOL checkAll; // check method return values
BOOL exitOnError; // terminate on error flag
int methodRtn; // status returned from method
char findLabel[16]; // label symbol
}
// -------------------------------------------------------------------------------------
+ (char*)appPath;
// Returns the path to the current application. The application name and extension have
// been removed.
//
// -------------------------------------------------------------------------------------
+ (char*)configPath:(const char*)fileName;
// Returns a fully qualified file name by appending the specified fileName to the
// current application path. This method uses malloc() to create a copy of the path,
// so free() must be used to deallocate the storage used by the returned name.
//
// -------------------------------------------------------------------------------------
+ (int)readConfigFile:(char*)cfgFile target:cfgTarget;
// Sends the configuration methods found in the fully qualified cfgFile to cfgTarget.
// Control is passed to the error trap method configErrorTrap:inFile:atLine: if an
// error occurs while reading cfgFile.
//
// -------------------------------------------------------------------------------------
+ (int)readAppConfig:(char*)cfgFile target:cfgTarget;
// Same as readConfigFile:target: except that cfgFile is specified relative to the
// current application directory.
//
// -------------------------------------------------------------------------------------
+ (int)sendConfigMethod:(char*)theBuffer toTarget:theTarget;
// This method parses the config record specified in theBuffer and send the method to
// theTarget. theBuffer cannot be prefaced with ':' (goto labels), '*' (internal
// ReadConfig calls), '!' (overridden checkReturns), or '/' (comments). This method
// returns cfgOK if it was successful, otherwise it return an error. Note: this method
// is not called as part of the normal file ReadConfig loop.
//
// -------------------------------------------------------------------------------------
+ (int)lineNumber;
// Returns the line number currently being processed in the config file. This may be
// useful during an error return situation to determine the line number in error.
//
// -------------------------------------------------------------------------------------
+ (int)levelNumber;
// Returns the current recursion level. This value starts out at 1, and is incremented
// each time an *include: statement begins, and decremented each time an *include:
// statement ends. The recursion level limit is 10 nested *include: statements.
//
// -------------------------------------------------------------------------------------
+ (char*)errorDescription:(int)errorCode;
// Returns the text error description for the specified error code.
//
// -------------------------------------------------------------------------------------
+ setTerminateOnError:(BOOL)yesNo;
// Set the global ReadConfig terminate-on-error flag. If set to YES, then any error
// encountered will cause the application to terminate. The default is NO.
//
// -------------------------------------------------------------------------------------
+ setPrintError:(BOOL)yesNo;
// Set the global ReadConfig print-error flag. If set to YES, then any error
// encountered will be printed to stdout. The default is NO.
//
// -------------------------------------------------------------------------------------
+ setCheckReturn:(BOOL)yesNo;
// Set the global ReadConfig check-return flag. If set to NO, then the return value
// is checked for all methods executed. Methods returning a true condition indicate
// an error condition. The default is YES.
//
// -------------------------------------------------------------------------------------
+ (int)setMethodTrace:(BOOL)yesNo;
// Set the global ReadConfig method-trace flag. If set to YES, then all method names
// which are about to be executed will be printed to stdout. The default is NO.
//
// -------------------------------------------------------------------------------------
+ setErrorTrap:target;
// Set the target which is to receive the configErrorTrap:inFile:atLine: method when
// an error is encountered. Default is self.
//
// -------------------------------------------------------------------------------------
+ configErrorTrap:(int)errCode inFile:(char*)fileName atLine:(int)lineNbr;
// This is the default error handler if no '+setErrorTrap:' method is issued.
//
// -------------------------------------------------------------------------------------
+ newConfigStorage:(char*)fileName;
// Reads the contents of the file fileName and place each record as an entry in a
// storage object. This storage object is used by replaceRecord:inCfgStorage: to
// allow replace configuration file records.
//
// -------------------------------------------------------------------------------------
+ newAppConfigStorage:(char*)fileName;
// Same as newConfigStorage: except that the fileName is referenced relative to the
// current application directory.
//
// -------------------------------------------------------------------------------------
+ (int)findIndexForMethodName:(char*)methName inCfgStorage:theStorage;
// Returns the element index in theStorage for the record beginning with the method
// name methName.
//
// -------------------------------------------------------------------------------------
+ replaceRecord:(char*)theRecord inCfgStorage:theStorage;
// This method searches for the occurrance of the method name found at the beginning of
// theRecord and replaces its occurrance in theStorage if found.
//
// -------------------------------------------------------------------------------------
+ writeConfigStorage:theStorage toFile:(char*)fileName;
// This method writes the contents of theStorage to the fully qualified fileName.
//
// -------------------------------------------------------------------------------------
+ writeAppConfigStorage:theStorage toFile:(char*)fileName;
// Same as writeConfigStorage:toFile: except that fileName is referenced relative to
// the current application directory.
//
// -------------------------------------------------------------------------------------
+ freeConfigStorage:theStorage;
// Frees the storage allocated by theStorage.
//
// -------------------------------------------------------------------------------------
+ printConfigStorage:theStorage;
// Prints the text data records found in theStorage to stdout. May be used for
// debugging purposes.
//
// -------------------------------------------------------------------------------------
+ setProfileTarget:theProfileTarget;
// During active elapsed time profiling, the method 'profileElapsedTime:' will be sent
// to the theProfileTarget whenever ReadConfig regains control after each config file
// method executed. theProfileTarget must respond to the method 'profileElapsedTime:',
// otherwise theProfileTarget is ignored. If no profile has been set by the time that
// '*startProfile' is executed then 'setProfileTarget:' is implicitly called with NXApp
// as the default target.
//
// -------------------------------------------------------------------------------------
+ (float)profileElapsedTime;
// Returns the elapsed time between the commands '*startProfile' and '*stopProfile'. If
// time profiling is still active then the elapsed time since the last '*startProfile'
// is returned. The return time is in seconds.
//
// -------------------------------------------------------------------------------------
+ (int)profileCount;
// Returns the number of methods executed by ReadConfig between the commands
// '*startProfile' and '*stopProfile'. If time profiling is still active then the
// number of executed methods since the last '*startProfile' is returned. This count
// does not included '*' command methods sent directly to ReadConfig itself.
//
// -------------------------------------------------------------------------------------
+ startProfile;
// Executes the ReadConfig command '*startProfile'.
//
// -------------------------------------------------------------------------------------
+ stopProfile;
// Executes the ReadConfig command '*stopProfile'.
//
// -------------------------------------------------------------------------------------
@end