home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Source / MiscMergeKit / MiscMergeDriver.m < prev    next >
Encoding:
Text File  |  1995-07-08  |  7.6 KB  |  209 lines

  1. //
  2. //    MiscMergeDriver.m -- a simple loop for driving bulk merges
  3. //        Written by Don Yacktman Copyright (c) 1995 by Don Yacktman.
  4. //                Version 1.0.  All rights reserved.
  5. //        This notice may not be removed from this source code.
  6. //
  7. //    This object is included in the MiscKit by permission from the author
  8. //    and its use is governed by the MiscKit license, found in the file
  9. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  10. //    for a list of all applicable permissions and restrictions.
  11. //    
  12.  
  13. #import <misckit/misckit.h>
  14. #import <misckit/miscmerge.h>
  15.  
  16. @implementation MiscMergeDriver
  17. /*" A MiscMergeDriver is used to merge an ASCII template with
  18. several dictionaries filled with key/value pairs.  Each dictionary
  19. will be used in turn to generate a new output “document”.
  20.  
  21. If you only need to generate a single merge, you may wish to
  22. simply use a MiscMergeEngine object.  If you have several
  23. merges to perform, then a MiscMergeDriver implements the
  24. required loop to generate the required merges, as well as
  25. supporting a protocol that allows the merge engine some
  26. control over the loop.  If you create your own loop, instead
  27. of using a MiscMergeDriver instance, some
  28. of the merge commands such as “next” will be ignored rather
  29. than performing the desired function.
  30.  
  31. To use a MiscMergeDriver you must provide it with a template,
  32. dictionaries to merge into the template, and, optionally, a
  33. MiscMergeEngine instance.  If a MiscMergeEngine is  not provided,
  34. one will be created to perform the merge.  To set up a merge
  35. template, use the -#{setTemplate:} method.  It expects an instance
  36. of the MiscMergeTemplate class, which comes from an ASCII file or
  37. from a MiscString object.
  38.  
  39. The data to be merged into the template
  40. is set up using the -#{setMergeData:} method.  The data should be
  41. stored as key/value pairs in a MiscDictionary object for each
  42. merge to be performed.  Place all the dictionaries into a List
  43. object and use the List object as the argument to -#{setMergeData:}.
  44.  
  45. Finally, use the -#{doMerge:} method to perform the desired
  46. merge operation.  The results will be returned as a List
  47. object with a MiscString corresponding to each MiscDictionary
  48. in the List provided to the MiscMergeDriver by the most recent -#{setData:}
  49. message.  For example, the third MiscString will contain the
  50. results from the merge with the third MiscDictionary.  If
  51. the Merge returned no result (due to an error or an “omit”
  52. command, for example) then the MiscString will be empty.
  53.  
  54. If you wish to use a specific subclass of MiscMergeEngine to
  55. perform the merge, then use the -#{setEngine:} method to set
  56. up the engine before calling -#{doMerge:}.  This engine will
  57. be used for all subsequent merges unless -#{setEngine:} is sent again.
  58.  
  59. For more information, please see the IntroMiscMerge.rtfd document.
  60. It describes the syntax of the merge language and built-in
  61. commands available.  The MiscMergeArchitecture.rtfd document
  62. describes the architecutre of the various classes used to
  63. perform merging operations and how to add custom commands to
  64. the framework.
  65. "*/
  66.  
  67. - (MiscMergeEngine *)engine
  68. /*" Returns the merge engine, an instance of MiscMergeEngine,
  69. that will be used to perform a merge.  If no engine has been
  70. set up, then nil is returned.
  71. "*/
  72. {
  73.     return engine;
  74. }
  75.  
  76. - (List *)mergeData
  77. /*" Returns the List of MiscDictionaries that will be used for the next merge.
  78. "*/
  79. {
  80.     return dictionaries;
  81. }
  82.  
  83. - (MiscMergeTemplate *)template
  84. /*" Returns the MiscMergeTemplate that will be used for the next merge.
  85. "*/
  86. {
  87.     return template;
  88. }
  89.  
  90. - setTemplate:aTemplate
  91. /*" Sets the MiscMergeTemplate that will be used for the next merge.
  92. Returns self upon success and nil upon failure.  This method fails if a
  93. merge is in progress.
  94. "*/
  95. { // we don't free the old -- watch for memory leaks!
  96.     if (merging) return nil;
  97.     template = aTemplate;
  98.     return self;
  99. }
  100.  
  101. - setMergeData:(List *)aList
  102. /*" Sets the List of MiscDictionaries that will be used for the next merge.
  103. Returns self upon success and nil upon failure.  This method fails if a
  104. merge is in progress.
  105. "*/
  106. { // we don't free the old -- watch for memory leaks!
  107.     if (merging) return nil;
  108.     dictionaries = aList;
  109.     return self;
  110. }
  111.  
  112. - (List *)doMerge:sender
  113. /*" Sets up a merge engine, if necessary, and performs a merge of
  114. the template with the MiscDictionaries in the data List.  Any
  115. engines created will be destroyed after the merge; engines set
  116. using -#{setEngine} will persist, however.  A List object populated
  117. with MiscStrings will be returned.  There is a one-to-one correspondence
  118. between the index of the return MiscStrings in the List and the
  119. MiscDictionaries' indices in the List that was provided via the
  120. most recent -#{setMergeData}.  Thus, if there were six dictionaries
  121. used for merging, six MiscStrings will be returned, as the result
  122. of six merges.  Note that the “next” command will cause a MiscMergeEngine
  123. to attempt to skip forward to the next MiscDictionary, while still
  124. performing a single merge.  In this case, an empty MiscString will
  125. be inserted in the output List as a placeholder and the final
  126. merge result will be put in the slot corresponding to the last
  127. dictionary used.  Merges that fail or are halted due to an “omit”
  128. command will also be represented by an empty MiscString in the output.
  129. "*/
  130. { // YOU have to free the returned list.
  131.     BOOL createdEngine = NO;
  132.  
  133.     if (merging) return nil; // not re-entrant!!!
  134.     if (!template || !dictionaries) return nil;
  135.     if ([dictionaries count] < 1) return nil;
  136.     if (!engine) {
  137.         createdEngine = YES;
  138.         engine = [MiscMergeEngine newWithTemplate:template];
  139.     }
  140.  
  141.     merging = YES;
  142.     output = [[List alloc] init];
  143.     for (_mergeLoopIndex=0; _mergeLoopIndex<[dictionaries count];
  144.             _mergeLoopIndex++) {
  145.         id ret = [engine mergeWithDictionary:
  146.                 [dictionaries objectAt:_mergeLoopIndex]
  147.                 sender:self];
  148.         while (_mergeLoopIndex > [output count]) {
  149.             [output addObject:[MiscString new]]; // placeholder for skipped
  150.         }
  151.         if (ret) [output addObject:ret];
  152.         else [output addObject:[MiscString new]]; // placeholder if failed
  153.     }
  154.     if (createdEngine) { // don't keep it hanging around
  155.         [engine free];
  156.         engine = nil;
  157.     }
  158.     merging = NO;
  159.     return output;
  160. }
  161.  
  162. - setEngine:(MiscMergeEngine *)anEngine
  163. /*" Sets up an engine to be used for merging.  If no engine is set, a
  164. temporary engine will be created before and used during a merge.  It
  165. will be destroyed after it is used.  Engines set using -#{setEngine:}
  166. will not be destroyed at the end of a merge and will be used for
  167. subsequent merges as well.  Setting a new engine will not free the
  168. old engine; the MiscMergeDriver does not “own” the engine; it only
  169. makes use of it.  This way, the same engine could be used by several
  170. MiscMergeDriver instances.  Setting the engine to nil will revert to
  171. the default create/use/destroy pattern.  The engine cannot be changed
  172. while a merge loop is in progress.  Returns self if successful or
  173. nil if failure occurs.
  174. "*/
  175. {
  176.     if (!merging) {
  177.         engine = anEngine;
  178.         return self;
  179.     } else {
  180.         return nil;
  181.     }
  182. }
  183.  
  184. // Methods required by the MiscMergeDriver protocol
  185.  
  186. // Advance merge loop and return the next dictionary, nil if no more left
  187. - advanceMergeLoop
  188. /*" During a merge, returns the next dictionary that will be merged and advances the merge loop.  Returns nil if not merging or if the loop is
  189. already performing the last merge.
  190. "*/
  191. {
  192.     if ((!merging) || (_mergeLoopIndex >= [dictionaries count])) return nil;
  193.     _mergeLoopIndex++;
  194.     if (_mergeLoopIndex >= [dictionaries count]) return nil;
  195.     return [dictionaries objectAt:_mergeLoopIndex];
  196. }
  197.  
  198. - currentDictionary
  199. /*" During a merge, returns the dictionary that is currently being merged.
  200. Returns nil otherwise.
  201. "*/
  202. {
  203.     if (!merging) return nil;
  204.     if (_mergeLoopIndex >= [dictionaries count]) return nil;
  205.     return [dictionaries objectAt:_mergeLoopIndex];
  206. }
  207.  
  208. @end
  209.