home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / Classes / SampleClasses / ReadConfig.h < prev    next >
Text File  |  1992-08-04  |  18KB  |  311 lines

  1. // -------------------------------------------------------------------------------------
  2. // ReadConfig.m - Read/Execute run-time configuration file.
  3. // Author: Martin D. Flynn, NeXT Computer, Inc.
  4. // Description:
  5. // This class provides a general solution to applications that require run-time
  6. // configuration.  A configuration file name can be passed to the method name:
  7. //             readConfigFile:target:
  8. // The file will be parsed and interpreted as method names and arguments to send to the
  9. // specified target.  Methods requiring no-arguments, or one-argument, are allowed.
  10. // The class also contains some primitive branching controls to provide a simple contol
  11. // language.
  12. // -------------------------------------------------------------------------------------
  13. // Permission is granted to freely redistribute this source code, and to use fragments
  14. // of this code in your own applications if you find them to be useful.  This class,
  15. // along with the source code, come with no warranty of any kind, and the user assumes
  16. // all responsibility for its use.
  17. // -------------------------------------------------------------------------------------
  18. // Notes:
  19. //   - Do NOT instantiate this object. It will instantiate a temporary copy of itself.
  20. //   - Comment lines start with (' ', '\n', '\t', or '/') in the first column.
  21. //   - A label is prefaced with a ':' (ie. ':Label').
  22. //   - Method return status is 0 for success, error otherwise.
  23. //   - Methods prefaced with '!' will skip return status checking for that method.
  24. //   - A method with no parameter is allowed.
  25. //   - If the target method responds to 'configWillPerform:with:', then this method will
  26. //     will be sent to the target prior to each config method sent.  If
  27. //     'configWillPerform:with:' returns true, then the config method will also be sent,
  28. //     otherwise it will be skipped.
  29. //   - Internal methods are prefaced with a '*' (internal methods listed below).
  30. //   - The configuration read will be terminated when an error is encountered.
  31. //   - [ReadConfig lineNumber] will return the last executed line.
  32. //   - '*checkReturn: *NO' must be set prior to using '*ifTrue: lbl' or '*ifFalse: lbl'
  33. //   - Method names may end with a '$' followed by any character.  This will be stripped
  34. //     prior to calling the method. (this is used for updating config files)
  35. //   - If time lapse profiling has been activated, then after each config file method
  36. //     executed, when ReadConfig regains control, the method 'profileTimeLapse:' will be
  37. //   - sent to the global
  38. //   - Reserved parameter options:
  39. //      *nil = pass a nil pointer to method
  40. //      *YES = pass boolean YES to method
  41. //      *NO  = pass boolean NO to method
  42. //      *id  = pass id created with *newId to method
  43. // -------------------------------------------------------------------------------------
  44. // Example config:
  45. //
  46. //      // -----------------------------------------------------------------------------
  47. //      // set ReadConfig modes
  48. //      *methodTrace:           *YES
  49. //      *printError:            *YES
  50. //      // -----------------------------------------------------------------------------
  51. //      // open and recalc data
  52. //      *print:                 openning data file
  53. //      myOpenData:             data/myData.file
  54. //      *print:                 recalculating info
  55. //      *checkReturn:           *NO
  56. //      recalcInfo              *nil
  57. //      *ifTrue:                returnTrue
  58. //      *print:                 recalcInfo returned False
  59. //      *goto:                  skip
  60. //      :returnTrue
  61. //      *print:                 recalcInfo returned True
  62. //      showErrorPanel
  63. //      :skip
  64. //      // -----------------------------------------------------------------------------
  65. //      // option selection panel
  66. //      *optionPanel:           select A or B
  67. //      *ifFalse:               selectA
  68. //      *print:                 you selected B
  69. //      *goto:                  endSelect
  70. //      :selectA
  71. //      *print:                 your selected A
  72. //      :endSelect
  73. //      // -----------------------------------------------------------------------------
  74. //
  75. // -------------------------------------------------------------------------------------
  76. // Example code:
  77. //
  78. //      /* read configuration file */
  79. //      if (error = [ReadConfig readAppConfig:"cfg/file.cfg" target:self])
  80. //        printf("ReadConfig ERROR: %s (line %d)\n", [ReadConfig errorDescription:error],
  81. //                [ReadConfig lineNumber]);
  82. //
  83. // -------------------------------------------------------------------------------------
  84. // Internal config methods:
  85. //
  86. //      *globalMethodTrace:     [ *YES | *NO ]  (set global method trace mode)
  87. //      *globalPrintError:      [ *YES | *NO ]  (set global print error mode)
  88. //      *globalCheckReturn:     [ *YES | *NO ]  (set global check error return mode)
  89. //
  90. //      *methodTrace:           [ *YES | *NO ]  (set debug method trace mode)
  91. //      *printError:            [ *YES | *NO ]  (set error message print mode)
  92. //      *checkReturn:           [ *YES | *NO ]  (set method return status check mode)
  93. //      *terminateOnError:      [ *YES | *NO ]  (terminate application on error)
  94. //
  95. //      *print:                 <text string>   (print text string)
  96. //      *goto:                  <label>         (goto specified label)
  97. //      *ifTrue:                <label>         (if method return==YES, then goto label)
  98. //      *ifFalse:               <label>         (if method return==NO, then goto label)
  99. //      *terminate                              (terminate application)
  100. //      *alertPanel:            <text string>   (display alert panel with message)
  101. //      *abortPanel:            <text string>   (display abort panel with message)
  102. //      *optionPanel:           <text string>   (display A/B option select panel w message)
  103. //      *ifOptionA:             <label>         (if option A selected {False}, goto label)
  104. //      *ifOptionB:             <label>         (if option B selected {True}, goto label)
  105. //
  106. //      *endModalPanel                          (end and remove modal info/stop panel)
  107. //      *infoPanel:             <text string>   (display info panel, no button options)
  108. //      *endInfoPanel                           (see 'endModalPanel')
  109. //      *stopPanel:             <text string>   (display stop status message panel)
  110. //      *endStopPanel                           (see 'endModalPanel')
  111. //      *ifStop:                <label>         (if stop selected, then goto label)
  112. //
  113. //      *startProfile                           (start time lapse profile counter)
  114. //      *stopProfile                            (stop time lapse profile counter)
  115. //      *printElapsedTime                       (print time lapse profile counter)
  116. //
  117. // -------------------------------------------------------------------------------------
  118. #import <appkit/Application.h>
  119.  
  120. // -------------------------------------------------------------------------------------
  121. // config file macros
  122. #define readCONFIG(F,T)         [ReadConfig readAppConfig:F target:T]
  123. #define readCfgSTORAGE(F)       [ReadConfig newAppConfigStorage:F];
  124. #define writeCfgSTORAGE(S,F)    [ReadConfig writeAppConfigStorage:S toFile:F];
  125.  
  126. // -------------------------------------------------------------------------------------
  127. #define cfgOK                   0       // successful
  128. #define cfgOPEN_ERROR           1       // file not open
  129. #define cfgINVALID_PARMS        2       // invalid cfg parameters
  130. #define cfgNO_METHOD            3       // no selector for method
  131. #define cfgMETHOD_ERROR         4       // method returned error
  132. #define cfgGOTO_LABEL           5       // goto label not found
  133. #define cfgINVALID_CODE         6       // invalid error code specified
  134. #define cfgSINGLE_MODE          7       // invalid format for single record mode
  135. #define cfgBADTARGET            8       // target does not respond to method
  136. #define cfgLAST_ERROR           8       // last error number
  137.  
  138. // -------------------------------------------------------------------------------------
  139. #define maxLEVEL                10
  140.  
  141. // -------------------------------------------------------------------------------------
  142. // multi-level vars
  143. typedef struct {
  144.   FILE                  *fNum;                  // config file handle
  145.   int                   lineNumber;             // current line number
  146. } excLEVEL;
  147.  
  148. // -------------------------------------------------------------------------------------
  149. @interface ReadConfig : Object
  150. {
  151.   int                   level;                  // recursion level
  152.   excLEVEL              exc[maxLEVEL];          // recursion data
  153.   id                    mainTarget;             // original target object
  154.   NXModalSession        modalSession;           // status message modal session
  155.   id                    modalPanel;             // status message modal panel
  156.   BOOL                  methodTrace;            // debug method trace mode
  157.   BOOL                  printError;             // print error message (if any)
  158.   BOOL                  checkAll;               // check method return values
  159.   BOOL                  exitOnError;            // terminate on error flag
  160.   int                   methodRtn;              // status returned from method
  161.   char                  findLabel[16];          // label symbol
  162. }
  163.   
  164. // -------------------------------------------------------------------------------------
  165. + (char*)appPath;
  166. //  Returns the path to the current application.  The application name and extension have
  167. //  been removed.
  168. //
  169. // -------------------------------------------------------------------------------------
  170. + (char*)configPath:(const char*)fileName;
  171. //  Returns a fully qualified file name by appending the specified fileName to the
  172. //  current application path.  This method uses malloc() to create a copy of the path,
  173. //  so free() must be used to deallocate the storage used by the returned name.
  174. //
  175. // -------------------------------------------------------------------------------------
  176. + (int)readConfigFile:(char*)cfgFile target:cfgTarget;
  177. //  Sends the configuration methods found in the fully qualified cfgFile to cfgTarget.
  178. //  Control is passed to the error trap method configErrorTrap:inFile:atLine: if an
  179. //  error occurs while reading cfgFile. 
  180. //
  181. // -------------------------------------------------------------------------------------
  182. + (int)readAppConfig:(char*)cfgFile target:cfgTarget;
  183. //  Same as readConfigFile:target: except that cfgFile is specified relative to the
  184. //  current application directory.
  185. //
  186. // -------------------------------------------------------------------------------------
  187. + (int)sendConfigMethod:(char*)theBuffer toTarget:theTarget;
  188. //  This method parses the config record specified in theBuffer and send the method to
  189. //  theTarget.  theBuffer cannot be prefaced with ':' (goto labels), '*' (internal
  190. //  ReadConfig calls), '!' (overridden checkReturns), or '/' (comments).  This method
  191. //  returns cfgOK if it was successful, otherwise it return an error.  Note: this method
  192. //  is not called as part of the normal file ReadConfig loop.
  193. //
  194. // -------------------------------------------------------------------------------------
  195. + (int)lineNumber;
  196. //  Returns the line number currently being processed in the config file.  This may be
  197. //  useful during an error return situation to determine the line number in error.
  198. //
  199. // -------------------------------------------------------------------------------------
  200. + (int)levelNumber;
  201. //  Returns the current recursion level.  This value starts out at 1, and is incremented
  202. //  each time an *include: statement begins, and decremented each time an *include:
  203. //  statement ends.  The recursion level limit is 10 nested *include: statements.
  204. //
  205. // -------------------------------------------------------------------------------------
  206. + (char*)errorDescription:(int)errorCode;
  207. //  Returns the text error description for the specified error code.
  208. //
  209. // -------------------------------------------------------------------------------------
  210. + setTerminateOnError:(BOOL)yesNo;
  211. //  Set the global ReadConfig terminate-on-error flag.  If set to YES, then any error
  212. //  encountered will cause the application to terminate.  The default is NO.
  213. //
  214. // -------------------------------------------------------------------------------------
  215. + setPrintError:(BOOL)yesNo;
  216. //  Set the global ReadConfig print-error flag.  If set to YES, then any error
  217. //  encountered will be printed to stdout.  The default is NO.
  218. //
  219. // -------------------------------------------------------------------------------------
  220. + setCheckReturn:(BOOL)yesNo;
  221. //  Set the global ReadConfig check-return flag.  If set to NO, then the return value
  222. //  is checked for all methods executed.  Methods returning a true condition indicate
  223. //  an error condition.  The default is YES.
  224. //
  225. // -------------------------------------------------------------------------------------
  226. + (int)setMethodTrace:(BOOL)yesNo;
  227. //  Set the global ReadConfig method-trace flag.  If set to YES, then all method names
  228. //  which are about to be executed will be printed to stdout.  The default is NO.
  229. //
  230. // -------------------------------------------------------------------------------------
  231. + setErrorTrap:target;
  232. //  Set the target which is to receive the configErrorTrap:inFile:atLine: method when
  233. //  an error is encountered.  Default is self.
  234. //
  235. // -------------------------------------------------------------------------------------
  236. + configErrorTrap:(int)errCode inFile:(char*)fileName atLine:(int)lineNbr;
  237. //  This is the default error handler if no '+setErrorTrap:' method is issued.
  238. //
  239. // -------------------------------------------------------------------------------------
  240. + newConfigStorage:(char*)fileName;
  241. //  Reads the contents of the file fileName and place each record as an entry in a 
  242. //  storage object.  This storage object is used by replaceRecord:inCfgStorage: to 
  243. //  allow replace configuration file records.
  244. //
  245. // -------------------------------------------------------------------------------------
  246. + newAppConfigStorage:(char*)fileName;
  247. //  Same as newConfigStorage: except that the fileName is referenced relative to the 
  248. //  current application directory.
  249. //
  250. // -------------------------------------------------------------------------------------
  251. + (int)findIndexForMethodName:(char*)methName inCfgStorage:theStorage;
  252. //  Returns the element index in theStorage for the record beginning with the method
  253. //  name methName.
  254. //
  255. // -------------------------------------------------------------------------------------
  256. + replaceRecord:(char*)theRecord inCfgStorage:theStorage;
  257. //  This method searches for the occurrance of the method name found at the beginning of
  258. //  theRecord and replaces its occurrance in theStorage if found.
  259. //
  260. // -------------------------------------------------------------------------------------
  261. + writeConfigStorage:theStorage toFile:(char*)fileName;
  262. //  This method writes the contents of theStorage to the fully qualified fileName.
  263. //
  264. // -------------------------------------------------------------------------------------
  265. + writeAppConfigStorage:theStorage toFile:(char*)fileName;
  266. //  Same as writeConfigStorage:toFile: except that fileName is referenced relative to
  267. //  the current application directory.
  268. //
  269. // -------------------------------------------------------------------------------------
  270. + freeConfigStorage:theStorage;
  271. //  Frees the storage allocated by theStorage.
  272. //
  273. // -------------------------------------------------------------------------------------
  274. + printConfigStorage:theStorage;
  275. //  Prints the text data records found in theStorage to stdout.  May be used for 
  276. //  debugging purposes.
  277. //
  278. // -------------------------------------------------------------------------------------
  279. + setProfileTarget:theProfileTarget;
  280. //  During active elapsed time profiling, the method 'profileElapsedTime:' will be sent
  281. //  to the theProfileTarget whenever ReadConfig regains control after each config file
  282. //  method executed.  theProfileTarget must respond to the method 'profileElapsedTime:',
  283. //  otherwise theProfileTarget is ignored.  If no profile has been set by the time that
  284. //  '*startProfile' is executed then 'setProfileTarget:' is implicitly called with NXApp
  285. //  as the default target.
  286. //
  287. // -------------------------------------------------------------------------------------
  288. + (float)profileElapsedTime;
  289. //  Returns the elapsed time between the commands '*startProfile' and '*stopProfile'.  If
  290. //  time profiling is still active then the elapsed time since the last '*startProfile'
  291. //  is returned.  The return time is in seconds. 
  292. //
  293. // -------------------------------------------------------------------------------------
  294. + (int)profileCount;
  295. //  Returns the number of methods executed by ReadConfig between the commands
  296. //  '*startProfile' and '*stopProfile'.  If time profiling is still active then the
  297. //  number of executed methods since the last '*startProfile' is returned.  This count
  298. //  does not included '*' command methods sent directly to ReadConfig itself.
  299. //
  300. // -------------------------------------------------------------------------------------
  301. + startProfile;
  302. //  Executes the ReadConfig command '*startProfile'.
  303. //
  304. // -------------------------------------------------------------------------------------
  305. + stopProfile;
  306. //  Executes the ReadConfig command '*stopProfile'.
  307. //
  308. // -------------------------------------------------------------------------------------
  309.  
  310. @end
  311.