home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 2: PC / frozenfish_august_1995.bin / bbs / d09xx / d0938.lha / Angie / ImportedModules.lha / BlackMagic.mod next >
Text File  |  1993-10-21  |  168KB  |  4,624 lines

  1. (* ------------------------------------------------------------------------
  2.   :Program.       BlackMagic.mod
  3.   :Contents.      Versatile, powerful module for GUIs, WBench Interfacing,
  4.   :Contents.      Dynamic Strings, Localization, and more.
  5.   :Author.        Franz Schwarz
  6.   :Copyright.     Giftware (Freely distributable, yet copyrighted software.
  7.   :Copyright.     If you like this magnificent;-) piece of software, you
  8.   :Copyright.     are encouraged to send the author a present, a nice
  9.   :Copyright.     postcard, money, or something else pleasing the author.)
  10.   :Copyright.     Free use in Freely Distributable stuff (but gimme credit)
  11.   :Copyright.     Explicit confirmation needed for use in commercial code
  12.   :Language.      Oberon-2
  13.   :Translator.    Amiga Oberon 3.00
  14.   :Support.       reqtools.library V38+ -which is ⌐ by Nico Franτois- is 
  15.   :Support.       needed for the 'Arguments Request' feature of ReadArgs**()
  16.   :History.       BlackMagic.mod 1.0 (24.6.93) [fSchwarz] initial release
  17.   :History.       1.1 (2.7.93) [fSchwarz] added GadKey()/GadKeyA()
  18.   :History.       1.2 (6.7.93) [fSchwarz] added Max2()/Min2() and 
  19.   :History.                               VisibleOfScreen()
  20.   :History.       1.3 (6.7.93) [fSchwarz] removed EasyRequest(Args)(),
  21.   :History.         added SimpleRequest() / SimpleRequestArgs()
  22.   :History.       1.4 (9.7.93) [fSchwarz] added Dos.IoErr support 
  23.   :History.         for ReadArgs*(), added CmpToolNames(), ToolNameLen(),
  24.   :History.         GetToolValue(), WriteTTEntry(), FLPrintf(), FLPrintF(),
  25.   :History.         VFLPrintF(), Strlastn(i)cmp(), fixed minor bugs
  26.   :History.       1.5 (20.7.93) [fSchwarz] moved varargs stuff to own
  27.   :History.         module BlackMagicVA, removed reqtools stuff,
  28.   :History.         added ClearMem() / ClearMemAPTR()
  29.   :History.       1.6 (25.7.93) [fSchwarz] changed DynamicExtra to be
  30.   :History.         variable and accessable from other modules.
  31.   :History.         added external access toDynamicExtra, changed
  32.   :History.         DynExpand() to use Exec.CopyMem() and copy whole
  33.   :History.         array.
  34.   :History.       1.7 (27.7.93) [fSchwarz] added GetTTYScreen(), fixed
  35.   :History.         BlackMagicVA <-> BlackMagic layout
  36.   :History.       1.8 (6.8.93) [fSchwarz] fixed GetTTYScreen()
  37.   :History.       1.9 (9.8.93) [fSchwarz] now really exports DynInsert()
  38.   :History.         fixed bug that kept ReadArgsWBMsg(), ReadArgsWB() &
  39.   :History.         ReadArgs from processing any template if none of the
  40.   :History.         flags argFile / argFiles was specified. This bug kept
  41.   :History.         RDArgsWB.ttRest() from beeing filled with ToolTypes
  42.   :History.         on empty ("") templates passed to ReadArgsTT()
  43.   :History.       1.10 (14.8.93) [fSchwarz] introduced TRAILBLAZING
  44.   :History.         'Arguments Request' concept to ReadArgs**() 
  45.   :History.         with localization support, extended DynAppendTT() and
  46.   :History.         WriteTTEntry().
  47.   :History.       1.11 (22.9.93) [fSchwarz] added ScrVPExtra() function
  48.   :History.       1.12 (30.9.93) [fSchwarz] adapted to OS3.0 interface
  49.   :History.         modules by hartmut Goebel, changed (Un)LockWindow()
  50.   :History.       1.13 (13.10.93) [fSchwarz] fixed WriteTTEntry() bug
  51.   :History.          when appending noNulTerm arrays, added DynInsertTT()
  52.   :Address.       Mⁿhlenstra▀e 2, D-78591 Durchhausen, Germany / R.F.A.
  53.   :Address.       uucp: Franz.Schwarz@mil.ka.sub.org; Fido: 2:241/7506.18
  54.   :Remark.        Requires OS3.0 interface modules update by hartmut Goebel
  55.   :Remark.        Don't be afraid of this module's extent: OLink supports
  56.   :Remark.        selective linking - so only functions that you use are
  57.   :Remark.        included into your code.
  58.   :Remark.        As of Amiga Oberon Release 3.00: possible odd pointers to
  59.   :Remark.        array of char/byte: _don't_ compile with OddChk. The
  60.   :Remark.        compiler's options stack is broken as of Amiga-Oberon 3.00
  61. --------------------------------------------------------------------------- *)
  62.  
  63. (* $SET NODEBUG *)
  64.  
  65. MODULE BlackMagic;
  66.  
  67. (****** BlackMagic/--overview-- ***********************************************
  68. *
  69. *       BlackMagic is a very versatile module designed for your relief
  70. *   when dealing with Graphical User Interfaces, Workbench Interfacing,
  71. *   dynamic-length strings, Localization, and more. Its Workbench argument
  72. *   parsing functions are unique in the Amiga community, yet. In fact, it 
  73. *   provides you with all the flexibility and power of Dos.ReadArgs() 
  74. *   argument parsing while keeping up to the Workbench ToolTypes
  75. *   design as stated in the Amiga User Interface Style Guide. It
  76. *   also takes care of project ToolTypes overriding corresponding
  77. *   tool ToolTypes entries. A trailblazing new feature that is only
  78. *   available if your system runs reqtools.library V38 or higher (which
  79. *   is ⌐ Nico Franτois) is the 'Argument Request' feature of the 
  80. *   ReadArgs**() functions, i.e. BlackMagic will pop up localized requesters
  81. *   that request either all, required or user-definable argument entries
  82. *   from the user. As an intended side effect of these functions , the parse
  83. *   functions may also be alienated from their main purpose by making
  84. *   them operate as inclusion- and/or exclusion-filters. For this
  85. *   very purpose, a new dynamic ToolType array datatype has been
  86. *   introduced for easy manipulation of the filtered ToolTypes. Similar
  87. *   to the concept of dynamic ToolType arrays, a dynamic String type has
  88. *   been introduced. As opposed to the one defined in the STRING Oberon-2
  89. *   support module supplied with the Amiga compiler, this one does not 
  90. *   require a garbage collector for resource deallocation. Both, the 
  91. *   dynamic ToolType array type as well as the dynamic String type are
  92. *   implemented using the new open array concept introduced in Oberon-2.
  93. *   There's another function which converts simple CLI arguments or a
  94. *   string into a ToolType array you can manipulate with this module's
  95. *   functions. 
  96. *   Furthermore two functions (ReadArgs()/FreeArgs()) have been made 
  97. *   available to the user, that provide a uniform interface to the Oberon
  98. *   program's arguments no matter whether the program was started from
  99. *   CLI or Workbench.
  100. *   For your ease when dealing with the Operating System, functions for
  101. *   string type conversion (LongStrPtr/Exec.STRPTR/ARRAY OF CHAR-Index
  102. *   conversion functions) as well as a general pointer arithmetics
  103. *   support functions have been supplied.  
  104. *   Another field of functions, BlackMagic provides, are sprintf()-like 
  105. *   functions for both, simple strings, as well as for the dynamic string
  106. *   type of this module - and all of them provide real varargs argument
  107. *   passing for the programmers ease, of course. Especially the varargs
  108. *   dynamic string sprintf()-pendant DynAppendFmt()/DSPrintf() is all you
  109. *   always missed in Amiga- Oberon, but never dared to think of in your
  110. *   wildest dreams (yeah, you'll be nuts about it, when you'll use
  111. *   DynAppendFmt()/DSPrintf() for your fist time, too;-)). After all,
  112. *   as a bonus, locale.library's FormatString() front ends (var/vector args)
  113. *   for dynamic strings are present, too - and they work without locale
  114. *   librray, too (fallback to DSPrintf()).
  115. *   Amongst BlackMagic's repertoire, there are functions for locking
  116. *   windows, setting busy pointers, functions for easy retrieval of menus
  117. *   and menu items that were created from GadTools/CreateMenusA(), and Last
  118. *   but not least, versatile and brief support functions for localization/
  119. *   catalogs with an appertaining ARexx script to convert catalog definition
  120. *   files (#?.cd) into the necessary Oberon source with string constants 
  121. *   definitions.
  122. *
  123. *   Two final notes: First, in this documentation, the term <function> is
  124. *   always used as a synonym for <procedure>.
  125. *   Finally, some implementation details: BlackMagic's Arguments parsing
  126. *   functions are implemented heavily using OOP (Object Orientated
  127. *   Programming) techniques like type-bound functions, inheritance of
  128. *   methods and dynamic binding.
  129. *
  130. *****************************************************************************)
  131.  
  132. (****** BlackMagic/--legal-- **************************************************
  133. *
  134. *   LEGAL STATUS
  135. *       BlackMagic is Giftware, Copyright ⌐ 1993 by F.Schwarz.  All
  136. *       Rights reserved.  Giftware is an abbreviation for Freely
  137. *       Distributable Copyrighted Software (i.e.  Freeware).  Moreover
  138. *       the author requests a gift like a small present, money, gold,
  139. *       disks, beer, chocolate, nice postcards, or at least an email
  140. *       from people appreciating or using this software product and
  141. *       other nice boys and girls that want to please the author.  You
  142. *       are encouraged to freely distribute this software for
  143. *       non-profit-making purposes, and use it in your own freely
  144. *       distributable software.  However if you intend to use it in
  145. *       commercial software or shareware you may only use it under the
  146. *       condition that you consider me to be a registered, legitimate
  147. *       user of that software _and in case of commercial software_ under
  148. *       the additional condition that you ask me for explicit permission
  149. *       to include this software in your product.
  150. *       
  151. *   DISCLAIMER
  152. *       Liability - what liability?? In fact, no liability whatsoever is
  153. *       provided by the author of this software - this is generally known
  154. *       as "USE AT YOUR OWN RISK" - and that is exactly what it means.
  155. *
  156. *   DISTRIBUTION
  157. *       This software may be distributed if only a _reasonable_ copying
  158. *       fee is charged apart from the consts for the media it is copied to.
  159. *       Furthermore, it may be included in Freely Distributable software
  160. *       libraries like AMOK, etc, including CD-ROM versions of them.
  161. *    
  162. *   Contact addresses for bug reports, comments, inquiries or anything else:
  163. *
  164. *          Mⁿhlenstra▀e 2, D-78591 Durchhausen, Germany / R.F.A.
  165. *     email: uucp: Franz.Schwarz@mil.ka.sub.org; Fido: 2:241/7506.18
  166. *
  167. *****************************************************************************)
  168.  
  169. IMPORT
  170.   e := Exec, d: Dos, I: Intuition, gt: GadTools, u: Utility, wb: Workbench, 
  171.   ic: Icon, g: Graphics, loc: Locale, st: Strings, bs: BlackMagicStrings,
  172.   o: OberonLib, y: SYSTEM
  173.   (* $IF DEBUG *) , NoGuru (* $END *)
  174.   ;
  175.  
  176. CONST
  177.  
  178. (* $IF DEBUG *)  defaultDynamicExtra = 0;
  179. (* $ELSE *)      defaultDynamicExtra = 64;   (* $END *)
  180.  
  181. VAR
  182.   DynamicExtra - : LONGINT;
  183.  
  184. TYPE
  185.   (* due to misdefinition of wb.WBArgumentsPtr: Ptr TO ARRAY 256!! OF ... *)
  186.   WBArgumentsPtr * = UNTRACED POINTER TO ARRAY MAX(LONGINT) DIV 8-1 OF wb.WBArg;
  187.  
  188.   LongStrPtr * = UNTRACED POINTER TO ARRAY MAX (LONGINT)-1 OF CHAR;
  189.   LStrPtr * = LongStrPtr;
  190.   TTPtr * = UNTRACED POINTER TO ARRAY MAX (LONGINT) DIV 4-1 OF LongStrPtr;
  191.   StrVecPtr * = TTPtr;
  192.   APtrVecPtr * = UNTRACED POINTER TO ARRAY MAX (LONGINT) DIV 4-1 OF 
  193.                   UNTRACED POINTER TO e.APTR;
  194.  
  195.   DynStrPtr * = UNTRACED POINTER TO ARRAY OF CHAR;
  196.   DynTTPtr * = UNTRACED POINTER TO ARRAY OF LongStrPtr;
  197.  
  198. (* ReadArgsWB  flags *)
  199. CONST
  200.   ignoreTool       * = 0;
  201.   relPath          * = 1;
  202.   dontFill         * = 3;
  203.   doCD             * = 4;
  204.   ignoreProject    * = 5;
  205.   allowAskArg      * = 6;  (* also propagated to to.Init(...,flags,...) *)
  206.   askEmpty         * = 7;  (* also propagated to to.Init(...,flags,...) *) 
  207.   askEmptyOnAlways * = 8;  (* also propagated to to.Init(...,flags,...) *) 
  208.   argFile          * = 9;  (* also propagated to to.Init(...,flags,...) *) 
  209.   argFiles         * = 10; (* also propagated to to.Init(...,flags,...) *) 
  210.   noFullMulti      * = 11; (* also propagated to to.Init(...,flags,...) *) 
  211.   noMultiMulti     * = 12; (* also propagated to to.Init(...,flags,...) *) 
  212.   multiBarSep      * = 13; (* also propagated to to.Init(...,flags,...) *) 
  213.   multiCommaSep    * = 14; (* also propagated to to.Init(...,flags,...) *) 
  214.   disableSpecialNo * = 15; (* also propagated to to.Init(...,flags,...) *) 
  215.  
  216.   TemplOptFlagsMask = {allowAskArg..disableSpecialNo};
  217.  
  218. PROCEDURE^ AddPtr * (a, b: e.APTR): e.APTR;
  219.  
  220. (****** BlackMagic/DynStrLen **************************************************
  221. *
  222. *   NAME
  223. *       DynStrLen -- Return the length of a dynamic string
  224. *
  225. *   SYNOPSIS
  226. *       DynStrLen (dstr: DynStrPtr): LONGINT;
  227. *
  228. *   FUNCTION
  229. *       Returns the length of the string that is currently stored
  230. *       in the dynamic, run-time allocated/expanded string array
  231. *       represented by the passed dstr handle. Note that this
  232. *       is NOT the actual current capacity of the dynamic array, i.e. 
  233. *       it is not the number of characters the array can store currently.
  234. *       You may get that value by invoking the standard Oberon-2 function
  235. *       LEN (dstr^) (only with a non-NIL dstr, of course!).
  236. *       This function handles a NIL dstr handle correctly, returning null.
  237. *       (which is the one and only raison d'Ωtre for this function, by
  238. *       the way;-))
  239. *
  240. *   INPUTS
  241. *       dstr     - the dynamic string handle - may be NIL.
  242. *
  243. *   RESULT
  244. *       The length of the string stored in the dynamic string passed as
  245. *       input parameter.
  246. *
  247. *   SEE ALSO
  248. *       DynExpand(), DynAppend(), DStrLPtr(), InitDynStr(), ResetDynStr()
  249. *
  250. *****************************************************************************)
  251.  
  252. PROCEDURE DynStrLen * (dstr: DynStrPtr): LONGINT;
  253. BEGIN
  254.   IF dstr = NIL THEN RETURN 0; END;
  255.   RETURN st.Length (dstr^);
  256. END DynStrLen;
  257.   
  258. (****** BlackMagic/DynExpand **************************************************
  259. *
  260. *   NAME
  261. *       DynExpand -- Ensure a specified length of a dynamic char array
  262. *
  263. *   SYNOPSIS
  264. *       DynExpand (VAR string: DynStrPtr; len: LONGINT): BOOLEAN;
  265. *
  266. *   FUNCTION
  267. *       Make sure that a dynamic, run-time allocated/expanded character
  268. *       array can hold at least len+1 characters while preserving its
  269. *       current contents -- performs a reallocation of the dynamic char
  270. *       array if its current length doesn't suffice. When a reallocation
  271. *       takes place, the whole contents - not only the contents until the
  272. *       first nul character- of the old dynamic char array is copied
  273. *       into the new dynamic char array. This enables usage of this
  274. *       function in conjunction with char buffers where nul is a valid
  275. *       character, generally without sacrificing performance because 
  276. *       Exec.CopyMem() is usually _much_ faster than Oberon's COPY()
  277. *       command.
  278. *
  279. *   INPUTS
  280. *       string   - the dynamic char array (string) handle - may be NIL.
  281. *       len      - desired minimum length. In fact, it is made sure that
  282. *                  the dynamic string can store at least len+1 characters
  283. *                  because of the terminating null character.
  284. *
  285. *   RESULT
  286. *       TRUE   - for success.
  287. *       FALSE  - if memory allocation fails - in this case the dynamic
  288. *                char array and its handle are left unchanged.
  289. *
  290. *   NOTES
  291. *       See DynAppend()
  292. *
  293. *   SEE ALSO
  294. *       DynAppend(), DStrLPtr(), InitDynStr(), ResetDynStr()
  295. *
  296. *****************************************************************************)
  297.  
  298. PROCEDURE DynExpand * (VAR string: DynStrPtr; len: LONGINT): BOOLEAN;
  299. VAR
  300.   str1: DynStrPtr;
  301. BEGIN
  302.   INC (len, 1);
  303.   IF string # NIL THEN IF LEN (string^) >= len THEN RETURN TRUE; END; END;
  304.   y.ALLOCATE (str1, len+DynamicExtra); (* add some extra space for less reallocs *)
  305.   IF str1 = NIL THEN RETURN FALSE; END;
  306.   IF string # NIL THEN
  307.     e.CopyMem (string^, str1^, LEN (string^));
  308.     DISPOSE (string);
  309.   ELSE
  310.     str1^[0] := '\000';
  311.   END;
  312.   string := str1;
  313.   RETURN TRUE;
  314. END DynExpand;
  315.  
  316. (****** BlackMagic/DynAppend **************************************************
  317. *
  318. *   NAME
  319. *       DynAppend -- Append a string to a dynamic string
  320. *
  321. *   SYNOPSIS
  322. *       DynAppend (VAR string: DynStrPtr; append: ARRAY OF CHAR): BOOLEAN;
  323. *
  324. *   FUNCTION
  325. *       Appends a null-terminated char array string to a dynamic, run-
  326. *       time allocated/expanded string - performs a reallocation of the
  327. *       dynamic string if its length doesn't suffice to append the append
  328. *       string.
  329. *
  330. *   INPUTS
  331. *       string   - the dynamic string handle - may be NIL.
  332. *       append   - the string to be appended - may be empty.
  333. *
  334. *   RESULT
  335. *       TRUE   - for success.
  336. *       FALSE  - if memory allocation fails - in this case the dynamic
  337. *                string and its handle are left unchanged.
  338. *
  339. *   NOTES
  340. *       Make sure that your string handle is set to NIL before its first
  341. *       reference in your code. (Amiga-Oberon does this for global
  342. *       vars, for function vars unless you set the compiler flag
  343. *       ClearVars to False, as well as for handles allocated by NEW()/
  344. *       SYSTEM.ALLOCATE()/OberonLib.Allocate() if (Exec.memClear IN
  345. *       OberonLib.MemReqs) which is the default. This is not only true for
  346. *       Dynamic String handles, but also for all other pointer vars.
  347. *       To free the dynamic string's resources, just call 
  348. *       'DISPOSE (string);'.
  349. *
  350. *       All unfreed Dynamic Strings' resources are automatically freed 
  351. *       on your program's termination.
  352. *
  353. *   SEE ALSO
  354. *       DynInsert(), DynExpand(), DStrLPtr(), InitDynStr(), ResetDynStr()
  355. *
  356. *****************************************************************************)
  357.  
  358. PROCEDURE DynAppend * (VAR string: DynStrPtr; append: ARRAY OF CHAR): BOOLEAN;
  359. (* $CopyArrays- *)
  360. BEGIN
  361.   IF ~DynExpand (string, DynStrLen (string)+st.Length (append)+1) THEN RETURN FALSE; END;
  362.   st.Append (string^, append);
  363.   RETURN TRUE;
  364. END DynAppend;
  365.  
  366. (****** BlackMagic/DynInsert **************************************************
  367. *
  368. *   NAME
  369. *       DynInsert -- Insert a string in a dynamic string
  370. *
  371. *   SYNOPSIS
  372. *       DynInsert (VAR string: DynStrPtr; 
  373. *                  at        : LONGINT;       
  374. *                  ins       : ARRAY OF CHAR): BOOLEAN;
  375. *
  376. *   FUNCTION
  377. *       Inserts a null-terminated char array string in a dynamic, run-
  378. *       time allocated/expanded string at a specific position - performs 
  379. *       a reallocation of the dynamic string if its length doesn't suffice
  380. *       to insert the ins string.
  381. *
  382. *   INPUTS
  383. *       string   - the dynamic string handle - may be NIL.
  384. *       at       - the position (starting at 0) at which the ins string
  385. *                  should be inserted in the dynamic string. Invalid
  386. *                  values cause this function to return failure
  387. *       ins      - the string to be inserted - may be empty.
  388. *
  389. *   RESULT
  390. *       TRUE   - for success.
  391. *       FALSE  - if memory allocation fails or the specified insertion
  392. *                position was invalid. In both cases the dynamic
  393. *                string and its handle are left unchanged.
  394. *
  395. *   NOTES
  396. *       See DynAppend()
  397. *
  398. *   SEE ALSO
  399. *       DynAppend(), DynExpand(), DStrLPtr(), InitDynStr(), ResetDynStr()
  400. *
  401. *****************************************************************************)
  402.  
  403. PROCEDURE DynInsert * (VAR string: DynStrPtr; 
  404.                        at        : LONGINT;
  405.                        ins       : ARRAY OF CHAR): BOOLEAN;
  406. (* $CopyArrays- *)
  407. BEGIN
  408.   IF (at < 0) OR (at > DynStrLen (string)) THEN RETURN FALSE; END;
  409.   IF ~DynExpand (string, DynStrLen (string)+st.Length (ins)+1) THEN RETURN FALSE; END;
  410.   st.Insert (string^, at, ins);
  411.   RETURN TRUE;
  412. END DynInsert;
  413.  
  414. (****** BlackMagic/ResetDynStr ************************************************
  415. *
  416. *   NAME
  417. *       ResetDynStr -- disposes a dynamic string if necessary and inits it.
  418. *
  419. *   SYNOPSIS
  420. *       ResetDynStr (VAR dstr: DynStrPtr): BOOLEAN;
  421. *
  422. *   FUNCTION
  423. *       Disposes the dynamic string if dstr is not NIL, and initializes it
  424. *       in a way that the dstr dynamic string handle points to a nul string.
  425. *
  426. *   INPUTS
  427. *       string   - the dynamic string handle - may be NIL.
  428. *
  429. *   RESULT
  430. *       TRUE   - for success.
  431. *       FALSE  - if memory allocation fails - in this case the dynamic
  432. *                string handle is set to NIL.
  433. *
  434. *   NOTES
  435. *       Make sure that your dstr handle is set to NIL before its first
  436. *       reference in your code. (Amiga-Oberon does this for global
  437. *       global, for function vars unless you set the compiler flag
  438. *       ClearVars to False, as well as for handles allocated by NEW()/
  439. *       SYSTEM.ALLOCATE()/OberonLib.Allocate() if (Exec.memClear IN
  440. *       OberonLib.MemReqs) which is the default. This is not only true for
  441. *       Dynamic String handles, but also for all other pointer vars.
  442. *        
  443. *   SEE ALSO
  444. *       InitDynStr(), DynExpand(), DynAppend()
  445. *
  446. *****************************************************************************)
  447.  
  448. PROCEDURE ResetDynStr * (VAR dstr: DynStrPtr): BOOLEAN;
  449. BEGIN
  450.   DISPOSE (dstr);
  451.   RETURN DynAppend (dstr, "");
  452. END ResetDynStr;
  453.  
  454. (****** BlackMagic/InitDynStr *************************************************
  455. *
  456. *   NAME
  457. *       InitDynStr -- inits a dynamic string IGNORING its handle's value
  458. *
  459. *   SYNOPSIS
  460. *       InitDynStr (VAR dstr: DynStrPtr): BOOLEAN;
  461. *
  462. *   FUNCTION
  463. *       Sets the dstr handle to NIL first while ignoring its hitherto value, 
  464. *       and initializes it then in a way that the dstr dynamic string handle
  465. *       points to a nul string. If you call this function for every dynamic
  466. *       string handle at the very beginning of your code, you ensure that
  467. *       you may reference all dynamic strings' contents using dstr^. Note
  468. *       however, that all functions of this module work fine with NIL-
  469. *       Dynamic String handles as well!
  470. *
  471. *   INPUTS
  472. *       string   - the dynamic string handle - may be NIL.
  473. *
  474. *   RESULT
  475. *       TRUE   - for success.
  476. *       FALSE  - if memory allocation fails - in this case the dynamic
  477. *                string handle is set to NIL.
  478. *
  479. *   SEE ALSO
  480. *       ResetDynStr(), DynExpand(), DynAppend()
  481. *
  482. *****************************************************************************)
  483.  
  484. PROCEDURE InitDynStr * (VAR dstr: DynStrPtr): BOOLEAN;
  485. BEGIN
  486.   dstr := NIL;
  487.   RETURN DynAppend (dstr, "");
  488. END InitDynStr;
  489.  
  490. (****** BlackMagic/DStrLPtr *****************************************************
  491. *
  492. *   NAME
  493. *       DStrLPtr -- Return a 'conventional' LongStrPtr to a dynamic string
  494. *       DStrAPtr -- Return a 'conventional' Exec.APTR to a dynamic string
  495. *
  496. *   SYNOPSIS
  497. *       DStrLPtr (dstr: DynStrPtr): LongStrPtr;
  498.  
  499. *       DStrAPtr (dstr: DynStrPtr): Exec.APTR;
  500. *
  501. *   FUNCTION
  502. *       These functions return a LongStrPtr as defined in this module, resp.
  503. *       an Exec.APTR, to the dynamic string passed as the function's
  504. *       argument. A LongStrPtr is defined as an UNTRACED POINTER TO ARRAY 
  505. *       MAX(LONGINT) - 1 OF CHAR which should be in all possible cases
  506. *       used instead of Exec.STRPTR, if you don't know the array 
  507. *       bound of the string. This keeps you from ugly runtime errors
  508. *       you get when you manipulate Exec.STRPTR^ beyond the 256th char
  509. *       element. (Exec.STRPTR is currently definded as ARRAY 256 OF CHAR)
  510. *       Note however, that you have to use (* [Dollar]CopyArrays- *) for
  511. *       your functions that have ARRAY OF CHAR parameters, you may pass 
  512. *       LongStrPtr^ to.
  513. *
  514. *   INPUTS
  515. *       dstr     - the dynamic string handle - may be NIL.
  516. *
  517. *   RESULT
  518. *       a LongStrPtr / Exec.APTR  pointing to the first char element of the
  519. *       dstr or NIL if dstr is NIL.
  520. *
  521. *   SEE ALSO
  522. *       DynAppend(), StrIndex()
  523. *
  524. *****************************************************************************)
  525.  
  526. PROCEDURE DStrLPtr * (dstr: DynStrPtr): LongStrPtr;
  527. BEGIN
  528.   IF dstr = NIL THEN RETURN NIL; END;
  529.   RETURN y.ADR (dstr^[0]);
  530. END DStrLPtr;
  531.  
  532. PROCEDURE DStrAPtr * (dstr: DynStrPtr): e.APTR;
  533. BEGIN
  534.   RETURN DStrLPtr (dstr);
  535. END DStrAPtr;
  536.  
  537. (****** BlackMagic/StrIndex ****************************************************
  538. *
  539. *   NAME
  540. *       StrIndex -- Return a LongStrPtr to a string index.
  541. *       StrIndexA -- Return an Exec.APTR to a string index.
  542. *
  543. *   SYNOPSIS
  544. *       StrIndex (str: ARRAY OF CHAR; n: LONGINT): LongStrPtr;
  545. *       StrIndexA (str: ARRAY OF CHAR; n: LONGINT): Exec.APTR;
  546. *
  547. *   FUNCTION
  548. *       These functions return a LongStrPtr as defined in this module,
  549. *       resp. an Exec.APTR, pointing to the nth element of the string str.
  550. *       This function is extremely useful since there are thousands if
  551. *       not millions of occasions where you need to pass an array of char 
  552. *       starting with a specific index of another string to a function,
  553. *       especially when working with the Operating System.
  554. *       Note however, that you have to use (* [Dollar]CopyArrays- *) for
  555. *       your functions that have ARRAY OF CHAR parameters, you may pass 
  556. *       LongStrPtr^ to.
  557. *
  558. *   INPUTS
  559. *       str      - the string to operate on
  560. *       n        - the ordinal index - may be even negative since no range
  561. *                  checking takes place
  562. *
  563. *   RESULT
  564. *       a LongStrPtr / Exec.APTR pointing to the nth char of the string.
  565. *
  566. *   SEE ALSO
  567. *       DStrLPtr()
  568. *
  569. *****************************************************************************)
  570.  
  571. PROCEDURE StrIndex * (str: ARRAY OF CHAR; n: LONGINT): LongStrPtr;
  572. (* $CopyArrays- *)
  573. BEGIN
  574.   RETURN AddPtr (y.ADR (str[0]), n);
  575. END StrIndex;
  576.  
  577.  
  578. PROCEDURE StrIndexA * (str: ARRAY OF CHAR; n: LONGINT): e.APTR;
  579. (* $CopyArrays- *)
  580. BEGIN
  581.   RETURN StrIndex (str, n);
  582. END StrIndexA;
  583.  
  584. (****** BlackMagic/StrToLStr ************************************************
  585. *
  586. *   NAME
  587. *       StrToLStr - Typecast an Exec.STRPTR into a LongStrPtr
  588. *
  589. *   SYNOPSIS
  590. *       StrToLStr (str: Exec.STRPTR): LongStrPtr;
  591. *
  592. *   FUNCTION
  593. *       This function simply typecasts the str Exec.STRPTR passed into
  594. *       a LongStrPtr which may be needed when dealing with Operating System
  595. *       structures and functions whose STRPTR typed strings you want to
  596. *       manipulate without disabling the compiler's range checking.
  597. *
  598. *   INPUTS
  599. *       str      - the Exec.STRPTR which is to be typecasted - may be NIL.
  600. *
  601. *   RESULT
  602. *       the LongStrPtr 
  603. *
  604. *   NOTES
  605. *       you should be able to pass an Exec.APTR to this function
  606. *
  607. *   SEE ALSO
  608. *       LStrToStr(), DStrLPtr(), StrIndex()
  609. *
  610. *****************************************************************************)
  611.  
  612. PROCEDURE StrToLStr * (str: e.STRPTR): LongStrPtr;
  613. BEGIN
  614.   RETURN AddPtr (str, 0);
  615. END StrToLStr;
  616.  
  617. (****** BlackMagic/LStrToStr ************************************************
  618. *
  619. *   NAME
  620. *       LStrToStr - Typecast a LongStrPtr into an Exec.STRPTR;
  621. *
  622. *   SYNOPSIS
  623. *       LStrToStr (lstr: LongStrPtr): Exec.STRPTR;
  624. *
  625. *   FUNCTION
  626. *       This function simply typecasts the lstr LongStrPtr passed into
  627. *       an Exec.STRPTR which may be needed when dealing with Operating
  628. *       System structures and functions that expect Exec.STRPTRs.
  629. *
  630. *   INPUTS
  631. *       lstr     - the LongStrPtr that is to be typecasted - may be NIL.
  632. *
  633. *   RESULT
  634. *       the Exec.STRPTR
  635. *
  636. *   NOTES
  637. *       you should be able to pass an Exec.APTR to this function
  638. *
  639. *   SEE ALSO
  640. *       StrToLStr(), DStrLPtr(), StrIndex()
  641. *
  642. *****************************************************************************)
  643.  
  644. PROCEDURE LStrToStr * (lstr: LongStrPtr): e.STRPTR;
  645. BEGIN
  646.   RETURN AddPtr (lstr, 0);
  647. END LStrToStr;
  648.  
  649.  
  650. (****** BlackMagic/DynTTLen **************************************************
  651. *
  652. *   NAME
  653. *       DynTTLen -- Return the length of a dynamic ToolType array
  654. *
  655. *   SYNOPSIS
  656. *       DynStrLen (tt: DynTTPtr): LONGINT;
  657. *
  658. *   FUNCTION
  659. *       Returns the number of entries that are currently stored
  660. *       in the dynamic, run-time allocated/expanded ToolType array
  661. *       represented by the passed tt handle. Note that this
  662. *       is NOT the actual current capacity of the dynamic array, i.e. 
  663. *       it is not the number of ToolTypes the array can store currently.
  664. *       You may get that value by invoking the standard Oberon-2 function
  665. *       LEN (dstr^) (only with a non-NIL tt, of course!).
  666. *       This function handles a NIL tt handle correctly, returning null.
  667. *
  668. *   INPUTS
  669. *       tt       - the dynamic ToolType array handle - may be NIL.
  670. *
  671. *   RESULT
  672. *       The number of entries that are currently stored in the dynamic 
  673. *       ToolType array passed as input parameter.
  674. *
  675. *   SEE ALSO
  676. *       DynAppendTT(), DynInsertTT(), WriteTTEntry()
  677. *
  678. *****************************************************************************)
  679.  
  680. PROCEDURE DynTTLen * (tt: DynTTPtr): LONGINT;
  681. VAR
  682.   i: LONGINT;
  683. BEGIN
  684.   IF tt = NIL THEN RETURN 0; END;
  685.   i := 0;
  686.   WHILE tt[i] # NIL DO INC (i); END;  
  687.   RETURN i;
  688. END DynTTLen;
  689.  
  690. (* DynAppendTT flags *)
  691. CONST
  692.   createEmpty * = 0;  (* create empty TT handle if NIL, otherwise NOP, ignore chr array *)
  693.   noNulTerm  *  = 1;  (* copy the whole structure / array, don't stop on Nul *)
  694.  
  695.  
  696. (****** BlackMagic/DynAppendTT *************************************************
  697. *
  698. *   NAME
  699. *       DynAppendTT -- Append a string to a dynamic ToolType array.
  700. *
  701. *   SYNOPSIS
  702. *       DynAppendTT (VAR tt : DynTTPtr;
  703. *                    append : ARRAY OF SYSTEM.BYTE;
  704. *                    flags  : SET                  ): BOOLEAN;
  705. *
  706. *   FUNCTION
  707. *       This function adds a string / structure / array  to a 
  708. *       dynamically, run-time allocated, NIL-terminated array of
  709. *       pointers to null-terminated strings. Space for the string /
  710. *       structure / array is allocated.
  711. *       A dynamic ToolType array handle (DynTTPtr) is defined as an 
  712. *       UNTRACED POINTER TO ARRAY OF LongStrPtr. If the array size is
  713. *       insufficient, this function reallocates it.
  714. *
  715. *   INPUTS
  716. *       tt       - the dynamic ToolType array handle - may be NIL.
  717. *       append   - the string / structure / array to be appended 
  718. *       flags    - currently two flags are defined: 
  719. *                  createEmpty: If you specify it, <append> is ignored,
  720. *                    and this function just returns TRUE except when the
  721. *                    ToolType array handle is NIL - in that case it will
  722. *                    allocate a minimal ToolType array and write NIL into
  723. *                    its first element, indicating that the array contains
  724. *                    no elements.
  725. *                  noNulTerm indicates that <append> should be treated as 
  726. *                    a fixed size structure / array rather than as a string,
  727. *                    i.e. the whole <append> is copied, not only until the
  728. *                    first Nul character.
  729. *
  730. *   RESULT
  731. *       TRUE   - for success.
  732. *       FALSE  - if memory allocation failed - in this case the contents
  733. *                of the ToolType array - NOT necessarily the handle 
  734. *                itself - is left unchanged.
  735. *
  736. *   NOTES
  737. *       You should initialize the ToolType array handle with 
  738. *       'tt := MIL;' before your first call to DynAppendTT().
  739. *
  740. *       It is of utmost importance that you only specify the flag(s)
  741. *       documented along with this function for the flags argument since
  742. *       otherwise unexpected things may happen to the system, to the
  743. *       computer, and finally to yourself (you may get a nervous, violent
  744. *       fit of temper, run amok, or even commit suicide due to your machine
  745. *       crashing at the very moment when you want to save save your hitherto
  746. *       unsaved source for your new great, nifty, revolutionary,
  747. *       trailblazing, unprecedented new software project!)) - Just kidding,
  748. *       girls & boys, currently no severe things may result, but this may
  749. *       well change in the future!
  750. *
  751. *   SEE ALSO
  752. *       FreeDynTT(), WriteTTEntry(), RemDynTTEntry(), DynInsertTT(),
  753. *       TTAPtr()
  754. *
  755. *****************************************************************************)
  756.  
  757.  
  758. PROCEDURE DynAppendTT * (VAR tt : DynTTPtr;
  759.                          append : ARRAY OF y.BYTE;
  760.                           flags : SET           ): BOOLEAN;
  761. VAR
  762.   tt1        : DynTTPtr;
  763.   origlen, i : LONGINT;
  764.   ls         : LongStrPtr;
  765.  
  766. (* $CopyArrays- *)
  767. BEGIN
  768.   origlen := DynTTLen (tt);
  769.   ls := y.ADR (append);
  770.   IF tt # NIL THEN
  771.     IF createEmpty IN flags THEN RETURN TRUE; END;
  772.   END;
  773.   LOOP
  774.     IF tt # NIL THEN IF LEN (tt^) >= origlen+2 THEN EXIT; END; END;
  775.     y.ALLOCATE (tt1, origlen+2+DynamicExtra DIV 4); (* add some extra space for less reallocs *)
  776.     IF tt1 = NIL THEN RETURN FALSE; END;
  777.     IF tt # NIL THEN
  778.       FOR i:=0 TO origlen DO tt1^[i] := tt^[i]; END;
  779.       DISPOSE (tt);
  780.     END;
  781.     tt := tt1;
  782.     EXIT;
  783.   END;
  784.   tt [origlen+1] := NIL;
  785.   IF createEmpty IN flags THEN
  786.     tt [origlen] := NIL;
  787.   ELSE
  788.     IF noNulTerm IN flags THEN
  789.       o.Allocate (tt [origlen], LEN (append));
  790.     ELSE
  791.       o.Allocate (tt [origlen], st.Length (ls^)+1);
  792.     END;
  793.     IF tt [origlen] = NIL THEN RETURN FALSE; END;
  794.     IF noNulTerm IN flags THEN
  795.       e.CopyMem (append, tt [origlen]^, LEN (append));
  796.     ELSE  
  797.       COPY (ls^, tt [origlen]^);
  798.     END;  
  799.   END;
  800.   RETURN TRUE;
  801. END DynAppendTT;
  802.  
  803. (****** BlackMagic/WriteTTEntry ***********************************************
  804. *
  805. *   NAME
  806. *       WriteTTEntry -- Write a TTEntry into a dynamic ToolType array.
  807. *
  808. *   SYNOPSIS
  809. *       WriteTTEntry (VAR dtt: DynTTPtr;
  810. *                     Entry  : LONGINT;
  811. *                     str    : ARRAY OF SYSTEM.BYTE;
  812. *                     flags  : SET                  ): BOOLEAN;
  813. *
  814. *   FUNCTION
  815. *       This function writes a string / structure / array at a
  816. *       specific position to a dynamically, run-time 
  817. *       allocated, NIL-terminated array of pointers to nul-
  818. *       terminated strings / non-nul-terminated structures or
  819. *       arrays. Space for the string / structure / array is
  820. *       allocated. A potential old string / structure / array is
  821. *       deleted first. A dynamic ToolType array handle (DynTTPtr)
  822. *       is defined as an UNTRACED POINTER TO ARRAY OF LongStrPtr.
  823. *       If the array size is insufficient, this function reallocates
  824. *       it.
  825. *
  826. *   INPUTS
  827. *       dtt      - the ToolType array handle - may be NIL.
  828. *       Entry    - The ordinal number of the entry where the string
  829. *                  is to be written, starting at zero, or -1 to
  830. *                  append at the end of the ToolType array.
  831. *       str      - the string / structure / array to add
  832. *       flags    - noNulTerm indicates that <str> should be treated as
  833. *                    a fixed size structure / array rather than as a
  834. *                    string, i.e. the whole <str> is copied, not only
  835. *                    until the first Nul character.
  836. *                  No other flags are defined currently.
  837. *
  838. *   RESULT
  839. *       TRUE   - for success.
  840. *       FALSE  - if memory allocation failed - in this case the contents
  841. *                of the ToolType array - NOT necessarily the handle
  842. *                itself - is left unchanged.
  843. *
  844. *   SEE ALSO
  845. *       DynAppendTT(), RemDynTTEntry(), FreeDynTT(), DynInsertTT(), 
  846. *       TTAPtr()
  847. *
  848. *****************************************************************************)
  849.  
  850. PROCEDURE WriteTTEntry * (VAR dtt: DynTTPtr;
  851.                           Entry  : LONGINT;
  852.                           str    : ARRAY OF y.BYTE;
  853.                           flags  : SET             ): BOOLEAN;
  854. VAR
  855.   i   : LONGINT;
  856.   ls  : LongStrPtr;
  857.   str1: LongStrPtr;
  858. (* $CopyArrays- *)
  859. BEGIN
  860.   str1 := y.ADR (str[0]);
  861.   ls := NIL;
  862.   i := DynTTLen (dtt);
  863.   IF (Entry < -1) OR (Entry > i) THEN RETURN FALSE; END;
  864.   IF (Entry = -1) OR (Entry = i) THEN 
  865.     RETURN DynAppendTT (dtt, str, flags) 
  866.   END;
  867.   IF dtt = NIL THEN RETURN FALSE; END;
  868.   IF noNulTerm IN flags THEN
  869.     o.Allocate (ls, LEN (str));
  870.   ELSE
  871.     o.Allocate (ls, st.Length (str1^)+1);
  872.   END;
  873.   IF ls = NIL THEN RETURN FALSE; END;
  874.   IF noNulTerm IN flags THEN
  875.     e.CopyMem (str, ls^, LEN (str));
  876.   ELSE
  877.     COPY (str1^, ls^);
  878.   END;
  879.   DISPOSE (dtt[Entry]); dtt[Entry] := ls;
  880.   RETURN TRUE;
  881. END WriteTTEntry;
  882.  
  883.  
  884. (****** BlackMagic/DynInsertTT ************************************************
  885. *
  886. *   NAME
  887. *       DynInsertTT -- Insert a TTEntry into a dynamic ToolType array.
  888. *
  889. *   SYNOPSIS
  890. *       DynInsertTT (VAR dtt: DynTTPtr;
  891. *                    Entry  : LONGINT;
  892. *                    str    : ARRAY OF SYSTEM.BYTE;
  893. *                    flags  : SET                  ): BOOLEAN;
  894. *
  895. *   FUNCTION
  896. *       This function inserts a string / structure / array at a
  897. *       pecific position (starting at 0) to a dynamically, run-time
  898. *       allocated, NIL-terminated array of pointers to nul-
  899. *       terminated strings / non-nul-terminated structures or
  900. *       arrays. Space for the string / structure / array is
  901. *       allocated. A dynamic ToolType array handle (DynTTPtr)
  902. *       is defined as an UNTRACED POINTER TO ARRAY OF LongStrPtr.
  903. *
  904. *   INPUTS
  905. *       dtt      - the ToolType array handle - may be NIL.
  906. *       Entry    - The ordinal number of the entry, at which the
  907. *                  stringis to be written, starting at zero. Invalid
  908. *                  values causes this function to return failure.
  909. *       str      - the string / structure / array to add
  910. *       flags    - noNulTerm indicates that <str> should be treated as
  911. *                    a fixed size structure / array rather than as a
  912. *                    string, i.e. the whole <str> is copied, not only
  913. *                    until the first Nul character.
  914. *                  No other flags are defined currently.
  915. *
  916. *   RESULT
  917. *       TRUE   - for success.
  918. *       FALSE  - if memory allocation failed or the Entry value was
  919. *                invalid - in this case the contents
  920. *                of the ToolType array - NOT necessarily the handle
  921. *                itself - is left unchanged.
  922. *
  923. *   SEE ALSO
  924. *       DynAppendTT(), RemDynTTEntry(), WriteTTEntry(), FreeDynTT(), 
  925. *       TTAPtr()
  926. *
  927. *****************************************************************************)
  928.  
  929. PROCEDURE DynInsertTT * (VAR dtt: DynTTPtr;
  930.                          Entry  : LONGINT;
  931.                          str    : ARRAY OF y.BYTE;
  932.                          flags  : SET             ): BOOLEAN;
  933. VAR
  934.   i,j : LONGINT;
  935.   ls  : LongStrPtr;
  936. (* $CopyArrays- *)
  937. BEGIN
  938.   ls := NIL;
  939.   i := DynTTLen (dtt);
  940.   IF (Entry < 0) OR (Entry > i) THEN RETURN FALSE; END;
  941.   IF ~DynAppendTT (dtt, str, flags) THEN RETURN FALSE; END;
  942.   ls := dtt[i];
  943.   FOR j := i-1 TO Entry BY -1 DO dtt[j+1] := dtt[j]; END;
  944.   dtt[Entry] := ls;
  945.   RETURN TRUE;
  946. END DynInsertTT;
  947.  
  948. (****** BlackMagic/FreeDynTT ***************************************************
  949. *
  950. *   NAME
  951. *       FreeDynTT -- Frees a ToolType array handle's resources & resets it.
  952. *
  953. *   SYNOPSIS
  954. *       FreeDynTT (VAR dtt: DynTTPtr);
  955. *
  956. *   FUNCTION
  957. *       This function frees all resources that may have been allocated
  958. *       for a ToolType array and reinitializes its handle to NIL.
  959. *       It is save to invoke this function with a NIL ToolType array
  960. *       handle.
  961. *
  962. *   INPUTS
  963. *       dtt      - the ToolType array handle - may be NIL.
  964. *
  965. *   NOTES
  966. *       All unfreed ToolType arrays' resources are automatically freed 
  967. *       on your program's termination.
  968. *
  969. *   SEE ALSO
  970. *       AppendDynTT(), RemDynTTEntry(), TTAPtr()
  971. *
  972. *****************************************************************************)
  973.  
  974. PROCEDURE FreeDynTT * (VAR dtt: DynTTPtr);
  975. VAR
  976.   i: LONGINT;
  977. BEGIN
  978.   IF dtt = NIL THEN RETURN; END;
  979.   i := 0;
  980.   LOOP
  981.     IF i>=LEN (dtt^) THEN EXIT; END;
  982.     IF dtt^[i] = NIL THEN EXIT; END;
  983.     DISPOSE (dtt^[i]);
  984.     INC (i);
  985.   END;
  986.   DISPOSE (dtt);
  987. END FreeDynTT;
  988.  
  989. (****** BlackMagic/RemDynTTEntry ***********************************************
  990. *
  991. *   NAME
  992. *       RemDynTTEntry -- Remove an entry from a dynamic ToolType array.
  993. *
  994. *   SYNOPSIS
  995. *       RemDynTTEntry (dtt: DynTTPtr; Entry: LONGINT): BOOLEAN;
  996. *
  997. *   FUNCTION
  998. *       This function removes an entry from a dynamic ToolType array.
  999. *       Removes the 'Entrieth' entry (count starts at 0) or the last
  1000. *       entry if Entry is -1, and deallocates the space for it.
  1001. *       This function is safe to call with insensible parameters like
  1002. *       NIL ToolType array handles, empty ToolType arrays, or invalid Entry
  1003. *       values. In these cases, it will return FALSE, otherwise TRUE.
  1004. *
  1005. *   INPUTS
  1006. *       dtt      - the ToolType array handle - may be NIL.
  1007. *       Entry    - The ordinal number of the entry to be removed, starting
  1008. *                  at zero, or -1 to remove the last entry.
  1009. *
  1010. *   RESULT
  1011. *       TRUE   - for success.
  1012. *       FALSE  - for 'insensible' parameters
  1013. *
  1014. *   SEE ALSO
  1015. *       DynAppendTT(), FreeDynTT(), TTAPtr()
  1016. *
  1017. *****************************************************************************)
  1018.  
  1019. PROCEDURE RemDynTTEntry * (dtt: DynTTPtr; Entry: LONGINT): BOOLEAN;
  1020. VAR
  1021.   i,j: LONGINT;
  1022. BEGIN
  1023.   IF dtt = NIL THEN RETURN FALSE; END;
  1024.   i := DynTTLen (dtt);
  1025.   DEC (i);
  1026.   IF Entry = -1 THEN Entry := i; END;
  1027.   IF (Entry < 0) OR (Entry > i) THEN RETURN FALSE; END;
  1028.   DISPOSE (dtt[Entry]);
  1029.   FOR j := Entry TO i DO dtt[j] := dtt[j+1]; END;
  1030.   RETURN TRUE;
  1031. END RemDynTTEntry;  
  1032.  
  1033. (****** BlackMagic/TTAPtr ******************************************************
  1034. *
  1035. *   NAME
  1036. *       TTAptr -- Returns a conventional pointer to a dynamic ToolType array
  1037. *
  1038. *   SYNOPSIS
  1039. *       TTAPtr (dtt: DynTTPtr): TTPtr;
  1040. *
  1041. *   FUNCTION
  1042. *       This function returns a TTPtr as defined in this module
  1043. *       to the dynamic ToolType array passed as the function's argument.
  1044. *       A TTPtr is defined as an UNTRACED POINTER TO ARRAY MAX(LONGINT) 
  1045. *       DIV 4 - 1 OF LongStrPtr. It is especially useful to pass it to
  1046. *       or to convert function results frm other functions that deal with
  1047. *       ToolTypes such as the icon.library's, etc.
  1048. *       Since this module's ReadArgs() functions return structure
  1049. *       RDArgsWB contain two dynamic ToolType array handles, which you may
  1050. *       use or manipulate with all of this module's documented dynamic
  1051. *       ToolType array handle related functions, you may convert
  1052. *       them to conventional ToolType array handles using this function.
  1053. *       
  1054. *   INPUTS
  1055. *       dtt      - the dynamic ToolType array handle - may be NIL.
  1056. *
  1057. *   RESULT
  1058. *       The respective 'conventional' TTPtr equivalent.
  1059. *
  1060. *   SEE ALSO
  1061. *       DynAppendTT(), FreeDynTT(), RemDynTTEntry()
  1062. *
  1063. *****************************************************************************)
  1064.  
  1065. PROCEDURE TTAPtr * (dtt: DynTTPtr): TTPtr;
  1066. BEGIN
  1067.   IF dtt = NIL THEN RETURN NIL; END;
  1068.   RETURN y.ADR (dtt^[0]);
  1069. END TTAPtr;
  1070.  
  1071.  
  1072. CONST
  1073.   (* type modifiers for template options *)
  1074.   ignoreC  = 'I';
  1075.   strC     = '\x00';
  1076.   numC     = 'N';
  1077.   switchC  = 'S';
  1078.   toggleC  = 'T';
  1079.   multiNumC= '\x00';
  1080.   remainC  = 'F';
  1081.   multiC   = 'M';
  1082.  
  1083.   (* attribute modifiers for template options *)
  1084.   keyC    = 'K';
  1085.   alwaysC = 'A';
  1086.   
  1087.   (* type values *)
  1088.   ignore  = 0;
  1089.   str     = 1;
  1090.   num     = 2;
  1091.   switch  = 3;
  1092.   toggle  = 4;
  1093.   multiNum= 5;
  1094.   remain  = 6;
  1095.   multi   = 7;
  1096.   maxType = multi; (* highest type value *)
  1097.   AddEmptyName = maxType+1;
  1098.  
  1099.   (* attribute set elements for TemplOpt.flags, etc *)
  1100.   keyAttr     = 0;
  1101.   alwaysAttr  = 1;
  1102.   numAttr     = 2;
  1103.  
  1104.   (* flag for TemplOpt.flags *)
  1105.   requestArg  = 4;
  1106.  
  1107. TYPE
  1108.   TmplTypArrT = ARRAY maxType+1 OF CHAR; 
  1109.  
  1110. CONST
  1111.   tmplTypes = TmplTypArrT ('I\000NST\000FM');
  1112.   tmplTypesSansNum = TmplTypArrT ('I\000\000ST\000FM'); (* required for special /M/N handling *)
  1113.  
  1114. TYPE
  1115.   TemplOptPtr = UNTRACED POINTER TO TemplOpt;
  1116.   TemplOpt = RECORD
  1117.     name       : DynStrPtr;
  1118.     names      : DynTTPtr;
  1119.     activeName : LongStrPtr;
  1120.     flags      : SET;
  1121.     pri        : LONGINT; (* was: type: LONGINT; *)
  1122.     used       : BOOLEAN;
  1123.     entry      : UNTRACED POINTER TO e.APTR;
  1124.     entryBackUp: e.APTR;
  1125.   END;
  1126.  
  1127.   TemplIgnore = RECORD (TemplOpt)
  1128.   END;
  1129.  
  1130.   TemplStrT = RECORD (TemplOpt)
  1131.     string: DynStrPtr;
  1132.   END;
  1133.  
  1134.   TemplStr = RECORD (TemplStrT)
  1135.   END;
  1136.  
  1137.   TemplRemain = RECORD (TemplStrT)
  1138.   END;
  1139.  
  1140.   TemplSwitchT = RECORD (TemplOpt)
  1141.   END;
  1142.  
  1143.   TemplSwitch = RECORD (TemplSwitchT)
  1144.   END;
  1145.  
  1146.   TemplToggle = RECORD (TemplSwitchT)
  1147.   END;
  1148.  
  1149.   TemplNum = RECORD (TemplOpt)
  1150.     num:  LONGINT;
  1151.   END;
  1152.  
  1153.   TemplMultiT = RECORD (TemplOpt)
  1154.     argsArr: DynTTPtr;
  1155.   END;
  1156.  
  1157.   TemplMulti = RECORD (TemplMultiT)
  1158.   END;
  1159.  
  1160.   TemplMultiNum = RECORD (TemplMultiT)
  1161.   END;
  1162.  
  1163.   TemplArrT = UNTRACED POINTER TO ARRAY OF TemplOptPtr;
  1164.  
  1165.   RDArgsPtr * = UNTRACED POINTER TO RDArgs;
  1166.  
  1167.   RDArgs * = RECORD
  1168.   END;
  1169.  
  1170.   RDArgsWBPtr * = UNTRACED POINTER TO RDArgsWB;
  1171.  
  1172.   RDArgsWB * = RECORD (RDArgs)
  1173.     opts     : TemplArrT;
  1174.     oldCD    : d.FileLockPtr; (* NIL is a valid oldCD directory! *)
  1175.     validCD  : BOOLEAN;       (* thus this entry... *)
  1176.     ttIncl * : DynTTPtr;
  1177.     ttRest * : DynTTPtr;
  1178.   END;
  1179.  
  1180.   RDArgsCLIPtr * = UNTRACED POINTER TO RDArgsCLI;
  1181.  
  1182.   RDArgsCLI = RECORD (RDArgs)
  1183.     rda: d.RDArgsPtr;
  1184.   END;
  1185.  
  1186. PROCEDURE^ FreeTemplArr (Arr: TemplArrT);
  1187.  
  1188. PROCEDURE (VAR rda: RDArgs) Free();
  1189. BEGIN
  1190. END Free;
  1191.  
  1192. PROCEDURE (VAR rda: RDArgsWB) Free();
  1193. BEGIN
  1194.   IF rda.opts = NIL THEN RETURN; END;
  1195.   IF rda.validCD THEN y.SETREG (0, d.CurrentDir (rda.oldCD)); END;
  1196.   FreeTemplArr (rda.opts); 
  1197.   FreeDynTT (rda.ttRest);
  1198.   FreeDynTT (rda.ttIncl);
  1199. END Free;
  1200.  
  1201. PROCEDURE (VAR rda: RDArgsCLI) Free();
  1202. BEGIN
  1203.   IF rda.rda = NIL THEN RETURN; END;
  1204.   d.FreeArgs (rda.rda); rda.rda := NIL;
  1205. END Free;
  1206.  
  1207. (****** BlackMagic/ToolNameLen ************************************************
  1208. *
  1209. *   NAME
  1210. *       ToolNameLen -- Get length of ToolType's name from a tt argument str
  1211. *
  1212. *   SYNOPSIS
  1213. *       ToolNameLen (tt: ARRAY OF CHAR): LONGINT;
  1214. *
  1215. *   FUNCTION
  1216. *       Returns the length of the name part of a ToolType arguemnt
  1217. *       string. This is done by checking for the first occurence of
  1218. *       either nul or '='.
  1219. *
  1220. *   INPUTS
  1221. *       tt       - the ToolType argument string
  1222. *
  1223. *   RESULT
  1224. *       the length of the ToolType's name part.
  1225. *
  1226. *   SEE ALSO
  1227. *       GetToolValue(), ToolNameLen()
  1228. *
  1229. *****************************************************************************)
  1230.  
  1231. PROCEDURE ToolNameLen * (tt: ARRAY OF CHAR): LONGINT;
  1232. VAR
  1233.   ii: LONGINT;
  1234. (* $CopyArrays- *)
  1235. BEGIN
  1236.   ii := 0;
  1237.   WHILE (tt[ii] # '=') & (tt[ii] # '\000') DO INC (ii); END;
  1238.   RETURN ii;
  1239. END ToolNameLen;
  1240.  
  1241. PROCEDURE (VAR to: TemplOpt) ToolNameLen (tt: ARRAY OF CHAR): LONGINT;
  1242. (* $CopyArrays- *)
  1243. BEGIN
  1244.   IF to.activeName # NIL THEN IF to.activeName^ = "" THEN RETURN 0; END; END;
  1245.   RETURN ToolNameLen (tt);
  1246. END ToolNameLen;
  1247.  
  1248. (****** BlackMagic/CmpToolNames ************************************************
  1249. *
  1250. *   NAME
  1251. *       CmpToolNames -- test two ToolTypes's names for equality
  1252. *
  1253. *   SYNOPSIS
  1254. *       CmpToolNames (tt1, tt2: ARRAY OF CHAR): BOOLEAN;
  1255. *
  1256. *   FUNCTION
  1257. *       Compares two ToolTypes' names 
  1258. *
  1259. *   INPUTS
  1260. *       tt1,tt2  - the ToolType argument strings
  1261. *
  1262. *   RESULT
  1263. *       TRUE if the ToolTypes' names are identical (case insensitive),
  1264. *       FALSE otherwise.
  1265. *
  1266. *   SEE ALSO
  1267. *       ToolNameLen(), GetToolValue()
  1268. *
  1269. *****************************************************************************)
  1270.  
  1271. PROCEDURE CmpToolNames * (tt1, tt2: ARRAY OF CHAR): BOOLEAN;
  1272. (* $CopyArrays- *)
  1273. BEGIN
  1274.   IF ToolNameLen (tt1) = ToolNameLen (tt2) THEN
  1275.     IF u.Strnicmp (tt1, tt2, ToolNameLen (tt1)) = 0 THEN
  1276.       RETURN TRUE;
  1277.     END;  
  1278.   END;  
  1279.   RETURN FALSE;
  1280. END CmpToolNames;
  1281.  
  1282. (****** BlackMagic/GetToolValue ***********************************************
  1283. *
  1284. *   NAME
  1285. *       GetToolValue -- Return LongStrPtr to value part of tt argument str
  1286. *
  1287. *   SYNOPSIS
  1288. *       GetToolValue (tt: ARRAY OF CHAR): LongStrPtr;
  1289. *
  1290. *   FUNCTION
  1291. *       Returns a LongStrPtr to the value part of the provided ToolType
  1292. *       argument string. This is done by getting the length of the name
  1293. *       part with ToolNameLen(), and returning either a pointer
  1294. *       to the next character, or if the next character is '=' a pointer
  1295. *       to the character right after the next charcter.
  1296. *
  1297. *   INPUTS
  1298. *       tt       - the ToolType argument string
  1299. *
  1300. *   RESULT
  1301. *       the LongStrPtr to the value part of the ToolType
  1302. *
  1303. *   SEE ALSO
  1304. *       ToolNameLen(), CmpToolNames()
  1305. *
  1306. *****************************************************************************)
  1307.  
  1308. PROCEDURE GetToolValue * (tt: ARRAY OF CHAR): LongStrPtr;
  1309. VAR
  1310.   l: LONGINT;
  1311. (* $CopyArrays- *)
  1312. BEGIN
  1313.   l := ToolNameLen (tt); IF tt[l] = '=' THEN INC (l); END;
  1314.   RETURN StrIndex (tt, l);
  1315. END GetToolValue;  
  1316.  
  1317. PROCEDURE (VAR to: TemplOpt) GetToolValue (tt: ARRAY OF CHAR): LongStrPtr;
  1318. (* $CopyArrays- *)
  1319. BEGIN
  1320.   IF to.activeName # NIL THEN IF to.activeName^ = "" THEN 
  1321.     RETURN StrIndex (tt, 0);
  1322.   END; END;
  1323.   RETURN GetToolValue (tt);
  1324. END GetToolValue;
  1325.  
  1326.  
  1327. CONST
  1328.   solelyMakeUnused = 0; (* flag for TemplOpt.Free() *)
  1329.  
  1330. PROCEDURE (VAR to: TemplOpt) Free (flags: SET);
  1331. BEGIN
  1332.   IF to.used THEN
  1333.     to.used := FALSE;
  1334.     to.entry^ := to.entryBackUp;
  1335.   END;  
  1336.   IF ~(solelyMakeUnused IN flags) THEN
  1337.     DISPOSE (to.name);
  1338.     FreeDynTT (to.names);
  1339.   END;  
  1340. END Free;
  1341.  
  1342. PROCEDURE (VAR ts: TemplStrT) Free (flags: SET);
  1343. BEGIN
  1344.   ts.Free^ (flags);
  1345.   DISPOSE (ts.string);
  1346. END Free;
  1347.  
  1348. PROCEDURE (VAR tm: TemplMultiT) Free (flags: SET);
  1349. BEGIN
  1350.   tm.Free^ (flags);
  1351.   FreeDynTT (tm.argsArr);
  1352. END Free;
  1353.  
  1354. PROCEDURE (VAR to: TemplOpt) Init (Name        : ARRAY OF CHAR;
  1355.                                    VAR Res     : y.BYTE;
  1356.                                    flags       : SET;           
  1357.                                    VAR TotNames: DynTTPtr      ): BOOLEAN;
  1358. VAR                                   
  1359.   s    : DynStrPtr;
  1360.   i,j,k: LONGINT;
  1361.   ls   : LongStrPtr;
  1362.   
  1363.   PROCEDURE CleanUp (success: BOOLEAN): BOOLEAN;
  1364.   BEGIN
  1365.     DISPOSE (s);
  1366.     IF ~success THEN 
  1367.       FreeDynTT (to.names); 
  1368.       DISPOSE (to.name);
  1369.     END;
  1370.     RETURN success;
  1371.   END CleanUp;
  1372. (* $CopyArrays- *)
  1373. BEGIN
  1374.   s := NIL; to.name := NIL; to.names := NIL; to.activeName := NIL;
  1375.   to.flags := flags; to.used := FALSE;
  1376.   to.entry := y.ADR (Res); to.entryBackUp := to.entry^;
  1377.   IF ~DynAppend (to.name, Name) THEN RETURN CleanUp (FALSE); END;
  1378.   IF ~DynAppend (s, Name) THEN RETURN CleanUp (FALSE); END;
  1379.   s[0] := CHR (0);
  1380.   j := 0; i := 0;
  1381.   LOOP
  1382.     IF (Name[i] = '=') OR (Name[i] = CHR (0)) THEN      
  1383.       st.Cut (Name, j, i-j, s^);
  1384.       k := 0;
  1385.       WHILE TotNames[k] # NIL DO
  1386.         IF (u.Stricmp (s^, TotNames[k]^) = 0) &
  1387.            ~(to IS TemplIgnore) THEN RETURN CleanUp (FALSE); END;
  1388.         INC (k);
  1389.       END;  
  1390.       IF s^ = "" THEN 
  1391.         IF (to.pri > maxType) OR 
  1392.            (keyAttr IN to.flags) THEN RETURN CleanUp (FALSE); END;
  1393.       END;  
  1394.       IF ~DynAppendTT (to.names, s^, {}) THEN RETURN CleanUp (FALSE); END;      
  1395.       IF ~(to IS TemplIgnore) THEN
  1396.         IF ~DynAppendTT (TotNames, s^, {}) THEN RETURN CleanUp (FALSE); END;
  1397.         IF s^ = "" THEN to.pri := to.pri + AddEmptyName; END;
  1398.       END;  
  1399.       j := i+1;
  1400.     END;
  1401.     IF Name[i] = CHR (0) THEN EXIT; END;
  1402.     INC (i);  
  1403.   END;
  1404.   IF to.pri > maxType THEN (* move empty name to the end of array *)
  1405.     i := 0;
  1406.     WHILE to.names[i] # NIL DO
  1407.       IF to.names[i]^ = "" THEN j := i; END;
  1408.       INC (i);
  1409.     END;  
  1410.     DEC (i);
  1411.     ls := to.names[i]; to.names[i] := to.names[j]; to.names[j] := ls;
  1412.   END;      
  1413.   RETURN CleanUp (TRUE);
  1414. END Init;
  1415.  
  1416. PROCEDURE (VAR ts: TemplStrT) Init (Name        : ARRAY OF CHAR;
  1417.                                     VAR Res     : y.BYTE;
  1418.                                     flags       : SET;
  1419.                                     VAR TotNames: DynTTPtr      ): BOOLEAN;
  1420. (* $CopyArrays- *)
  1421. BEGIN
  1422.   ts.string := NIL;
  1423.   RETURN ts.Init^ (Name, Res, flags, TotNames);
  1424. END Init;
  1425.  
  1426. PROCEDURE (VAR ts: TemplStr) Init (Name        : ARRAY OF CHAR;
  1427.                                    VAR Res     : y.BYTE;
  1428.                                    flags       : SET;
  1429.                                    VAR TotNames: DynTTPtr      ): BOOLEAN;
  1430. (* $CopyArrays- *)
  1431. BEGIN
  1432.   ts.pri := str;
  1433.   RETURN ts.Init^ (Name, Res, flags, TotNames);
  1434. END Init;
  1435.  
  1436. PROCEDURE (VAR ts: TemplSwitch) Init (Name        : ARRAY OF CHAR;
  1437.                                       VAR Res     : y.BYTE;
  1438.                                       flags       : SET;           
  1439.                                       VAR TotNames: DynTTPtr      ): BOOLEAN;
  1440. (* $CopyArrays- *)
  1441. BEGIN
  1442.   ts.pri := switch;
  1443.   IF ~ts.Init^ (Name, Res, flags, TotNames) THEN RETURN FALSE; END;
  1444.   IF ts.pri > maxType THEN ts.Free({}); RETURN FALSE; END; (* no empty name please *)
  1445.   RETURN TRUE;
  1446. END Init;
  1447.  
  1448. PROCEDURE (VAR tn: TemplNum) Init (Name         : ARRAY OF CHAR;
  1449.                                    VAR Res      : y.BYTE;
  1450.                                    flags        : SET;           
  1451.                                    VAR TotNames : DynTTPtr      ): BOOLEAN;
  1452. (* $CopyArrays- *)
  1453. BEGIN
  1454.   tn.pri := num;
  1455.   RETURN tn.Init^ (Name, Res, flags, TotNames);
  1456. END Init;
  1457.  
  1458. PROCEDURE (VAR ti: TemplIgnore) Init (Name         : ARRAY OF CHAR;
  1459.                                       VAR Res      : y.BYTE;
  1460.                                       flags        : SET;           
  1461.                                       VAR TotNames : DynTTPtr      ): BOOLEAN;
  1462. (* $CopyArrays- *)
  1463. BEGIN
  1464.   ti.pri := ignore; flags := {};
  1465.   RETURN ti.Init^ (Name, Res, flags, TotNames);
  1466. END Init;
  1467.  
  1468. PROCEDURE (VAR tg: TemplToggle) Init (Name        : ARRAY OF CHAR;
  1469.                                       VAR Res     : y.BYTE;
  1470.                                       flags       : SET;           
  1471.                                       VAR TotNames: DynTTPtr      ): BOOLEAN;
  1472. (* $CopyArrays- *)
  1473. BEGIN
  1474.   tg.pri := toggle;
  1475.   IF ~tg.Init^ (Name, Res, flags, TotNames) THEN RETURN FALSE; END;
  1476.   IF tg.pri > maxType THEN tg.Free({}); RETURN FALSE; END; (* no empty name please *)
  1477.   RETURN TRUE;
  1478. END Init;
  1479.  
  1480. PROCEDURE (VAR tr: TemplRemain) Init (Name        : ARRAY OF CHAR;
  1481.                                       VAR Res     : y.BYTE;
  1482.                                       flags       : SET;           
  1483.                                       VAR TotNames: DynTTPtr      ): BOOLEAN;
  1484. (* $CopyArrays- *)
  1485. BEGIN
  1486.   tr.pri := remain;
  1487.   RETURN tr.Init^ (Name, Res, flags, TotNames);
  1488. END Init;
  1489.  
  1490. PROCEDURE (VAR tm: TemplMultiT) Init (Name        : ARRAY OF CHAR;
  1491.                                       VAR Res     : y.BYTE;
  1492.                                       flags       : SET;           
  1493.                                       VAR TotNames: DynTTPtr      ): BOOLEAN;
  1494. (* $CopyArrays- *)
  1495. BEGIN
  1496.   tm.argsArr := NIL;
  1497.   RETURN tm.Init^ (Name, Res, flags, TotNames);
  1498. END Init;
  1499.  
  1500. PROCEDURE (VAR tm: TemplMulti) Init (Name        : ARRAY OF CHAR;
  1501.                                      VAR Res     : y.BYTE;
  1502.                                      flags       : SET;           
  1503.                                      VAR TotNames: DynTTPtr      ): BOOLEAN;
  1504. (* $CopyArrays- *)
  1505. BEGIN
  1506.   tm.pri := multi;
  1507.   RETURN tm.Init^ (Name, Res, flags, TotNames);
  1508. END Init;
  1509.  
  1510. PROCEDURE (VAR tm: TemplMultiNum) Init (Name        : ARRAY OF CHAR;
  1511.                                         VAR Res     : y.BYTE;
  1512.                                         flags       : SET;           
  1513.                                         VAR TotNames: DynTTPtr      ): BOOLEAN;
  1514. (* $CopyArrays- *)
  1515. BEGIN
  1516.   tm.pri := multiNum;
  1517.   RETURN tm.Init^ (Name, Res, flags, TotNames);
  1518. END Init;
  1519.  
  1520. PROCEDURE DisposeTemplOpt (VAR to: TemplOptPtr);
  1521. BEGIN
  1522.   IF to = NIL THEN RETURN END;
  1523.   to.Free ({});
  1524.   to := NIL;
  1525. END DisposeTemplOpt;
  1526.  
  1527. (* CmpTT flags *)
  1528. CONST
  1529.   specialNo = 0;
  1530.  
  1531. PROCEDURE CmpTT (s : DynTTPtr; tt: ARRAY OF CHAR; flags: SET): LongStrPtr;
  1532. VAR 
  1533.   i    : LONGINT;
  1534.   ls   : LongStrPtr;
  1535. (* $CopyArrays- *)
  1536. BEGIN  
  1537.   IF s = NIL THEN RETURN NIL; END;
  1538.   FOR i := 0 TO LEN (s^)-1 DO
  1539.     IF s[i] = NIL THEN RETURN NIL; END;
  1540.     IF specialNo IN flags THEN
  1541.       IF u.Strnicmp ("NO", s[i]^, 2) = 0 THEN      
  1542.         ls := y.ADR (s[i] [2]);
  1543.         IF (u.Strnicmp (ls^, tt, st.Length (ls^)) = 0) & 
  1544.            (ToolNameLen (tt) = st.Length (ls^)) THEN RETURN s[i]; END;
  1545.       END;  
  1546.       IF u.Strnicmp ("NO", tt, 2) = 0 THEN      
  1547.         ls := y.ADR (tt[2]);
  1548.         IF (u.Strnicmp (s[i]^, ls^, st.Length (s[i]^)) = 0) &
  1549.            (ToolNameLen (ls^) = st.Length (s[i]^)) THEN RETURN s[i]; END;
  1550.       END;
  1551.     ELSE  
  1552.       IF (s[i]^ = "") OR 
  1553.          ((u.Strnicmp (s[i]^, tt, ToolNameLen (tt)) = 0) &
  1554.           (st.Length (s[i]^) = ToolNameLen (tt))) THEN RETURN s[i]; END;
  1555.     END;    
  1556.   END; (* FOR *)
  1557.   RETURN NIL;
  1558. END CmpTT;
  1559.  
  1560. (* to.Process return codes *)
  1561. CONST
  1562.   fail      = 0;
  1563.   ok        = 1;
  1564.   okSwitchT = 2;
  1565.   okSpecNo  = 3;  
  1566.  
  1567. (* to.Cmp return codes *)
  1568. CONST
  1569.   notFound     = 0;
  1570.   found        = 1;
  1571.   foundEmpty   = 2;
  1572.   foundNoSpc   = 3;
  1573.   foundSwitchT = 4;
  1574.  
  1575. PROCEDURE (VAR to: TemplOpt) Cmp (tt    : ARRAY OF CHAR;
  1576.                                   status: LONGINT       ): LONGINT;
  1577. (* $CopyArrays- *)
  1578. BEGIN
  1579.   IF status # fail THEN RETURN notFound; END;
  1580.   to.activeName := CmpTT (to.names, tt, {});
  1581.   IF to.activeName = NIL THEN
  1582.     RETURN notFound;
  1583.   ELSIF to.activeName^ = "" THEN
  1584.     RETURN foundEmpty;
  1585.   ELSE  
  1586.     RETURN found;
  1587.   END;  
  1588. END Cmp;
  1589.  
  1590. PROCEDURE (VAR ti: TemplIgnore) Cmp (tt    : ARRAY OF CHAR;
  1591.                                    status: LONGINT       ): LONGINT;
  1592. VAR 
  1593. (* $CopyArrays- *)
  1594. BEGIN
  1595.   RETURN notFound;
  1596. END Cmp;  
  1597.  
  1598. PROCEDURE (VAR ts: TemplSwitchT) Cmp (tt    : ARRAY OF CHAR;
  1599.                                       status: LONGINT       ): LONGINT;
  1600. VAR
  1601.   s        : LongStrPtr;
  1602. (* $CopyArrays- *)
  1603. BEGIN
  1604.   IF status # okSwitchT THEN
  1605.     IF ts.Cmp^ (tt, fail) = found THEN RETURN foundSwitchT; END; (* foundEmpty impossible for TemplSwitchT! *)
  1606.   END;  
  1607.   IF (status = okSpecNo) OR (disableSpecialNo IN ts.flags) THEN RETURN notFound; END;
  1608.   ts.activeName := CmpTT (ts.names, tt, {specialNo});
  1609.   IF ts.activeName = NIL THEN RETURN notFound; END;
  1610.   s := ts.GetToolValue (tt);
  1611.   IF (s^ = "") OR ic.MatchToolValue (s^, "FALSE") OR 
  1612.          ic.MatchToolValue (s^, "NO") OR ic.MatchToolValue (s^, "TRUE") OR
  1613.          ic.MatchToolValue (s^, "YES") THEN
  1614.     RETURN foundNoSpc;       
  1615.   END;    
  1616.   RETURN notFound;
  1617. END Cmp;
  1618.  
  1619. PROCEDURE (VAR to: TemplOpt) Process (tt: ARRAY OF CHAR): LONGINT;
  1620. (* $CopyArrays- *)
  1621. BEGIN
  1622.   RETURN fail;
  1623. END Process;
  1624.  
  1625. PROCEDURE (VAR ts: TemplStr) Process (tt: ARRAY OF CHAR): LONGINT;
  1626. (* $CopyArrays- *)
  1627. BEGIN
  1628.   IF ts.used THEN RETURN fail; END;
  1629.   IF ~DynAppend (ts.string, ts.GetToolValue (tt)^) THEN RETURN fail; END;
  1630.   ts.entry^ := DStrLPtr (ts.string);
  1631.   ts.used := TRUE;
  1632.   RETURN ok;
  1633. END Process;
  1634.  
  1635. PROCEDURE (VAR tr: TemplRemain) Process (tt: ARRAY OF CHAR): LONGINT;
  1636. (* $CopyArrays- *)
  1637. BEGIN
  1638.   IF tr.used & (noFullMulti IN tr.flags) THEN RETURN fail; END; 
  1639.   IF tr.string # NIL THEN 
  1640.     IF ~DynAppend (tr.string, " ") THEN RETURN fail; END;
  1641.   END;  
  1642.   IF ~DynAppend (tr.string, tr.GetToolValue (tt)^) THEN RETURN fail; END;
  1643.   tr.entry^ := DStrLPtr (tr.string);
  1644.   tr.used := TRUE;
  1645.   RETURN ok;
  1646. END Process;
  1647.  
  1648. PROCEDURE (VAR ts: TemplSwitch) Process (tt: ARRAY OF CHAR): LONGINT;
  1649. VAR
  1650.   val      : LONGINT;
  1651.   specialno: BOOLEAN;
  1652. (* $CopyArrays- *)
  1653. BEGIN
  1654.   IF ts.used THEN RETURN fail; END;
  1655.   specialno := CmpTT (ts.names, tt, {}) = NIL;
  1656.   val := I.LTRUE;
  1657.   LOOP    
  1658.     IF ts.GetToolValue (tt)^ = "" THEN EXIT END;
  1659.     IF ic.MatchToolValue (ts.GetToolValue (tt)^, "TRUE") OR 
  1660.        ic.MatchToolValue (ts.GetToolValue (tt)^, "YES") THEN
  1661.       IF ic.MatchToolValue (ts.GetToolValue (tt)^, "FALSE") OR
  1662.          ic.MatchToolValue (ts.GetToolValue (tt)^, "NO") THEN RETURN fail; END;
  1663.       EXIT;
  1664.     END;
  1665.     IF ~ic.MatchToolValue (ts.GetToolValue (tt)^, "FALSE") &
  1666.        ~ic.MatchToolValue (ts.GetToolValue (tt)^, "NO") THEN RETURN fail; END;
  1667.     val := I.LFALSE;
  1668.     EXIT;
  1669.   END;
  1670.   IF specialno THEN
  1671.     IF val = I.LTRUE THEN val := I.LFALSE; ELSE val := I.LTRUE; END;
  1672.   END;
  1673.   ts.entry^ := val;
  1674.   ts.used := TRUE;
  1675.   IF specialno THEN RETURN okSpecNo; ELSE RETURN okSwitchT; END;
  1676. END Process;
  1677.  
  1678. PROCEDURE (VAR tg: TemplToggle) Process (tt: ARRAY OF CHAR): LONGINT;
  1679. VAR
  1680.   val       : LONGINT;
  1681.   specialno : BOOLEAN;
  1682. (* $CopyArrays- *)
  1683. BEGIN
  1684.   IF tg.used THEN RETURN fail; END;
  1685.   specialno := CmpTT (tg.names, tt, {}) = NIL;
  1686.   val := I.LTRUE;
  1687.   LOOP
  1688.     IF tg.GetToolValue (tt)^ = "" THEN
  1689.       IF ~specialno THEN
  1690.         IF tg.entry^ = 0 THEN val := I.LTRUE; ELSE val := I.LFALSE; END;
  1691.       END;
  1692.       EXIT;
  1693.     END;
  1694.     IF ic.MatchToolValue (tg.GetToolValue (tt)^, "TRUE") OR
  1695.        ic.MatchToolValue (tg.GetToolValue (tt)^, "YES") THEN
  1696.       IF ic.MatchToolValue (tg.GetToolValue (tt)^, "FALSE") OR
  1697.          ic.MatchToolValue (tg.GetToolValue (tt)^, "NO") THEN RETURN fail; END;
  1698.       EXIT;
  1699.     END;
  1700.     IF ~ic.MatchToolValue (tg.GetToolValue (tt)^, "FALSE") &
  1701.        ~ic.MatchToolValue (tg.GetToolValue (tt)^, "NO") THEN RETURN fail; END;
  1702.     val := I.LFALSE;
  1703.     EXIT;
  1704.   END;
  1705.   IF specialno THEN 
  1706.     IF val = I.LTRUE THEN val := I.LFALSE; ELSE val := I.LTRUE; END;
  1707.   END;
  1708.   tg.entry^ := val;
  1709.   tg.used := TRUE;
  1710.   IF specialno THEN RETURN okSpecNo; ELSE RETURN okSwitchT; END;
  1711. END Process;
  1712.  
  1713.  
  1714. (****** BlackMagic/StrToLong ************************************************
  1715. *
  1716. *   NAME
  1717. *       StrToLong - convert (hexa)decimal string to integer representation
  1718. *
  1719. *   SYNOPSIS
  1720. *       StrToLong (str: ARRAY OF CHAR; VAR result: LONGINT): BOOLEAN;
  1721. *
  1722. *   FUNCTION
  1723. *       StrToLong converts a (hexa)decimal string representatation of an
  1724. *       integer into an integer. Leading white space chars are skipped,
  1725. *       then a sign char ('+','-') may occur, followed by decimal digits
  1726. *       or a '0x', '0X' or '[Dollar]' hex identifier followed by hex digits.
  1727. *       After the digits sequence, any number of white space chars may
  1728. *       terminate the string.
  1729. *
  1730. *   INPUTS
  1731. *       str      - the string holding the number
  1732. *       result   - the variable that will hold the resulting integer
  1733. *                  if a valid number is read. 
  1734. *
  1735. *   RESULT
  1736. *       TRUE if a number was successfully read into the result variable,
  1737. *         false otherwise
  1738. *       FALSE if an error occurred. In that case the result variable holds
  1739. *         the generated number at the very stage when the error occurred.
  1740. *
  1741. ****************************************************************************)
  1742.  
  1743. PROCEDURE StrToLong * (str: ARRAY OF CHAR; VAR result: LONGINT): BOOLEAN;
  1744. VAR
  1745.   i: LONGINT;
  1746.   c: INTEGER;
  1747.   neg: BOOLEAN;
  1748.   hex: BOOLEAN;
  1749.   base: INTEGER;
  1750. (* $CopyArrays- $OvflChk- *)
  1751. BEGIN
  1752.   result := 0; i := 0; neg := FALSE; hex := FALSE;
  1753.   WHILE (str[i] = ' ') OR (str[i] = '\t') DO INC (i); END;
  1754.   CASE str[i] OF
  1755.   '+': INC (i); |
  1756.   '-': neg := TRUE; INC (i);
  1757.   ELSE END;
  1758.   CASE str[i] OF  
  1759.   '$': hex := TRUE; INC (i); |
  1760.   '0': IF CAP(str[i+1])='X' THEN hex := TRUE; INC (i,2); END;
  1761.   ELSE END;
  1762.   IF ~hex THEN base := 10; ELSE base := 16; END;
  1763.   LOOP
  1764.     c := ORD (CAP (str[i]));
  1765.     CASE c OF
  1766.     ORD('0')..ORD('9'):
  1767.       c := c - ORD ('0'); |
  1768.     ORD('A')..ORD('F'):
  1769.       IF ~hex THEN y.SETREG (0, d.SetIoErr (d.badNumber)); RETURN FALSE; END;
  1770.       c := c - ORD ('A') + 10;
  1771.     ELSE  
  1772.       LOOP
  1773.         CASE str[i] OF
  1774.         CHR (0)  : IF neg THEN result := - result; END; RETURN TRUE; |
  1775.         ' ', '\t': INC (i); |
  1776.         ELSE y.SETREG (0, d.SetIoErr (d.badNumber)); RETURN FALSE; END;
  1777.       END;  
  1778.     END;  
  1779.     result := base * result + c;
  1780.     INC (i);
  1781.   END;  
  1782. END StrToLong;
  1783. (* $OvflChk= *)
  1784.  
  1785. PROCEDURE (VAR tn: TemplNum) Process (tt: ARRAY OF CHAR): LONGINT;
  1786. (* $CopyArrays- *)
  1787. BEGIN
  1788.   IF tn.used THEN RETURN fail; END;
  1789.   IF ~StrToLong (tn.GetToolValue (tt)^, tn.num) THEN RETURN fail; END;
  1790.   tn.entry^ := y.ADR (tn.num);
  1791.   tn.used := TRUE;
  1792.   RETURN ok;
  1793. END Process;
  1794.  
  1795. PROCEDURE (VAR tm: TemplMultiT) Process (tt: ARRAY OF CHAR): LONGINT;
  1796. VAR
  1797.   ds      : DynStrPtr;
  1798.   s1      : LongStrPtr;
  1799.   c1,c2,i : LONGINT;
  1800.   num     : LONGINT;
  1801.  
  1802.   PROCEDURE CleanUp();
  1803.   BEGIN
  1804.     DISPOSE (ds);
  1805.     WHILE i>0 DO IF RemDynTTEntry (tm.argsArr, -1) THEN END; DEC (i); END;
  1806.   END CleanUp;
  1807.  
  1808.   PROCEDURE ArgFil (): BOOLEAN;
  1809.   BEGIN
  1810.     RETURN (((u.Stricmp (tm.activeName^, "FILE")=0)  & (argFile  IN tm.flags)) OR
  1811.             ((u.Stricmp (tm.activeName^, "FILES")=0) & (argFiles IN tm.flags))   ) &
  1812.            ~(requestArg IN tm.flags) 
  1813.   END ArgFil;         
  1814.  
  1815. (* $CopyArrays- *)
  1816. BEGIN
  1817.   ds := NIL; i := 0; c1 := 0; c2 := 0; s1 := NIL;
  1818.   IF tm.used & (noMultiMulti IN tm.flags) & ~ArgFil() THEN CleanUp(); RETURN fail; END;  
  1819.   s1 := tm.GetToolValue (tt);
  1820.   IF ~DynAppend (ds, s1^) THEN CleanUp(); RETURN fail; END;
  1821.   ds[0] := CHR (0);
  1822.   LOOP
  1823.     IF ((((s1[c2] = ',') & (multiCommaSep IN tm.flags)) OR
  1824.         ((s1[c2] = '|') & (multiBarSep IN tm.flags))) & ~ArgFil()) OR
  1825.        (s1[c2] = CHR (0)) THEN
  1826.       st.Cut (s1^, c1, c2-c1, ds^);
  1827.       WITH tm: TemplMultiNum DO
  1828.         IF ~StrToLong (ds^, num) THEN CleanUp(); RETURN fail; END;
  1829.         IF ~DynAppendTT (tm.argsArr, num, {noNulTerm}) THEN CleanUp(); RETURN fail; END; |
  1830.       tm: TemplMulti DO 
  1831.         IF ~DynAppendTT (tm.argsArr, ds^, {}) THEN CleanUp(); RETURN fail; END;
  1832.       END;  
  1833.       INC (i);
  1834.       IF s1[c2] = CHR (0) THEN EXIT; END;
  1835.       c1 := c2+1;
  1836.     END;  
  1837.     INC (c2);
  1838.   END; (* LOOP *)  
  1839.   i := 0;
  1840.   tm.entry^ := TTAPtr (tm.argsArr);
  1841.   CleanUp();
  1842.   tm.used := TRUE;
  1843.   RETURN ok;
  1844. END Process;
  1845.  
  1846.  
  1847. PROCEDURE (VAR to: TemplOpt) EntryToTT (): DynStrPtr;
  1848. BEGIN
  1849.   RETURN NIL;
  1850. END EntryToTT;  
  1851.  
  1852. PROCEDURE (VAR ts: TemplStrT) EntryToTT (): DynStrPtr;
  1853. VAR
  1854.   ls: LStrPtr;
  1855.   ds: DynStrPtr;
  1856. BEGIN
  1857.   IF ~InitDynStr (ds) THEN RETURN NIL; END;
  1858.   ls := ts.entry^;
  1859.   IF ls # NIL THEN 
  1860.     IF ~DynAppend (ds, ls^) THEN DISPOSE (ds); END; 
  1861.   END;  
  1862.   RETURN ds;
  1863. END EntryToTT;  
  1864.  
  1865. PROCEDURE (VAR ts: TemplSwitchT) EntryToTT (): DynStrPtr;  
  1866. VAR
  1867.   ds: DynStrPtr;
  1868. BEGIN  
  1869.   ds := NIL;
  1870.   IF ~DynAppend (ds, "FALSE") THEN RETURN NIL; END;
  1871.   IF ts.entry^ # NIL THEN COPY ("TRUE", ds^); END;
  1872.   RETURN ds;
  1873. END EntryToTT;  
  1874.  
  1875. PROCEDURE^ VDSPrintf * (VAR dstr: DynStrPtr;
  1876.                         format  : ARRAY OF CHAR;
  1877.                         args    : e.APTR        ): BOOLEAN;
  1878.  
  1879. PROCEDURE^ VDynFmtLocale * (VAR dstr: DynStrPtr;
  1880.                             locale  : loc.LocalePtr;
  1881.                             format  : ARRAY OF CHAR;
  1882.                             args    : e.APTR        ): BOOLEAN;
  1883.  
  1884. PROCEDURE (VAR tn: TemplNum) EntryToTT (): DynStrPtr;
  1885. VAR
  1886.   ds: DynStrPtr;
  1887. BEGIN  
  1888.   IF ~InitDynStr (ds) THEN RETURN NIL; END;
  1889.   IF tn.entry^ # NIL THEN
  1890.     IF ~VDSPrintf (ds, "%ld", tn.entry^) THEN DISPOSE (ds); END;
  1891.   END;  
  1892.   RETURN ds;
  1893. END EntryToTT;  
  1894.  
  1895. CONST 
  1896.   numFmt = "%ld%lc";
  1897.   strFmt = "%s%lc";
  1898.  
  1899. PROCEDURE^ Max2 * (x, y: LONGINT): LONGINT;
  1900.  
  1901. PROCEDURE (VAR tm: TemplMultiT) EntryToTT (): DynStrPtr;
  1902. VAR
  1903.   ds: DynStrPtr;
  1904.   ls: LStrPtr;
  1905.   ar: APtrVecPtr;
  1906.   i : LONGINT;
  1907.   pa: ARRAY 2 OF e.APTR;
  1908.   
  1909. BEGIN  
  1910.   IF ~InitDynStr (ds) THEN RETURN NIL; END;
  1911.   IF tm.flags * {multiCommaSep,multiBarSep} = {} THEN
  1912.     WITH tm: TemplMultiNum DO
  1913.       INCL (tm.flags, multiCommaSep); |
  1914.     tm: TemplMulti DO
  1915.       INCL (tm.flags, multiBarSep);
  1916.     END;  
  1917.   END;
  1918.   ar := tm.entry^;
  1919.   IF ar # NIL THEN
  1920.     WITH tm: TemplMultiNum DO
  1921.       ls := StrIndex (numFmt, 0); |
  1922.     tm: TemplMulti DO  
  1923.       ls := StrIndex (strFmt, 0);
  1924.     END;  
  1925.     IF multiCommaSep IN tm.flags THEN pa[1] := ORD (','); ELSE pa[1] := ORD ('|'); END;
  1926.     i := 0;
  1927.     WHILE ar[i] # NIL DO
  1928.       WITH tm: TemplMultiNum DO
  1929.         pa[0] := ar[i]^; |
  1930.       tm: TemplMulti DO  
  1931.         pa[0] := ar[i];
  1932.       END;  
  1933.       IF ~VDSPrintf (ds, ls^, y.ADR (pa[0])) THEN DISPOSE (ds); RETURN NIL; END;
  1934.       INC (i);
  1935.     END; (* WHILE *)  
  1936.     ds [Max2 (0, st.Length(ds^)-1)] := '\000';
  1937.   END; (* IF ar # NIL *)  
  1938.   RETURN ds;
  1939. END EntryToTT;  
  1940.  
  1941. PROCEDURE^ GetCatalogStr * (catalog: loc.CatalogPtr; 
  1942.                             string : ARRAY OF CHAR  ): LongStrPtr;
  1943.  
  1944. PROCEDURE (VAR to: TemplOpt) ReqPrompt (): DynStrPtr;
  1945. VAR
  1946.   ds: DynStrPtr;
  1947.   typeStr, opt: LStrPtr;
  1948.   a : ARRAY 3 OF e.APTR;
  1949. (* $CopyArrays- *)
  1950. BEGIN
  1951.   ds := NIL; typeStr := NIL; opt := NIL;
  1952.   WITH to: TemplStr DO
  1953.     typeStr := StrIndex (bs.itemString, 0); opt := StrIndex ("", 0); |
  1954.   to: TemplRemain  DO
  1955.     typeStr := StrIndex (bs.itemString, 0); opt := StrIndex ("/R", 0); |
  1956.   to: TemplSwitch DO  
  1957.     typeStr := StrIndex (bs.itemBool, 0); opt := StrIndex ("/S", 0); |
  1958.   to: TemplToggle DO
  1959.     typeStr := StrIndex (bs.itemBool, 0); opt := StrIndex ("/T", 0); |
  1960.   to: TemplNum DO  
  1961.     typeStr := StrIndex (bs.itemInteger, 0); opt := StrIndex ("/N", 0); |
  1962.   to: TemplMulti DO  
  1963.     IF multiCommaSep IN to.flags THEN
  1964.       typeStr := StrIndex (bs.itemStringsCommaSep, 0);
  1965.     ELSE  
  1966.       typeStr := StrIndex (bs.itemStringsBarSep, 0);
  1967.     END;  
  1968.     opt := StrIndex ("/M", 0); |
  1969.   to: TemplMultiNum DO  
  1970.     IF multiCommaSep IN to.flags THEN
  1971.       typeStr := StrIndex (bs.itemIntegersCommaSep, 0);
  1972.     ELSE  
  1973.       typeStr := StrIndex (bs.itemIntegersBarSep, 0);
  1974.     END;  
  1975.     opt := StrIndex ("/M/N", 0);
  1976.   END;  
  1977.   a[0] := GetCatalogStr (bs.DefaultCatalog, typeStr^);
  1978.   a[1] := StrIndex (to.name^, 0);
  1979.   a[2] := opt;
  1980.   IF ~VDynFmtLocale (ds, NIL, GetCatalogStr (bs.DefaultCatalog, 
  1981.                                              bs.fmtRequestArgPrompt)^,
  1982.                      y.ADR (a[0])) THEN DISPOSE (ds); END;
  1983.   RETURN ds;               
  1984. END ReqPrompt;  
  1985.  
  1986. PROCEDURE FreeTemplArr (Arr: TemplArrT);
  1987. VAR
  1988.   i: LONGINT;
  1989. BEGIN
  1990.   IF Arr = NIL THEN RETURN; END;
  1991.   FOR i := 0 TO LEN (Arr^)-1 DO
  1992.     IF Arr[i] # NIL THEN
  1993.       Arr[i].Free({});
  1994.       DISPOSE (Arr[i]);
  1995.     END;
  1996.   END;
  1997.   DISPOSE (Arr);
  1998. END FreeTemplArr;
  1999.  
  2000. CONST
  2001.   askMagic = "ASK:";
  2002.  
  2003. PROCEDURE (VAR to: TemplOpt) SkipAskMagic (tt    : ARRAY OF CHAR;
  2004.                                            found : LONGINT       ): LStrPtr;
  2005. VAR
  2006.   i: LONGINT;
  2007. (* $CopyArrays- *)
  2008. BEGIN  
  2009.   IF (found # foundEmpty) & (allowAskArg IN to.flags) &
  2010.      (u.Strnicmp (tt, askMagic, 4) = 0) THEN i := 4; ELSE i := 0; END;
  2011.   RETURN StrIndex (tt, i);
  2012. END SkipAskMagic;
  2013.  
  2014.  
  2015. (* ReqTools V38 definitions: *)
  2016. VAR
  2017.   req: e.LibraryPtr;
  2018.  
  2019. PROCEDURE rtGetString {req, -72} (VAR buffer{9}: ARRAY OF CHAR;
  2020.                                   maxchars{0}: LONGINT;
  2021.                                   title{10}: ARRAY OF CHAR;
  2022.                                   reqInfo{11}: e.APTR;
  2023.                                   tag1{8}..: u.Tag): BOOLEAN;
  2024.  
  2025. CONST
  2026.   rtTagBase    = u.user;
  2027.   gsFlags      = rtTagBase+22;
  2028.   gsTextFmt    = rtTagBase+38;
  2029.   gsTextFmtArgs= rtTagBase+39;
  2030.   gsAllowEmpty = rtTagBase+80;
  2031.   
  2032.   gsReqCenterText = 2;
  2033.   
  2034. (****** BlackMagic/ReadArgsTT *************************************************
  2035. *
  2036. *   NAME
  2037. *       ReadArgsTT -- Parse ToolType's input similar to Dos.ReadArgs()
  2038. *
  2039. *   SYNOPSIS
  2040. *       ReadArgsTT (tmpl             : ARRAY OF CHAR;
  2041. *                   args             : ARRAY OF y.BYTE;
  2042. *                   ttTool, ttProject: TTPtr;
  2043. *                   flags            : SET             ): RDArgsWBPtr;
  2044. *
  2045. *   FUNCTION
  2046. *       This function is a very versatile and powerful ToolTypes parse
  2047. *       routine, supplying you with all the flexibility of current 
  2048. *       Dos.ReadArgs, plus access to the ToolTypes that weren't used
  2049. *       to fill the argument fields, as well as to the ones used.
  2050. *       This function is also well-suited for filtering ToolTypes, 
  2051. *       manipulating the ToolTypes of one or more DiskObjects, merging
  2052. *       ToolTypes of two DiskObjects into one ToolType array, etc.
  2053. *       The aim of this function was also to follow the Amiga User Style 
  2054. *       Guide's claim that the project's ToolTypes should be merged with
  2055. *       the tool's  ToolTypes, while the project's ToolTypes supercede the
  2056. *       tool's ones, etc. This function may be controlled using several
  2057. *       flags, resulting in thorough-going configurability of its behaviour
  2058. *       in fields like handling of /M,/F,/T & /S options. Furthermore this 
  2059. *       function is quite fool-proof to a certain extent, and accepts only
  2060. *       sensible command line templates. Starting with Version 1.10,
  2061. *       missing, required or user-definable template entries may be requested
  2062. *       through string requesters if reqtools.library V38 or higher (which is
  2063. *       ⌐ Nico Franτois) is installed in the system running your software.
  2064. *       The requester itself is localized and pops with an equivalent string
  2065. *       of the current contents of the appertaining argument array.
  2066. *
  2067. *   INPUTS
  2068. *       tmpl     - A command line template as defined in the the
  2069. *                  documentation of Dos.ReadArgs() For a complete
  2070. *                  description, look there. Full support for aliases/
  2071. *                  abbreviations ("Quit=Q/S" or "Multi=/S" etc.) 
  2072. *                  is available.
  2073. *                  
  2074. *                  Possible types of template options:
  2075. *             
  2076. *                  no specifier - string
  2077. *                  The action of this option template is to fill
  2078. *                  the arguemnt entry with the string value of the
  2079. *                  first matching ToolType.
  2080. *                   
  2081. *                  /N  - number
  2082. *                  The argument entry is filled with a pointer to
  2083. *                  an integer, or left unchanged if not provided
  2084. *                  In addidtion to decimal numbers, hexadecimal numbers
  2085. *                  are accepted if they are preceded by a [Dollar] or '0x'
  2086. *                  If no valid number is provided, the entry is left
  2087. *                  unchanged.
  2088. *                  
  2089. *                  /S  - switch  -- implies option modifier /K
  2090. *                  The argument entry is filled with -1 (LTRUE) if
  2091. *                  the keyword is specified as a ToolType with no
  2092. *                  value or values YES or TRUE. It is filled with
  2093. *                  0 (LFALSE) if the ToolType has NO or FALSE as its
  2094. *                  value. There is also, if you don't supply the flag
  2095. *                  disableSpecialNo, a more extentsive recognition:
  2096. *                  If the template option and a tooltype name
  2097. *                  match each other except a missing prefix 'NO' of one of
  2098. *                  them, after
  2099. *                  checking all other options' non-empty names for exact
  2100. *                  equality (as oppposed to 'NO'-prefix equality), the
  2101. *                  ToolType is considered to fit for that /S option:
  2102. *                  If the ToolType has no value, or it's value is YES or
  2103. *                  TRUE, the arguemnt entry will be filled with a 0 (LFALSE)
  2104. *                  If it's value is FALSE or NO, the entry will be filled
  2105. *                  with -1 (LTRUE). Note that in any case, if the ToolType
  2106. *                  value is not empty, TRUE, YES, FALSE or NO, no action will
  2107. *                  take place, and in the case of 'NO'-prefix equality the
  2108. *                  ToolType won't be considered to appertain to this option.
  2109. *
  2110. *                  /T - toggle  -- implies option modifier /K
  2111. *                  The action for this option type exactly follows the
  2112. *                  description of the /S (switch) option except that
  2113. *                  in the case of exact equality (not 'NO'-prefix equality)
  2114. *                  if the ToolType has no value assigned, the action will
  2115. *                  toggle the arguemnt entry: if it is 0 (LFALSE),
  2116. *                  it will turn into -1 (LTRUE), otherwise it will turn into
  2117. *                  LFALSE.
  2118. *
  2119. *                  /M - Multi
  2120. *                  The argument entry is filled with a pointer to a NIL-
  2121. *                  terminated array of pointers to strings.
  2122. *                  The action for this option type is heavily influenced
  2123. *                  by the following flags:
  2124. *                  noMultiMulti:The first matching ToolType is considered
  2125. *                    only - all later matches will be ignored. Useful in
  2126. *                    connection with the other flags:
  2127. *                  multiBarSep: Considers the ToolType value string to
  2128. *                    consist of several differnt strings, seperated
  2129. *                    by vertical bars (|)
  2130. *                  multiCommaSep: Same goes for this - yet the separators
  2131. *                    are commas (,) in this case.
  2132. *
  2133. *                  /M/N - MultiNum
  2134. *                  The action for this is the same as for /M (Multi) type,
  2135. *                  except that the tooltype values must be numbers, and
  2136. *                  the argument entry is filled with a pointer to an array
  2137. *                  of pointers to LONGINTs (32 bit integers) For more
  2138. *                  information also look at the /N (number) option type.
  2139. *                  Note that if there are one or more invalid numbers
  2140. *                  in a ToolType value, and multi****Sep is enabled,
  2141. *                  no number of that ToolType will be regarded to be valid.
  2142. *
  2143. *                  /F - Full remainder
  2144. *                  All matching ToolType values will be joined, with one
  2145. *                  whitespace separator between them, and the argument
  2146. *                  entry will be filled with a pointer to that string.
  2147. *                  This type is affected by the noFullMulti flag. If it is
  2148. *                  specified, only the first matching ToolType will match,
  2149. *                  all other following matching ToolTypes are ignored, i.e.
  2150. *                  the action is the same as with simple String option type.
  2151. *
  2152. *                  /I - Ignore
  2153. *                  Yes, you,re right!;-) This is just a dummy entry, which
  2154. *                  will never match, however, space in the argument entry
  2155. *                  array for this option must be present.
  2156. *                 
  2157. *                possible modifiers:
  2158. *                  /K - key attribute
  2159. *                  require the specification of one of the option's  alias
  2160. *                  names as the ToolType name - excludes the possibilty of
  2161. *                  specifying empty ("") aliases. This attribute is
  2162. *                  implicitely specified with the /S and /T option types.
  2163. *                  /A - always attribute
  2164. *                  this attribute causes ReadArgsTT() to fail if the
  2165. *                  respective argument entry could not be filled from the
  2166. *                  supplied ToolType array handles.
  2167. *
  2168. *                Priority of filling up arguement entries:
  2169. *                  String entries are filled first, then Numeric entries,
  2170. *                  then Switch entries, then Toggle entries, then
  2171. *                  MultiNum entries, then FullRest (/F) entries, and
  2172. *                  at last Multi entries. In addition, all matching name 
  2173. *                  aliases that are not empty ("") are filled before any
  2174. *                  entry of any type whatsoever that only matches because
  2175. *                  of an empty name alias match (Empty name aliases match
  2176. *                  any tooltype whatsoever, and their possible name part
  2177. *                  is considered to be part of the value string!) The 
  2178. *                  priority is also broken by the 'NO'-prefix equality
  2179. *                  match of /S and /T -type option entries: Any exact
  2180. *                  match of any not empty name alias is preferred to them.
  2181. *                  
  2182. *                Two remarks of significance: One ToolType may -of course-
  2183. *                only match one option entry, and any name alias may only
  2184. *                occure once -except for /I ignore type options: they are
  2185. *                always ignored- otherwise, failure is returned.
  2186. *
  2187. *       args     - an array or structure to hold the argument entries -
  2188. *                  four bytes per template option large at least. You may
  2189. *                  predefine the entries with your default values: if no
  2190. *                  valid matching tooltype is found, and successfully
  2191. *                  processed, no changes are made to the pertinent entry.
  2192. *                  However, if ReadArgsTT() returns failure, you may _NOT_
  2193. *                  assume, that no changes have been made to the predefined
  2194. *                  defaults.
  2195. *
  2196. *       ttTool & - ordinary, 'conventional' ToolType array handles, as 
  2197. *       ttProject  opposed to dynamic ones (which can be converted to
  2198. *                   conventional ones by TTAPtr() ). May be NIL or simple
  2199. *                   Exec.APTRs, etc.
  2200. *
  2201. *       flags    - No, One or several of noFullMulti, noMultiMulti,
  2202. *                  multiBarSep, multiCommaSep, disableSpecialNo,
  2203. *                  dontFill, allowAskArg, askEmpty & askEmptyOnAlways.
  2204. *                  dontFill has the effect that the args argument
  2205. *                  is ignored, thus you won't get any values of the
  2206. *                  template options specified within the ToolTypes reported.
  2207. *                  This is useful when you want to use this function solely
  2208. *                  as an inclusion/exclusion filter for your ToolTypes.
  2209. *                  The allowAskArg, askEmpty & askEmptyOnAlways flags control
  2210. *                  the popping of argument requesters on systems that run
  2211. *                  reqtools.library V38 or higher:
  2212. *                  - allowAskArg enables user control of popping:
  2213. *                    Every successfully processed ToolType entry that 
  2214. *                    matches because of any non-empty template name alias
  2215. *                    that has a magic 'ASK:' - prefix in front of the
  2216. *                    ToolType name itself will pop a string requester
  2217. *                    that asks you for a valid argument string for that
  2218. *                    entry.
  2219. *                  - askEmpty makes ReadArgsTT() pop a requester for each
  2220. *                    template entry that couldn't be filled from the supplied
  2221. *                    ToolTypes.
  2222. *                  - askEmptyOnAlways has exactly the same effect as askEmpty
  2223. *                    except that only requesters for required (/A) template 
  2224. *                    entries are popped.
  2225. *                  The description of the other flags is given in the 
  2226. *                  section about the tmpl input argument. NOTE: DON'T 
  2227. *                  specify any OTHER flags, since strange things may happen
  2228. *                  if you specify flags apart from those documented here!!
  2229. *
  2230. *   RESULT
  2231. *       RDArgsWBPtr
  2232. *                - A pointer to a RECORD RDArgsWB, which contains
  2233. *                  two dynamic ToolType array handles, one containing 
  2234. *                  all ToolTypes that have been used while parsing the
  2235. *                  template, and one with all those ToolTypes that
  2236. *                  remain unparsed. You can manipulate them using
  2237. *                  the dynamic ToolType array manipulation functions
  2238. *                  of this module. This gives an enormous burst of
  2239. *                  versatility and usefulness for this function - you
  2240. *                  can use it just to filter normal ToolTypes arrays
  2241. *                  multiple times, discarding the Dos.ReadArgs()
  2242. *                  functionality of this function.
  2243. *                  NIL is this function's failure indicator.
  2244. *
  2245. *
  2246. *   NOTES
  2247. *       Remember what I said in the discussion of the flags input parameter
  2248. *       section.
  2249. *
  2250. *   SEE ALSO
  2251. *       FreeArgsWB(), ReadArgsWBMsg(), ReadArgsWB(), TTAPtr()
  2252. *
  2253. *****************************************************************************)
  2254.  
  2255. PROCEDURE^ SubPtr * (a, b: e.APTR): e.APTR;
  2256.  
  2257. PROCEDURE ReadArgsTT * (tmpl             : ARRAY OF CHAR;
  2258.                         args             : ARRAY OF y.BYTE;
  2259.                         ttTool, ttProject: TTPtr;
  2260.                         flags            : SET             ): RDArgsWBPtr;
  2261.  
  2262. VAR
  2263.   ToolEnd, ProjectEnd     : BOOLEAN;
  2264.   ttCurr                  : LONGINT;
  2265.   tt                      : LongStrPtr;
  2266.   TmplArr                 : TemplArrT;
  2267.   Rda                     : RDArgsWBPtr;
  2268.   i,j                     : LONGINT;
  2269.   ret, status, fnd        : LONGINT;
  2270.   ttUsed                  : BOOLEAN;
  2271.   ReqBuf, ReqStr, ReqTitle: DynStrPtr;
  2272.  
  2273.   PROCEDURE CleanUp(err: LONGINT);
  2274.   BEGIN
  2275.     DISPOSE (ReqBuf); DISPOSE (ReqStr); DISPOSE (ReqTitle);
  2276.     FreeTemplArr (TmplArr);
  2277.     IF (err # 0) & (d.IoErr() = 0) THEN 
  2278.       y.SETREG (0, d.SetIoErr (err));
  2279.     END;  
  2280.   END CleanUp;
  2281.  
  2282.   PROCEDURE GetTT(): LongStrPtr;
  2283.   BEGIN
  2284.     IF ~ProjectEnd THEN
  2285.       IF ttProject # NIL THEN
  2286.         IF ttProject^[ttCurr] # NIL THEN
  2287.           INC (ttCurr);
  2288.           RETURN ttProject^[ttCurr-1];
  2289.         END;
  2290.       END;
  2291.       ProjectEnd := TRUE;
  2292.       ttCurr:=0;
  2293.     END;
  2294.     IF ToolEnd THEN
  2295.       RETURN NIL;
  2296.     END;
  2297.     IF ttTool # NIL THEN
  2298.       IF ttTool^[ttCurr] # NIL THEN
  2299.         INC (ttCurr);
  2300.         RETURN ttTool^[ttCurr-1];
  2301.       END;
  2302.     END;
  2303.     ToolEnd := TRUE;
  2304.     RETURN NIL;
  2305.   END GetTT;
  2306.  
  2307.   PROCEDURE ParseTemplate(): BOOLEAN;
  2308.   VAR
  2309.     i, j, n : LONGINT;
  2310.     fl      : SET;
  2311.     el      : INTEGER;
  2312.     type    : LONGINT;
  2313.     chr     : ARRAY 2 OF CHAR;
  2314.     s       : DynStrPtr;
  2315.     AllNames: DynTTPtr;
  2316.     to      : TemplOptPtr;
  2317.     fakeargs: ARRAY 4 OF y.BYTE;
  2318.  
  2319.     PROCEDURE CleanUp ();
  2320.     BEGIN
  2321.       DISPOSE (s);
  2322.       FreeDynTT (AllNames);
  2323.     END CleanUp;
  2324.  
  2325.     PROCEDURE ClrOptVars(): BOOLEAN;
  2326.     BEGIN
  2327.       fl := flags * TemplOptFlagsMask;
  2328.       type := str;
  2329.       DISPOSE (s);
  2330.       RETURN DynAppend (s, "");
  2331.     END ClrOptVars;
  2332.  
  2333.   BEGIN
  2334.     i := 0; n := 0; chr[1] := '\x00'; s := NIL; AllNames := NIL;
  2335.     LOOP
  2336.       CASE tmpl[i] OF
  2337.       '\x00' : EXIT; |
  2338.       ','    : INC (n);
  2339.       ELSE END;
  2340.       INC (i);
  2341.     END;
  2342.     IF i # 0 THEN INC (n); END;
  2343.     IF n = 0 THEN CleanUp(); RETURN TRUE; END;
  2344.     IF ~DynAppendTT (AllNames, "", {createEmpty}) THEN CleanUp(); RETURN FALSE; END;
  2345.     y.ALLOCATE (TmplArr, n);
  2346.     IF TmplArr = NIL THEN CleanUp(); RETURN FALSE; END;
  2347.     FOR i := 0 TO LEN (TmplArr^)-1 DO TmplArr[i] := NIL; END;
  2348.     i := 0; n := 0;
  2349.     IF ~ClrOptVars() THEN CleanUp(); RETURN FALSE; END;
  2350.     LOOP
  2351.       CASE tmpl[i] OF
  2352.       '\x00', ',':
  2353.         IF (numAttr IN fl) THEN
  2354.           LOOP
  2355.             IF type = str THEN type := num; EXIT; END;
  2356.             IF type = multi THEN type := multiNum; EXIT; END;
  2357.             CleanUp(); RETURN FALSE;          
  2358.           END;
  2359.           EXCL (fl, numAttr);
  2360.         END;
  2361.         CASE type OF
  2362.         ignore  : y.ALLOCATE (TmplArr[n] (TemplIgnore)); |
  2363.         str     : y.ALLOCATE (TmplArr[n] (TemplStr)); |
  2364.         switch  : y.ALLOCATE (TmplArr[n] (TemplSwitch)); |
  2365.         num     : y.ALLOCATE (TmplArr[n] (TemplNum)); |
  2366.         toggle  : y.ALLOCATE (TmplArr[n] (TemplToggle)); |
  2367.         multiNum: y.ALLOCATE (TmplArr[n] (TemplMultiNum)) |
  2368.         remain  : y.ALLOCATE (TmplArr[n] (TemplRemain)); |
  2369.         multi   : y.ALLOCATE (TmplArr[n] (TemplMulti));
  2370.         END;
  2371.         IF TmplArr[n] = NIL THEN CleanUp(); RETURN FALSE; END;
  2372.         IF dontFill IN flags THEN
  2373.           e.CopyMem ("\000\000\000\000", fakeargs, LEN (fakeargs));
  2374.           IF ~TmplArr[n].Init (s^, fakeargs[0], fl, AllNames) THEN CleanUp(); RETURN FALSE; END;
  2375.         ELSE  
  2376.           IF ~TmplArr[n].Init (s^, args[4*n], fl, AllNames) THEN CleanUp(); RETURN FALSE; END;
  2377.         END;  
  2378.         IF ~ClrOptVars() THEN CleanUp(); RETURN FALSE; END;
  2379.         INC (n); 
  2380.         IF tmpl[i] = '\x00' THEN EXIT; END; |
  2381.       '/'    :
  2382.         WHILE tmpl[i] = '/' DO
  2383.           INC (i);
  2384.           j := 0;
  2385.           LOOP
  2386.             IF j >= LEN (tmplTypesSansNum) THEN EXIT; END;
  2387.             IF (CAP(tmpl[i]) = tmplTypesSansNum[j]) &
  2388.                (tmplTypesSansNum[j] # CHR (0)) THEN EXIT; END;
  2389.             INC (j);
  2390.           END;
  2391.           IF j < LEN (tmplTypesSansNum) THEN
  2392.             IF type # str THEN CleanUp(); RETURN FALSE; END;
  2393.             type := j;
  2394.           ELSE
  2395.             CASE CAP(tmpl[i]) OF
  2396.             numC:
  2397.               el := numAttr; | (* new special num type handling *)
  2398.             keyC:
  2399.               el := keyAttr; |
  2400.             alwaysC:
  2401.               el := alwaysAttr; 
  2402.             ELSE
  2403.               CleanUp(); RETURN FALSE;
  2404.             END;
  2405.             IF el IN fl THEN CleanUp(); RETURN FALSE; END;
  2406.             INCL (fl, el);
  2407.           END;
  2408.           INC (i);
  2409.         END; (* WHILE *)
  2410.         CASE tmpl[i] OF
  2411.         ',', '\x00': |
  2412.         ELSE 
  2413.           CleanUp(); RETURN FALSE;
  2414.         END;  
  2415.         DEC (i);
  2416.       ELSE
  2417.         chr[0] := tmpl[i];
  2418.         IF ~DynAppend (s, chr) THEN CleanUp(); RETURN FALSE; END;
  2419.       END; (* CASE *)
  2420.       INC (i);
  2421.     END; (* LOOP *)
  2422.     FOR i:=0 TO LEN (TmplArr^)-1 DO (* sorting *)
  2423.       FOR j:=i+1 TO LEN (TmplArr^)-1 DO
  2424.         IF TmplArr[j].pri<TmplArr[i].pri THEN
  2425.           to := TmplArr[i]; TmplArr[i] := TmplArr[j]; TmplArr[j] := to;
  2426.         END;  
  2427.       END;  
  2428.     END;                    
  2429.     CleanUp();
  2430.     RETURN TRUE;
  2431.   END ParseTemplate;
  2432.   
  2433.   PROCEDURE RequestArg (VAR opt: TemplOpt): LongStrPtr;
  2434.   VAR
  2435.     ls    : LStrPtr;
  2436.     i,diff: LONGINT;
  2437.     me    : d.ProcessPtr;
  2438.   BEGIN
  2439.     IF req = NIL THEN RETURN NIL; END;
  2440.     IF ReqTitle = NIL THEN
  2441.       IF ~DynExpand (ReqTitle, 256) THEN DISPOSE (ReqTitle); RETURN NIL; END;
  2442.       me := e.FindTask (NIL);
  2443.       IF me.cli = NIL THEN
  2444.         IF me.task.node.name # NIL THEN
  2445.           IF ~DynAppend (ReqTitle, me.task.node.name^) THEN DISPOSE (ReqTitle); RETURN NIL; END;
  2446.         END;  
  2447.       ELSE  
  2448.         IF ~d.GetProgramName (ReqTitle^, LEN (ReqTitle^)) THEN DISPOSE (ReqTitle); RETURN NIL; END;
  2449.       END;
  2450.       IF ~DynAppend (ReqTitle, 
  2451.                      GetCatalogStr (bs.DefaultCatalog, bs.titleReadArgsRequest)^) THEN 
  2452.         DISPOSE (ReqTitle); RETURN NIL; 
  2453.       END;
  2454.     END;
  2455.     DISPOSE (ReqStr);
  2456.     IF ReqBuf = NIL THEN 
  2457.       ReqBuf := opt.EntryToTT (); 
  2458.     ELSE
  2459.       diff := SubPtr (GetToolValue (ReqBuf^), StrIndex (ReqBuf^, 0));
  2460.       FOR i := diff TO st.Length (ReqBuf^) DO ReqBuf[i-diff] := ReqBuf [i]; END;
  2461.     END;  
  2462.     IF ReqBuf = NIL THEN RETURN NIL; END;
  2463.     ReqStr := opt.ReqPrompt ();
  2464.     IF ReqStr = NIL THEN RETURN NIL; END;
  2465.     IF alwaysAttr IN opt.flags THEN
  2466.       IF ~DynAppend (ReqStr, GetCatalogStr (bs.DefaultCatalog, bs.msgWarnArgRequired)^) THEN RETURN NIL; END;
  2467.     END;  
  2468.     IF ~DynExpand (ReqStr, st.Length (ReqStr^)+2000) THEN RETURN NIL; END;
  2469.     ls := StrIndex (ReqStr^, 0);
  2470.     IF ~rtGetString (ReqBuf^, LEN (ReqBuf^)-1, ReqTitle^, NIL, gsTextFmt, 
  2471.                       StrIndex ("%s", 0), gsAllowEmpty, I.LTRUE,
  2472.                       gsFlags, LONGSET{gsReqCenterText},
  2473.                       gsTextFmtArgs, y.ADR (ls), u.done) THEN RETURN NIL; END;
  2474.     IF ~DynInsert (ReqBuf, 0, "=") THEN RETURN NIL; END;
  2475.     IF ~DynInsert (ReqBuf, 0, opt.names[0]^) THEN RETURN NIL; END;
  2476.     RETURN StrIndex (ReqBuf^, 0);
  2477.   END RequestArg;  
  2478.     
  2479. (* $CopyArrays- *)
  2480. BEGIN
  2481.   ReqBuf := NIL; ReqStr := NIL; ReqTitle := NIL;
  2482.   ToolEnd := FALSE; ProjectEnd := FALSE; ttCurr := 0; TmplArr := NIL; Rda := NIL;
  2483.   status := fail;
  2484.   y.SETREG (0, d.SetIoErr (0));
  2485.   IF ~ParseTemplate() THEN CleanUp (d.badTemplate); RETURN NIL; END;
  2486.   y.ALLOCATE (Rda);
  2487.   IF Rda = NIL THEN CleanUp(d.noFreeStore); RETURN NIL; END;
  2488.   Rda.opts := NIL; Rda.ttRest := NIL; Rda.ttIncl := NIL; Rda.validCD := FALSE;
  2489.   IF ~DynAppendTT (Rda.ttRest, "", {createEmpty}) THEN CleanUp(d.noFreeStore); RETURN NIL; END;
  2490.   IF ~DynAppendTT (Rda.ttIncl, "", {createEmpty}) THEN CleanUp(d.noFreeStore); RETURN NIL; END;
  2491.   LOOP
  2492.     tt := GetTT();
  2493.     IF tt = NIL THEN EXIT; END;
  2494.     i := 0; status := fail; ttUsed := FALSE;
  2495.     LOOP
  2496.       IF TmplArr = NIL THEN EXIT; END;
  2497.       IF i >= LEN (TmplArr^) THEN EXIT; END;
  2498.       fnd := TmplArr[i].Cmp (TmplArr[i].SkipAskMagic (tt^, notFound)^, status);
  2499.       IF fnd = foundNoSpc THEN
  2500.         FOR j:=i+1 TO LEN (TmplArr^)-1 DO
  2501.           IF TmplArr[j].Cmp (TmplArr[i].SkipAskMagic (tt^, notFound)^, status) = found THEN fnd := notFound; END;
  2502.         END;  
  2503.       END; 
  2504.       IF fnd # notFound THEN
  2505.         ret := TmplArr[i].Process (TmplArr[i].SkipAskMagic (tt^, fnd)^);
  2506.         IF ret # fail THEN
  2507.           ttUsed := TRUE;
  2508.           IF TmplArr[i].SkipAskMagic (tt^, fnd) # tt THEN
  2509.             INCL (TmplArr[i].flags, requestArg); 
  2510.           END;
  2511.         END;  
  2512.         IF ret = ok THEN
  2513.           EXIT;
  2514.         ELSIF (ret = okSwitchT) OR (ret = okSpecNo) THEN
  2515.           status := ret;
  2516.         END;
  2517.       END;  
  2518.       INC (i);
  2519.     END; (* LOOP *)
  2520.     IF ~ttUsed THEN
  2521.       IF ~DynAppendTT (Rda.ttRest, tt^, {}) THEN CleanUp(d.noFreeStore); RETURN NIL; END;
  2522.     ELSE  
  2523.       IF ~DynAppendTT (Rda.ttIncl, tt^, {}) THEN CleanUp(d.noFreeStore); RETURN NIL; END;
  2524.     END;  
  2525.   END; (* LOOP *)
  2526.   IF TmplArr # NIL THEN
  2527.     FOR i:= 0 TO LEN (TmplArr^)-1 DO
  2528.       IF ((~TmplArr[i].used & ((askEmpty IN flags) OR 
  2529.            ((askEmptyOnAlways IN flags) & (alwaysAttr IN TmplArr[i].flags)))) OR
  2530.           (requestArg IN TmplArr[i].flags)) & (req # NIL) THEN
  2531.         DISPOSE (ReqBuf); 
  2532.         TmplArr[i].flags := TmplArr[i].flags - {noMultiMulti,noFullMulti} + {requestArg};
  2533.         LOOP
  2534.           tt := RequestArg(TmplArr[i]^); 
  2535.           IF tt = NIL THEN TmplArr[i].Free ({solelyMakeUnused}); EXIT; END;
  2536.           ret := TmplArr[i].Cmp (tt^, fail);
  2537.           IF ret = notFound THEN EXIT; END;
  2538.           TmplArr[i].Free ({solelyMakeUnused});
  2539.           IF TmplArr[i].Process (tt^) # fail THEN EXIT; END;
  2540.         END; (* LOOP *)
  2541.       END;  
  2542.       IF alwaysAttr IN TmplArr[i].flags THEN 
  2543.         IF ~TmplArr[i].used THEN CleanUp(d.requiredArgMissing); RETURN NIL; END; 
  2544.       END;
  2545.     END;  
  2546.   END;  
  2547.   Rda.opts := TmplArr;  TmplArr := NIL;
  2548.   CleanUp(0);
  2549.   RETURN Rda;
  2550. END ReadArgsTT;
  2551.  
  2552.  
  2553. (****** BlackMagic/FreeArgs ***************************************************
  2554. *
  2555. *   NAME
  2556. *       FreeArgs -- Frees resources allocated with ReadArgs()
  2557. *
  2558. *   SYNOPSIS
  2559. *       FreeArgs (VAR rda: RDArgsPtr);
  2560. *
  2561. *   FUNCTION
  2562. *       This function just frees all resources allocated with a prior
  2563. *       call to ReadArgs() and reinitializes the RDArgsPtr to NIL.
  2564. *
  2565. *   INPUTS
  2566. *       rda      - A valid or NIL RDArgsPtr
  2567. *
  2568. *   SEE ALSO
  2569. *       ReadArgs()
  2570. *
  2571. *****************************************************************************)
  2572.  
  2573. PROCEDURE FreeArgs * (VAR rda: RDArgsPtr);
  2574. BEGIN
  2575.   IF rda # NIL THEN
  2576.     rda.Free();
  2577.     DISPOSE (rda);
  2578.   END;
  2579. END FreeArgs;
  2580.  
  2581.  
  2582. (****** BlackMagic/FreeArgsWB *************************************************
  2583. *
  2584. *   NAME
  2585. *       FreeArgsWB -- Frees resources allocated with ReadArgsTT/WBMsg/WB()
  2586. *
  2587. *   SYNOPSIS
  2588. *       FreeArgsWB (VAR rda: RDArgsWBPtr);
  2589. *
  2590. *   FUNCTION
  2591. *       This function just frees all resources allocated with a prior
  2592. *       call to ReadArgsTT(), ReadArgsWBMsg() or ReadArgsWB() and 
  2593. *       reinitializes the RDArgsWBPtr to NIL.
  2594. *
  2595. *   INPUTS
  2596. *       rda      -  A valid or NIL RDArgsWBPtr
  2597. *
  2598. *   SEE ALSO
  2599. *       ReadArgsTT(), ReadArgsWBMsg(), ReadArgsWB()
  2600. *
  2601. *****************************************************************************)
  2602.  
  2603. PROCEDURE FreeArgsWB * (VAR rda: RDArgsWBPtr);
  2604. BEGIN
  2605.   IF rda # NIL THEN
  2606.     rda.Free();
  2607.     DISPOSE (rda);
  2608.   END;
  2609. END FreeArgsWB;
  2610.  
  2611. (****** BlackMagic/WBArgToFNam *************************************************
  2612. *
  2613. *   NAME
  2614. *       WBArgToFNam -- generates complete file path from filename & dir lock
  2615. *
  2616. *   SYNOPSIS
  2617. *       WBArgToFNam * (VAR string : DynStrPtr; 
  2618. *                      lock       : d.FileLockPtr;
  2619. *                      fName      : ARRAY OF CHAR;
  2620. *                      flags      : SET): BOOLEAN;
  2621. *
  2622. *   FUNCTION
  2623. *       This function generates the complete path of a file from
  2624. *       its name component and a lock of the directory where
  2625. *       the file is located, and appends it to the passed dynamic
  2626. *       string. This function is especially useful when dealing
  2627. *       with WBStartup / AppMessage file lists. Note that you
  2628. *       can alienate this function from its original purpose by
  2629. *       supplying an empty fName parameter. In that case, this
  2630. *       function simply returns the complete path of the supplied
  2631. *       lock parameter.
  2632. *
  2633. *   INPUTS
  2634. *       string   - the dynamic string handle - may be NIL.
  2635. *       lock     - the lock of the directory where the file is located.
  2636. *       fName    - the name of the file.
  2637. *       flags    - flags modifying the operation of this function. 
  2638. *                  At the moment, the one and only documented flag is
  2639. *                  relPath. If you specify it, this function may
  2640. *                  generate relative paths to the current directory,
  2641. *                  otherwise it will always create absolute paths.
  2642. *                  It is *absolutely illegal* to specify any other
  2643. *                  flags than the ones documented here.
  2644. *
  2645. *   RESULT
  2646. *       TRUE   - for success.
  2647. *       FALSE  - for failure - in this case the dynamic string and its 
  2648. *                handle are left unchanged.
  2649. *
  2650. *   SEE ALSO
  2651. *       ReadArgsWBMsg()
  2652. *
  2653. *****************************************************************************)
  2654.  
  2655. PROCEDURE WBArgToFNam * (VAR string : DynStrPtr; 
  2656.                          lock       : d.FileLockPtr;
  2657.                          fName      : ARRAY OF CHAR;
  2658.                          flags      : SET): BOOLEAN;
  2659. VAR
  2660.   FullPathStr: DynStrPtr;
  2661.   i: LONGINT;                      
  2662.  
  2663.   PROCEDURE CleanUp();
  2664.   BEGIN
  2665.     DISPOSE (FullPathStr);
  2666.   END CleanUp;  
  2667.  
  2668. (* $CopyArrays- *)
  2669. BEGIN  
  2670.   FullPathStr := NIL;
  2671.   IF (d.SameLock (lock, e.FindTask (NIL)(d.Process).currentDir) # d.same) OR
  2672.      ~(relPath IN flags) THEN
  2673.     i := 1+DynamicExtra;
  2674.     LOOP
  2675.       y.ALLOCATE (FullPathStr, i);
  2676.       IF FullPathStr = NIL THEN CleanUp(); RETURN FALSE; END;
  2677.       IF d.NameFromLock (lock, FullPathStr^,
  2678.                          LEN (FullPathStr^)) THEN
  2679.         EXIT;
  2680.       ELSE  
  2681.         IF d.IoErr() # d.lineTooLong THEN CleanUp(); RETURN FALSE; END;
  2682.       END;  
  2683.       INC (i, 1+DynamicExtra);
  2684.       DISPOSE (FullPathStr);
  2685.     END; (* LOOP *)
  2686.   END;
  2687.   IF ~DynExpand (FullPathStr, DynStrLen (FullPathStr)+st.Length (fName)+2) THEN 
  2688.     CleanUp(); RETURN FALSE; 
  2689.   END;
  2690.   IF fName # "" THEN
  2691.     IF ~d.AddPart (FullPathStr^, fName, 
  2692.                    LEN (FullPathStr^)) THEN CleanUp(); RETURN FALSE; END;
  2693.   END;                 
  2694.   IF ~DynAppend (string, FullPathStr^) THEN CleanUp(); RETURN FALSE; END;
  2695.   CleanUp();
  2696.   RETURN TRUE;
  2697. END WBArgToFNam;  
  2698.  
  2699.  
  2700. (****** BlackMagic/ReadArgsWBMsg **********************************************
  2701. *
  2702. *   NAME
  2703. *       ReadArgsWBMsg -- Parse WBStartup's input similar to Dos.ReadArgs()
  2704. *
  2705. *   SYNOPSIS
  2706. *       ReadArgsWBMsg (template : ARRAY OF CHAR;
  2707. *                      args     : ARRAY OF y.BYTE;
  2708. *                      wbenchMsg: wb.WBStartupPtr;
  2709. *                      project  : LONGINT;
  2710. *                      flags    : SET): RDArgsWBPtr;
  2711. *
  2712. *   FUNCTION
  2713. *       This function is a frontend for the ReadArgsTT() function.
  2714. *       Its main additional benefit is that it does all the bothersome
  2715. *       DiskObject handling and provides the capability to pass the
  2716. *       project(s)'s file names you supply as arguments for your tool
  2717. *       invocation. All ToolTypes of the project (if specified) are
  2718. *       searched for a match and are processed before the tool's 
  2719. *       ToolTypes, as demanded in the Amiga User Interface Style Guide.
  2720. *
  2721. *   INPUTS
  2722. *       template-  The option template. Have a look at the ReadArgsTT
  2723. *                  documentation for a thorough-going discussion.
  2724. *                  
  2725. *       args    -  The array or struct to hold the option argument entries.
  2726. *                  Four bytes for each option large at least. See also
  2727. *                  ReadArgsTT() documentation.
  2728. *
  2729. *       wbenchMsg- The WBStartup you were passed by Workbench on 
  2730. *                  startup of your program. For Oberon you can access it
  2731. *                  with OberonLib.wbStartup
  2732. *       
  2733. *       project  - The ordinal number of the project you want to be taken 
  2734. *                  into account for parsing - starting at 1. Passing 0
  2735. *                  means that you only want the tool's ToolTypes to be
  2736. *                  taken into account. Passing -1 means that if there
  2737. *                  exist one or more passed projects, the first project
  2738. *                  is used for parsing, otherwise only the tool's ToolTypes
  2739. *                  are taken into account. The number of projects supplied
  2740. *                  may be calculated using wbenchMsg^.numArgs-1
  2741. *
  2742. *       flags    - Flags modifying the operation of this function:
  2743. *                  You may use all those documented with ReadArgsTT,
  2744. *                  including noFullMulti, noMultiMulti, multiBarSep, 
  2745. *                  multiCommaSep, disableSpecialNo & dontFill.
  2746. *                  There are six more flags you may specify along with
  2747. *                  this function:
  2748. *                  doCD:
  2749. *                    Make the directory specified by the directory lock of
  2750. *                    WBStartup's tool the current directory. A call to 
  2751. *                    FreeArgsWB() will reset the original current 
  2752. *                    directory.
  2753. *                  ignoreTool:
  2754. *                    Discard the tool's ToolTypes, only consider the
  2755. *                    project's ToolTypes. Incompatible with specifying 0
  2756. *                    as project parameter and with ignoreProject
  2757. *                  ignoreProject:
  2758. *                    Discard the project's ToolTypes, only consider the
  2759. *                    tools's ToolTypes. Incompatible with ignoreTool
  2760. *                  argFile, argFiles & relPath:
  2761. *                    If you specify exactly one of either argFile or
  2762. *                    argFiles, and you pass either a FILE/K or a
  2763. *                    a FILES/M/K template option, the respective option
  2764. *                    entries will either be filled with the file name
  2765. *                    of the specified project or with all file names of
  2766. *                    all projects passed on startup.
  2767. *                    File name(s) are either always given as an absolute
  2768. *                    path (default) or may have a path relative to the
  2769. *                    tool's current directory if you specify the relPath
  2770. *                    flag.
  2771. *
  2772. *   RESULT
  2773. *       RDArgsWBPtr
  2774. *                - A pointer to a RECORD RDArgsWB, as documented along
  2775. *                  with the ReadArgsTT() doc. NIL indicates failure.
  2776. *
  2777. *   NOTES
  2778. *       Remember what I said in the discussion of unauthorized flag
  2779. *       specification in the ReadArgsTT() and also in the DynAppendTT()
  2780. *       documentation.
  2781. *
  2782. *   SEE ALSO
  2783. *       FreeArgsWB(), ReadArgsTT(), ReadArgsWB()
  2784. *
  2785. *****************************************************************************)
  2786.  
  2787. PROCEDURE ReadArgsWBMsg * (template : ARRAY OF CHAR;
  2788.                            args     : ARRAY OF y.BYTE;
  2789.                            wbenchMsg: wb.WBStartupPtr;
  2790.                            project  : LONGINT;
  2791.                            flags    : SET): RDArgsWBPtr;
  2792.  
  2793. VAR                           
  2794.   do1, do2: wb.DiskObjectPtr;
  2795.   lock: d.FileLockPtr;
  2796.   rda: RDArgsPtr; 
  2797.   rdareturn: RDArgsWBPtr;
  2798.   ArgStr: DynStrPtr;
  2799.   endflg : BOOLEAN;
  2800.   i: LONGINT;
  2801.   tmpl: LongStrPtr;
  2802.   av: ARRAY 4 OF y.BYTE;
  2803.   tt1, tt2: TTPtr;
  2804.   fprj: LONGINT;
  2805.   cd:   d.FileLockPtr;
  2806.   wba: WBArgumentsPtr;
  2807.  
  2808. (* $CopyArrays- *)
  2809. BEGIN
  2810.   do1 := NIL; do2 := NIL; lock := NIL; rda := NIL; rdareturn := NIL; 
  2811.   ArgStr := NIL; endflg := FALSE; i := 0; tmpl := NIL; tt1 := NIL; tt2 := NIL;
  2812.   IF ((argFile IN flags) & (argFiles IN flags)) OR 
  2813.      ((ignoreTool IN flags) & ((ignoreProject IN flags) OR (project=0))) THEN 
  2814.     y.SETREG (0, d.SetIoErr (d.objectWrongType)); RETURN NIL; 
  2815.   END;
  2816.   IF argFile IN flags THEN 
  2817.     tmpl := y.ADR ("FILE/M/K");
  2818.   ELSIF argFiles IN flags THEN 
  2819.     tmpl := y.ADR ("FILES/M/K");
  2820.   ELSE
  2821.     tmpl := y.ADR ("");
  2822.   END;  
  2823.   IF wbenchMsg = NIL THEN y.SETREG (0, d.SetIoErr (d.objectWrongType)); RETURN NIL; END;
  2824.   IF project = -1 THEN 
  2825.     IF wbenchMsg^.numArgs > 1 THEN project := 1; ELSE project := 0; END;
  2826.   END;  
  2827.   IF (project < 0) OR (project >=  wbenchMsg^.numArgs) THEN 
  2828.     y.SETREG (0, d.SetIoErr (d.badNumber)); RETURN NIL; 
  2829.   END;
  2830.   IF (project=0) & (wbenchMsg^.numArgs>1) THEN fprj := 1; ELSE fprj := project; END;
  2831.   (* due to misdefinition of wb.WBArgumentsPtr: Ptr TO ARRAY 256!! OF ... *)
  2832.   wba := AddPtr (wbenchMsg.argList, 0);
  2833.   IF doCD IN flags THEN cd := d.CurrentDir (wba^[0].lock); END;
  2834.   lock := d.CurrentDir (wba^[0].lock);
  2835.   do1 := ic.GetDiskObjectNew (wba^[0].name^);
  2836.   y.SETREG (0, d.CurrentDir (wba^[project].lock));
  2837.   do2 := ic.GetDiskObjectNew (wba^[project].name^);
  2838.   y.SETREG (0, d.CurrentDir (lock));
  2839.   IF ignoreTool IN flags THEN tt1 := NIL; ELSE tt1 := do1^.toolTypes; END;
  2840.   IF ((project = 0) OR (ignoreProject IN flags)) & 
  2841.      (tt1 # NIL) THEN tt2 := NIL; ELSE tt2 := do2^.toolTypes; END;
  2842.   LOOP
  2843.     IF ~DynAppend (ArgStr, "") THEN EXIT; END;
  2844.     rda := ReadArgsTT (tmpl^, av, tt1, tt2, {});
  2845.     IF rda = NIL THEN EXIT; END;
  2846.     WITH rda: RDArgsWB DO
  2847.       IF (argFile IN flags) & (fprj > 0) THEN
  2848.         ArgStr[0] := CHR (0);
  2849.         IF ~DynAppend (ArgStr, "FILE=") THEN EXIT; END;
  2850.     (* due to misdefinition of wb.WBArgumentsPtr: Ptr TO ARRAY 256!! OF ... *)
  2851.         IF ~WBArgToFNam (ArgStr, wba^[fprj].lock, wba^[fprj].name^, 
  2852.                         flags) THEN EXIT; END;
  2853.         IF ~DynAppendTT (rda.ttRest, ArgStr^, {}) THEN EXIT; END;
  2854.       END;  
  2855.       IF argFiles IN flags THEN
  2856.         FOR i := 1 TO wbenchMsg^.numArgs-1 DO      
  2857.           ArgStr[0] := CHR (0);
  2858.     (* due to misdefinition of wb.WBArgumentsPtr: Ptr TO ARRAY 256!! OF ... *)
  2859.           IF ~DynAppend (ArgStr, "FILES=") THEN EXIT; END;      
  2860.           IF ~WBArgToFNam (ArgStr, wba^[i].lock, wba^[i].name^, flags) THEN EXIT; END;
  2861.           IF ~DynAppendTT (rda.ttRest, ArgStr^, {}) THEN EXIT; END;
  2862.         END; (* FOR *)
  2863.       END; (* IF argFiles IN flags *)
  2864.       rdareturn := ReadArgsTT (template, args, NIL, TTAPtr (rda.ttRest), flags);
  2865.       EXIT;
  2866.     END (* WITH *)     
  2867.   END; (* LOOP *)  
  2868.   IF rda # NIL THEN FreeArgs (rda); END; 
  2869.   IF do1 # NIL THEN ic.FreeDiskObject (do1); END;
  2870.   IF do2 # NIL THEN ic.FreeDiskObject (do2); END;
  2871.   DISPOSE (ArgStr);
  2872.   IF doCD IN flags THEN
  2873.     IF rdareturn # NIL THEN 
  2874.       rdareturn.validCD := TRUE; rdareturn.oldCD := cd; 
  2875.     ELSE  
  2876.       y.SETREG (0, d.CurrentDir (cd));
  2877.     END;  
  2878.   END;  
  2879.   RETURN rdareturn;
  2880. END ReadArgsWBMsg;
  2881.  
  2882.  
  2883. (****** BlackMagic/ReadArgsWB *************************************************
  2884. *
  2885. *   NAME
  2886. *       ReadArgsWB -- Parse Workbench input within an Oberon program
  2887. *
  2888. *   SYNOPSIS
  2889. *       ReadArgsWB (template: ARRAY OF CHAR;
  2890. *                   args    : ARRAY OF y.BYTE;
  2891. *                   project : LONGINT;
  2892. *                   flags   : SET): RDArgsWBPtr;
  2893. *
  2894. *   FUNCTION
  2895. *       This function is a frontend for the ReadArgsWBMsg() function
  2896. *       to be used in Oberon programs. The arguments passed to it are
  2897. *       exactly the same as the ones passed to ReadArgsWBMsg() except
  2898. *       for the omitted wbenchMsg arguement which is directly taken
  2899. *       from OberonLib.wbStartup. If the Oberon program was started from
  2900. *       CLI, failure is returned.
  2901. *
  2902. *   INPUTS
  2903. *       see ReadArgsWBMsg() documentation
  2904. *
  2905. *   RESULT
  2906. *       RDArgsWBPtr
  2907. *                - A pointer to a RECORD RDArgsWB, as documented along
  2908. *                  with the ReadArgsTT() doc, NIL for failure.
  2909. *
  2910. *   NOTES
  2911. *       Remember what I said in the discussion of unauthorized flag
  2912. *       specification in the ReadArgsTT() and also in the DynAppendTT()
  2913. *       documentation.
  2914. *
  2915. *   SEE ALSO
  2916. *       FreeArgsWB(), ReadArgsTT(), ReadArgsWBMsg()
  2917. *
  2918. *****************************************************************************)
  2919.  
  2920. PROCEDURE ReadArgsWB * (template: ARRAY OF CHAR;
  2921.                         args    : ARRAY OF y.BYTE;
  2922.                         project : LONGINT;
  2923.                         flags   : SET): RDArgsWBPtr;
  2924. (* $CopyArrays- *)
  2925. BEGIN
  2926.   IF ~o.wbStarted THEN y.SETREG (0, d.SetIoErr (d.objectWrongType)); RETURN NIL; END;
  2927.   RETURN ReadArgsWBMsg (template, args, o.wbenchMsg(wb.WBStartup),
  2928.                         project, flags);
  2929. END ReadArgsWB;
  2930.                        
  2931. (****** BlackMagic/ReadArgs ***************************************************
  2932. *
  2933. *   NAME
  2934. *       ReadArgs -- Parse Workbench OR CLI input args Dos.ReadArgs()-like
  2935. *
  2936. *   SYNOPSIS
  2937. *       ReadArgs (template: ARRAY OF CHAR;
  2938. *                 args    : ARRAY OF y.BYTE;
  2939. *                 project : LONGINT;
  2940. *                 flags   : SET): RDArgsWBPtr;
  2941. *
  2942. *   FUNCTION
  2943. *       This function provides all Oberon programmers with a unique
  2944. *       argument parsing interface, from both CLI and Workbench.
  2945. *       It offers you all of the flexibility of the Dos.ReadArgs()
  2946. *       function also for Workbench argument parsing.
  2947. *
  2948. *   INPUTS
  2949. *       see ReadArgsWBMsg() documentation
  2950. *       Note that for CLI parsing, the project and flags paramters
  2951. *       are naturally ignored, since they are Workbench specific. You
  2952. *       may only use template option combinations that are documented
  2953. *       for both, ReadArgsTT() AND dos/ReadArgs(), of course.
  2954. *
  2955. *   RESULT
  2956. *       RDArgsPtr 
  2957. *                - A pointer to a RECORD RDArgs or NIL.
  2958. *                  You may free the resources allocated with it by
  2959. *                  invoking FreeArgs (RDArgsPtr).
  2960. *
  2961. *   NOTES
  2962. *       Remember what I said in the discussion of unauthorized flag
  2963. *       specification in the ReadArgsTT() and also in the DynAppendTT()
  2964. *       documentation.
  2965. *
  2966. *   SEE ALSO
  2967. *       FreeArgs(), ReadArgsTT(), ReadArgsWBMsg(), ReadArgsWB()
  2968. *
  2969. *****************************************************************************)
  2970.  
  2971. PROCEDURE ReadArgs * (template: ARRAY OF CHAR;
  2972.                       args    : ARRAY OF y.BYTE;
  2973.                       project : LONGINT;
  2974.                       flags   : SET): RDArgsPtr;
  2975. VAR 
  2976.   rda: RDArgsPtr;                      
  2977. (* $CopyArrays- *)                      
  2978. BEGIN
  2979.   rda := NIL;
  2980.   IF o.wbStarted THEN
  2981.     rda := ReadArgsWBMsg (template, args, o.wbenchMsg(wb.WBStartup),
  2982.                           project, flags);
  2983.   ELSE                        
  2984.     y.ALLOCATE (rda (RDArgsCLI));    
  2985.     IF rda # NIL THEN
  2986.       rda (RDArgsCLI).rda := d.OldReadArgs (template, args, NIL);
  2987.       IF rda (RDArgsCLI).rda = NIL THEN DISPOSE (rda); END;
  2988.     END;  
  2989.   END;  
  2990.   RETURN rda;
  2991. END ReadArgs;  
  2992.  
  2993.  
  2994. (****** BlackMagic/ArgsToTT ***************************************************
  2995. *
  2996. *   NAME
  2997. *       ArgsToTT -- Convert a string/CLIArgs into a dynamic ToolType array
  2998. *
  2999. *   SYNOPSIS
  3000. *       ArgsToTT (str: ARRAY OF CHAR, flags: SET): DynTTPtr;
  3001. *
  3002. *   FUNCTION
  3003. *       This function does 'CLI to WB parsing' for you, as opposed to the
  3004. *       ReadArgsTT/WBMsg/WB() functions which parse the other way round.
  3005. *       It simply stores each of the white-space separated 'words' of the
  3006. *       input string into an own entry of a dynamic ToolType array. Usual
  3007. *       dos escaping like *n, *e, ** inside quotes is done because this
  3008. *       function uses Dos.ReadArgs().
  3009. *
  3010. *   INPUTS
  3011. *       str      - the string to be parsed
  3012. *       flags    - flags that modify operation of this function.
  3013. *                  currently only useCLIArgs may be specified, which
  3014. *                  causes ArgsToTT to ignore the passed string and get
  3015. *                  its input rather from the arguemnts passed to your
  3016. *                  program by the shell on startup.
  3017. *
  3018. *   RESULT
  3019. *       DynTTPtr - The dynamic ToolType array handle whose ToolTypes
  3020. *                  represent the input source's string. The array may
  3021. *                  be empty, i.e. its first element may be NIL if the
  3022. *                  input string was empty or consisted solely of white
  3023. *                  space characters. A NIL return is this function's
  3024. *                  failure indicator.
  3025. *                  
  3026. *   NOTES
  3027. *       Dos.ReadItem()/Dos.ReadArgs() parse all '=' equal characters into
  3028. *       white space, if they're not surrounded by quotes. Remember this.
  3029. *       Concerning the flags parameter, keep in mind what I said in the
  3030. *       DynAppendTT documentation about using unauthorized flags for
  3031. *       the flags paramter!
  3032. *       
  3033. *   SEE ALSO
  3034. *       FreeDynTT(), DynAppendTT(), ReadArgsTT()
  3035. *
  3036. *****************************************************************************)
  3037.       
  3038. (* Flags for ArgsToTT *)
  3039. CONST
  3040.   useCLIArgs * = 0; 
  3041.  
  3042. PROCEDURE ArgsToTT * (str: ARRAY OF CHAR; flags: SET): DynTTPtr;
  3043. VAR
  3044.   rda1, rda2: d.RDArgsPtr;
  3045.   dtt, dttnf: DynTTPtr;  
  3046.   Args: TTPtr;
  3047.   i : LONGINT;
  3048.  
  3049.   PROCEDURE CleanUp();
  3050.   BEGIN
  3051.     FreeDynTT (dtt);
  3052.     IF rda2 # NIL THEN d.FreeArgs (rda2); rda2 := NIL; END;
  3053.     IF rda1 # NIL THEN d.FreeDosObject (d.rdArgs, rda1); rda1 := NIL; END;
  3054.   END CleanUp;  
  3055.  
  3056. (* $CopyArrays- *)
  3057. BEGIN
  3058.   rda1 := NIL; rda2 := NIL; dtt := NIL; dttnf := NIL; Args := NIL;
  3059.   IF ~(useCLIArgs IN flags) THEN
  3060.     rda1 := d.AllocDosObject (d.rdArgs, NIL);
  3061.     IF rda1 = NIL THEN CleanUp(); RETURN NIL; END;
  3062.     rda1.source.buffer := y.ADR (str);
  3063.     rda1.source.length := st.Length (str);
  3064.     rda1.source.curChr := 0;
  3065.     rda1.daList := NIL; rda1.buffer := NIL; rda1.bufSiz := 0; rda1.extHelp := NIL;
  3066.     rda1.flags := LONGSET{d.noPrompt};
  3067.   END;  
  3068.   rda2 := d.OldReadArgs ("/M", Args, rda1);
  3069.   IF rda2 = NIL THEN CleanUp(); RETURN NIL; END;
  3070.   IF ~DynAppendTT (dtt, "", {createEmpty}) THEN CleanUp(); RETURN NIL; END;
  3071.   IF Args # NIL THEN 
  3072.     i := 0;
  3073.     WHILE Args[i] # NIL DO
  3074.       IF ~DynAppendTT (dtt, Args[i]^, {}) THEN CleanUp(); RETURN NIL; END;
  3075.       INC (i);  
  3076.     END;  
  3077.   END;  
  3078.   dttnf := dtt; dtt := NIL;
  3079.   CleanUp();
  3080.   RETURN dttnf;
  3081. END ArgsToTT;
  3082.  
  3083.  
  3084. (****** BlackMagic/AddPtr *****************************************************
  3085. *
  3086. *   NAME
  3087. *       AddPtr -- Add UNTRACED (B)POINTERs/integers/LONGSETs
  3088. *
  3089. *   SYNOPSIS
  3090. *       AddPtr (a: Exec.APTR; b: Exec.APTR): Exec.APTR;
  3091. *
  3092. *   FUNCTION
  3093. *       This function provides mixed untraced pointer/integer arithmetics
  3094. *       for you, no matter whether the passed values are Exec.APTRS, 
  3095. *       BPOINTERs, integers or LONGSETs
  3096. *       It takes the two values (and corrects any BPOINTER values), adds
  3097. *       them, and returns the result as an Exec.APTR.
  3098. *
  3099. *   INPUTS
  3100. *       a,b      - the values to perform the addition on.
  3101. *
  3102. *   RESULT
  3103. *      Exec.APTR - the result of the performed arithmetics returned as an
  3104. *                  Exec.APTR.
  3105. *                  
  3106. *   NOTES
  3107. *       *Never* try to use this function with traced pointers arguments.
  3108. *       
  3109. *   SEE ALSO
  3110. *       SubPtr(), StrIndex(), PtrToInt()
  3111. *
  3112. *****************************************************************************)
  3113.       
  3114. PROCEDURE AddPtr * (a, b: e.APTR): e.APTR;
  3115. BEGIN
  3116.   RETURN y.VAL (e.APTR, y.VAL (LONGINT, a) + y.VAL (LONGINT, b));
  3117. END AddPtr;  
  3118.  
  3119.  
  3120. (****** BlackMagic/SubPtr *****************************************************
  3121. *
  3122. *   NAME
  3123. *       SubPtr -- Subtracts UNTRACED (B)POINTERs/integers/LONGSETs
  3124. *
  3125. *   SYNOPSIS
  3126. *       SubPtr (a: Exec.APTR; b: Exec.APTR): Exec.APTR;
  3127. *
  3128. *   FUNCTION
  3129. *       This function provides mixed untraced pointer/integer arithmetics
  3130. *       for you, no matter whether the passed values are Exec.APTRS, 
  3131. *       BPOINTERs, integers or LONGSETs.
  3132. *       It takes the b parameter, subtracts it from the a parameter, and
  3133. *       returns the result as an Exec.APTR (result := a-b;)
  3134. *
  3135. *   INPUTS
  3136. *       a        - the value from which b is to be subtracted
  3137. *       b        - the value to subtract from a.
  3138. *
  3139. *   RESULT
  3140. *      Exec.APTR - the result of the performed arithmetics returned as an
  3141. *                  Exec.APTR.
  3142. *                  
  3143. *   NOTES
  3144. *       *Never* try to use this function with traced pointers arguments.
  3145. *       
  3146. *   SEE ALSO
  3147. *       AddPtr(), StrIndex(), PtrToInt()
  3148. *
  3149. *****************************************************************************)
  3150.       
  3151. PROCEDURE SubPtr * (a, b: e.APTR): e.APTR;
  3152. BEGIN
  3153.   RETURN y.VAL (e.APTR, y.VAL (LONGINT, a) - y.VAL (LONGINT, b));
  3154. END SubPtr;
  3155.  
  3156. (****** BlackMagic/PtrToInt ****************************************************
  3157. *
  3158. *   NAME
  3159. *       PtrToInt - Typecast UNTRACED (B)POINTER/integer/LONGSET to LONGINT
  3160. *
  3161. *   SYNOPSIS
  3162. *       PtrToInt (ptr: Exec.APTR): LONGINT;
  3163. *
  3164. *   FUNCTION
  3165. *       This function simply typecasts an Exec.APTR into a LONGINT.
  3166. *       This is useful for pointer arithmetics.
  3167. *
  3168. *   INPUTS
  3169. *       ptr      - the UNTRACED POINTER / BPOINTER / integer / LONGSET
  3170. *                  to be typecasted into LONGINT
  3171. *
  3172. *   RESULT
  3173. *       the typecasted LONGINT
  3174. *
  3175. *   SEE ALSO
  3176. *       AddPtr(), SubPtr(), BPtrVal()
  3177. *
  3178. *****************************************************************************)
  3179.  
  3180. PROCEDURE PtrToInt * (ptr: e.APTR): LONGINT;
  3181. BEGIN
  3182.   RETURN y.VAL (LONGINT, ptr);
  3183. END PtrToInt;
  3184.  
  3185.  
  3186. (****** BlackMagic/BPtrVal *****************************************************
  3187. *
  3188. *   NAME
  3189. *       BPtrVal - Typecast a BPOINTER to LONGINT
  3190. *
  3191. *   SYNOPSIS
  3192. *       BPtrVal (bptr: Exec.APTR): LONGINT;
  3193. *
  3194. *   FUNCTION
  3195. *       This function simply typecasts a BPOINTER into a LONGINT
  3196. *       without shifting it 2 bits left. Useful for operating system
  3197. *       TagLists where BPOINTERs have to be passed as real BPOINTERs.
  3198. *
  3199. *
  3200. *   INPUTS
  3201. *       bptr      - the BPOINTER to be typecasted into LONGINT
  3202. *
  3203. *   RESULT
  3204. *       the typecasted LONGINT
  3205. *
  3206. *   SEE ALSO
  3207. *       PtrToInt(), AddPtr(), SubPtr()
  3208. *
  3209. *****************************************************************************)
  3210.  
  3211. PROCEDURE BPtrVal * (bptr: e.APTR): LONGINT;
  3212. BEGIN
  3213.   RETURN y.VAL (LONGINT, bptr) DIV 4;
  3214. END BPtrVal;
  3215.  
  3216. (****** BlackMagic/GetCatalogStr ***********************************************
  3217. *
  3218. *   NAME
  3219. *       GetCatalogStr - Return a localized string from a catalog
  3220. *       GetCatalogStrA - Return a localized str (Exec.APTR) from a catalog
  3221. *
  3222. *   SYNOPSIS
  3223. *       GetCatalogStr (catalog: Locale.CatalogPtr; 
  3224. *                      string : ARRAY OF CHAR     ): LongStrPtr;
  3225. *
  3226. *       GetCatalogStrA (catalog: Locale.CatalogPtr; 
  3227. *                       string : ARRAY OF CHAR     ): Exec.APTR;
  3228. *
  3229. *   FUNCTION
  3230. *       These functions are similar to locale.library's GetCatalogStr()
  3231. *       equivalent, except that they work with a NIL - Locale.base and
  3232. *       consume one parameter less, because they expect the string id
  3233. *       to be placed in the two leading chars of the passed string
  3234. *       (high byte first, then low byte), the actual default string
  3235. *       is expected to start at the 3rd char of the string.
  3236. *       For further documentation, have a look at Locale/GetCatalogStr().
  3237. *
  3238. *   INPUTS
  3239. *       catalog  - a valid Locale.CatalogPtr or NIL.
  3240. *       string   - the string containing the string id in the first two
  3241. *                  characters, and the null-terminated default string
  3242. *                  starting from the third character.
  3243. *       
  3244. *   RESULT
  3245. *       a LongStrPtr/Exec.APTR pointing to the 'best' string found.
  3246. *       Guaranteed to be non-NIL.
  3247. *
  3248. *   NOTES
  3249. *       you may convert your catalog definition files (#?.cd) into the
  3250. *       required Oberon source with the string constants definitions in 
  3251. *       the format this function expects, with the enclosed Cat2Mod.rexx
  3252. *       script.
  3253. *
  3254. *   SEE ALSO
  3255. *       GetStr(), Locale/GetCatalogStr(), Cat2Mod.rexx
  3256. *
  3257. *****************************************************************************)
  3258.  
  3259. PROCEDURE GetCatalogStr * (catalog: loc.CatalogPtr; 
  3260.                            string : ARRAY OF CHAR  ): LongStrPtr;
  3261. VAR                           
  3262.   str1     : LongStrPtr;
  3263.   str2     : e.APTR;
  3264.   id       : LONGINT;
  3265. (* $CopyArrays- *)                           
  3266. BEGIN                         
  3267.   str1 := StrIndex (string, 2);
  3268.   IF loc.base = NIL THEN RETURN str1; END;
  3269.   id := ASH (ORD (string[0]), 8) + ORD (string[1]);  
  3270.   str2 := loc.GetCatalogStr (catalog, id, str1^);
  3271.   IF str2 # NIL THEN str1 := str2; END;
  3272.   RETURN str1;
  3273. END GetCatalogStr;
  3274.  
  3275. PROCEDURE GetCatalogStrA * (catalog: loc.CatalogPtr;
  3276.                             string : ARRAY OF CHAR  ): e.APTR;
  3277. (* $CopyArrays- *)                            
  3278. BEGIN
  3279.   RETURN GetCatalogStr (catalog, string);
  3280. END GetCatalogStrA;  
  3281.  
  3282.   
  3283. (****** BlackMagic/GetStr ******************************************************
  3284. *
  3285. *   NAME
  3286. *       GetStr - Return a localized string from the default catalog   
  3287. *       GetStrA - Return localized str (Exec.APTR) from the default catalog
  3288. *
  3289. *   SYNOPSIS
  3290. *       GetStr (string: ARRAY OF CHAR): LongStrPtr;
  3291. *
  3292. *       GetStrA (string: ARRAY OF CHAR): Exec.APTR;
  3293. *
  3294. *   FUNCTION
  3295. *       These functions are frontends for the GetCatalogStr() function.
  3296. *       They take only the string parameter, and use the contents of
  3297. *       BlackMagic.Default as GetCatalogStr()'s catalog argument.
  3298. *
  3299. *   INPUTS
  3300. *       string   - the string containing the string id in the first two
  3301. *                  characters, and the null-terminated default string
  3302. *                  starting from the third character.
  3303. *       
  3304. *   RESULT
  3305. *       a LongStrPtr/Exec.APTR pointing to the 'best' string found -
  3306. *       guaranteed to be non-NIL;
  3307. *
  3308. *   NOTES
  3309. *       You should open your program's catalog in your initialization code
  3310. *       and assign the value returned by Locale.OpenCatalog() to the
  3311. *       BlackMagic.DefaultCatalog variable. After that GetStr() / GetStrA() 
  3312. *       do anything for you, you _MUST NOT_ even close the Catalog since
  3313. *       that is done in this module's shutdown code. However, if you
  3314. *       omit opening your catalog at startup, this function will
  3315. *       still work - it simply returns the built-in strings in that case.
  3316. *       If you convert your catalog definitions with the enclosed
  3317. *       Cat2Mod.rexx script, this initialization is done in the
  3318. *       generated Oberon source module.
  3319. *       
  3320. *   SEE ALSO
  3321. *       GetCatalogString(), Cat2Mod.rexx
  3322. *
  3323. *****************************************************************************)
  3324.  
  3325. VAR
  3326.   DefaultCatalog * : loc.CatalogPtr;
  3327.  
  3328. PROCEDURE GetStr * (string: ARRAY OF CHAR): LongStrPtr;
  3329. (* $CopyArrays- *)                           
  3330. BEGIN                         
  3331.   RETURN GetCatalogStr (DefaultCatalog, string);
  3332. END GetStr;
  3333.  
  3334. PROCEDURE GetStrA * (string: ARRAY OF CHAR): e.APTR;
  3335. (* $CopyArrays- *)                           
  3336. BEGIN
  3337.   RETURN GetStr (string);
  3338. END GetStrA;  
  3339.  
  3340. (****** BlackMagic/Cat2Mod.rexx *********************************************
  3341. *
  3342. *   NAME
  3343. *       Cat2Mod.rexx - convert a catalog defintion file into Oberon source
  3344. *
  3345. *   SYNOPSIS
  3346. *       rx Cat2mod.rexx NOBLACKMAGIC=NOBM/S,
  3347. *                       CDFILE/A,BUILTINLANGUAGE=TONGUE,VERSION
  3348. *
  3349. *   FUNCTION
  3350. *       Converts a catalog definition file (#?.cd) into Oberon source as
  3351. *       needed by GetCatalogString() and GetStr(). Just import the
  3352. *       resulting source module in your Oberon main module, and you can
  3353. *       use GetCatalogString() / GetStr() with the generated string
  3354. *       constants definitions.
  3355. *
  3356. *       Originally this  rexx script needed Nico Franτois' Cat2H utility,
  3357. *       which converts catalog definitons into C-source headers. Starting
  3358. *       from version Cat2Mod.rexx 2.0, Cat2Mod.rexx reads the catalog
  3359. *       definition files directly and Cat2H employment has been discarded.
  3360. *       Since Cat2Mod.rexx 2.0, the only alien ressource used by
  3361. *       Cat2Mod.rexx is the (enclosed) rexxextra.library
  3362. *       
  3363. *   INPUTS
  3364. *       NOBLACKMAGIC=NOBM/S
  3365. *                - if this switch is specified, Cat2Mod.rexx generates
  3366. *                  a module which does _NOT_ need BlackMagic to run.
  3367. *                  The generated module exports equivalents to BlackMagic's
  3368. *                  StrIndex(), StrIndexA(), GetCatalogStr(),
  3369. *                  GetCatalogStrA(), GetStr() and GetStrA() functions.
  3370. *
  3371. *       CDFILE/A - the catalog defintion file
  3372. *
  3373. *       BUILTINLANGUAGE=TONGUE
  3374. *                - the name of the language of the built-in strings.
  3375. *                  Defaults to 'english'. Possible values for this
  3376. *                  parameter are 'deutsch', 'franτais', etc.
  3377. *
  3378. *       VERSION  - the version of the catalogs belonging to the
  3379. *                  catalog definition file that is to be processed.
  3380. *     
  3381. *   RESULT
  3382. *       the Oberon source module with the string constants defintions
  3383. *       and the default catalog opening code - import it into your main 
  3384. *       module. It tries to open its appertaining catalog in the
  3385. *       system's default language on startup, and assigns it to
  3386. *       BlackMagic.DefaultCatalog. Moreover the generated module exports
  3387. *       a function named Open<ProjectName>Catalog (language: ARRAY OF CHAR);
  3388. *       which you can use to change the language. Passing an emtpy string
  3389. *       ("") to it, makes it trying to (re)open the catalog in the system's
  3390. *       default language.
  3391. *
  3392. *   NOTES
  3393. *       This rexx script and the generated Oberon source module make
  3394. *       some assumptions about naming and storing conventions of
  3395. *       your catalog defintion and Oberon source files:
  3396. *       the destination source is written into the directory, where the
  3397. *       source catalog definition file is located. Its filename is
  3398. *       the same as the source file's one, plus 'Strings.mod', with
  3399. *       a probable '.cd' suffix of the source file name omitted.
  3400. *       The catalog is considered to be named like the file name of the
  3401. *       destination module without the trailing 'Strings.mod' in lower 
  3402. *       case, plus the standard '.catalog' suffix.
  3403. *
  3404. *   SEE ALSO
  3405. *       GetCatalogString(), GetStr()
  3406. *
  3407. *****************************************************************************)
  3408.  
  3409.  
  3410. TYPE
  3411.   SpritePtr = UNTRACED POINTER TO Sprite;
  3412.   Sprite    = ARRAY 36 OF INTEGER;
  3413. VAR 
  3414.   waitPointer: SpritePtr;  
  3415. CONST 
  3416.   waitPointer1 = Sprite(
  3417.         00000H, 00000U,
  3418.         00400H, 007C0U,
  3419.         00000H, 007C0U,
  3420.         00100H, 00380U,
  3421.         00000H, 007E0U,
  3422.         007C0H, 01FF8U,
  3423.         01FF0H, 03FECU,
  3424.         03FF8H, 07FDEU,
  3425.         03FF8H, 07FBEU,
  3426.         07FFCH, 0FF7FU,
  3427.         07EFCH, 0FFFFU,
  3428.         07FFCH, 0FFFFU,
  3429.         03FF8H, 07FFEU,
  3430.         03FF8H, 07FFEU,
  3431.         01FF0H, 03FFCU,
  3432.         007C0H, 01FF8U,
  3433.         00000H, 007E0U,
  3434.         00000H, 00000H);
  3435.  
  3436. (****** BlackMagic/SetWaitPointer **********************************************
  3437. *
  3438. *   NAME
  3439. *       SetWaitPointer - set a window's pointer to busy state
  3440. *
  3441. *   SYNOPSIS
  3442. *       SetWaitPointer (win: Intuition.WindowPtr);
  3443. *
  3444. *   FUNCTION
  3445. *       This function sets a window's pointer to busy state without
  3446. *       blocking window input or anything else. This is useful to inform
  3447. *       the user that your application is busy, but you still want to react
  3448. *       to the user's input activity.
  3449. *       This function tries to apply the best technique available at
  3450. *       runtime for this job; including Intuition V39.
  3451. *
  3452. *   INPUTS
  3453. *       win      - the window whose pointer is to be set to busy state - may
  3454. *                  be NIL.
  3455. *       
  3456. *   SEE ALSO
  3457. *       ClearWaitPointer()
  3458. *
  3459. *****************************************************************************)
  3460.  
  3461. PROCEDURE SetWaitPointer * (win: I.WindowPtr);
  3462. BEGIN
  3463.   IF win = NIL THEN RETURN; END;
  3464.   IF I.int.libNode.version >= 39 THEN
  3465.     I.SetWindowPointer (win, I.waBusyPointer, I.LTRUE, u.done);
  3466.   ELSE  
  3467.     e.Forbid();
  3468.     IF waitPointer = NIL THEN
  3469.       waitPointer := e.AllocVec (SIZE (waitPointer^), LONGSET{e.chip,e.public});
  3470.       IF waitPointer # NIL THEN waitPointer^ := waitPointer1; END;
  3471.     END;
  3472.     e.Permit();
  3473.     IF waitPointer # NIL THEN I.SetPointer(win, waitPointer^, 16, 16, 0, 0); END;
  3474.   END;
  3475. END SetWaitPointer;
  3476.  
  3477. (****** BlackMagic/ClearWaitPointer ********************************************
  3478. *
  3479. *   NAME
  3480. *       ClearWaitPointer - release a window's pointer from busy state
  3481. *
  3482. *   SYNOPSIS
  3483. *       ClearWaitPointer (win: Intuition.WindowPtr);
  3484. *
  3485. *   FUNCTION
  3486. *       This function releases a window's pointer from its busy state
  3487. *       set by SetWaitPointer(). It is generally harmless to call this
  3488. *       function without a prior call to SetWaitPointer().
  3489. *
  3490. *   INPUTS
  3491. *       win      - the window whose pointer is to be released from busy
  3492. *                  state - may be NIL.
  3493. *       
  3494. *   SEE ALSO
  3495. *       SetWaitPointer()
  3496. *
  3497. *****************************************************************************)
  3498.  
  3499. PROCEDURE ClearWaitPointer * (win: I.WindowPtr);
  3500. BEGIN
  3501.   IF win = NIL THEN RETURN; END;
  3502.   IF I.int.libNode.version >= 39 THEN
  3503.     I.SetWindowPointer (win, u.done);
  3504.   ELSE  
  3505.     I.ClearPointer (win)
  3506.   END;
  3507. END ClearWaitPointer;
  3508.     
  3509. (****** BlackMagic/LockWindow **************************************************
  3510. *
  3511. *   NAME
  3512. *       LockWindow - set a window to busy state - calls may be nested
  3513. *
  3514. *   SYNOPSIS
  3515. *       LockWindow (win: Intuition.WindowPtr;
  3516. *                   wl : WinLockPtr          ): WinLockPtr;
  3517. *
  3518. *   FUNCTION
  3519. *       This function makes a window block all input and makes it
  3520. *       indicate that it is in busy state by setting its busy pointer.
  3521. *       This function tries to apply the best technique available at
  3522. *       runtime for this job; including Intuition V39. You may nest
  3523. *       calls to this function.
  3524. *       
  3525. *
  3526. *   INPUTS
  3527. *       win      - the window to be locked - may be NIL.
  3528. *       wl       - a valid WinLockPtr from former calls to LockWindow()
  3529. *                  for the same <win> window or NIL.
  3530. *
  3531. *                 
  3532. *       
  3533. *   RESULT
  3534. *       a valid WinLockPtr that is used by UnlockWindow() to release 
  3535. *       the Window from its busy state, or NIL. (You should usually
  3536. *       not check the return value for NIL since UnlockWindow()
  3537. *       handles a NIL input correctly.
  3538. *       
  3539. *   SEE ALSO
  3540. *       UnlockWindow()
  3541. *
  3542. *****************************************************************************)
  3543.  
  3544. TYPE
  3545.   WinLockPtr * = UNTRACED POINTER TO WinLock;
  3546.   
  3547.   WinLock = STRUCT (req: I.Requester) 
  3548.     nestCount : LONGINT;
  3549.   END;  
  3550.  
  3551. PROCEDURE LockWindow * (win: I.WindowPtr; wl: WinLockPtr): WinLockPtr;
  3552. BEGIN
  3553.   IF wl # NIL THEN
  3554.     IF wl.req.rWindow = win THEN INC (wl.nestCount); END;
  3555.   ELSE
  3556.     IF win=NIL THEN RETURN NIL; END;
  3557.     y.ALLOCATE (wl);  
  3558.     IF wl=NIL THEN RETURN NIL; END;
  3559.     IF ~I.Request (wl, win) THEN DISPOSE (wl); RETURN NIL; END;
  3560.   END;  
  3561.   SetWaitPointer (win);
  3562.   RETURN wl;
  3563. END LockWindow;  
  3564.   
  3565.  
  3566. (****** BlackMagic/UnlockWindow ************************************************
  3567. *
  3568. *   NAME
  3569. *       UnlockWindow - release a window from its busy state
  3570. *
  3571. *   SYNOPSIS
  3572. *       UnlockWindow (VAR wl: WinLockPtr);
  3573. *
  3574. *   FUNCTION
  3575. *       This function releases a window that was previously set to busy
  3576. *       state by LockWindow() from its busy state and frees the passed
  3577. *       wl WinLockPtr if the nest count is zero, otherwise the nest count
  3578. *       is solely decremented by 1. For a NIL wl input parameter, it does 
  3579. *       nothing at all. 
  3580. *
  3581. *   INPUTS
  3582. *       wl       - the WinLockPtr retured by LockWindow(). May be NIL.
  3583. *       
  3584. *   RESULTS
  3585. *       The VAR wl is cleared if the window has really been unlocked.
  3586. *
  3587. *   SEE ALSO
  3588. *       LockWindow()
  3589. *
  3590. *****************************************************************************)
  3591.  
  3592. PROCEDURE UnlockWindow* (VAR wl: WinLockPtr);
  3593. VAR
  3594.   win: I.WindowPtr;
  3595. BEGIN
  3596.   IF wl = NIL THEN RETURN END;
  3597.   IF wl.nestCount > 0 THEN
  3598.     DEC (wl.nestCount);
  3599.   ELSE  
  3600.     win := wl.req.rWindow;
  3601.     I.EndRequest (wl, win);
  3602.     ClearWaitPointer (win);
  3603.     DISPOSE (wl);
  3604.   END;  
  3605. END UnlockWindow;  
  3606.  
  3607.  
  3608. (****** BlackMagic/gtItemAddr *************************************************
  3609. *
  3610. *   NAME
  3611. *       gtItemAddr - return the MenuItem from a GadTools.NewMenu.userData
  3612. *
  3613. *   SYNOPSIS
  3614. *       gtItemAddr (menu: Intuition.MenuPtr; 
  3615. *                   data: Exec.APTR         ): Intuition.MenuItemPtr;
  3616. *
  3617. *   FUNCTION
  3618. *       This function returns the menu item that was created by GadTools
  3619. *       from a specific GadTools.NewMenu entry. This is done, employing
  3620. *       the GadTools.NewMenu.userData field, which has to be set to a 
  3621. *       unique value if you want to find the menu item using this function.
  3622. *       Both, items and sub items are found.
  3623. *
  3624. *   INPUTS
  3625. *       menu     - the Intuition menu that was previously created by 
  3626. *                  GadTools.CreateMenusA() - may be NIL.
  3627. *       data     - the unique userData entry of a GadTools.NewMenu array
  3628. *                  element of either GadTools.item or GadTools.sub type
  3629. *       
  3630. *   RESULT
  3631. *       a valid Intuition.MenuItemPtr or NIL if the item was not found in
  3632. *       in the menu chain.
  3633. *       
  3634. *   SEE ALSO
  3635. *       gtMenuAddr()
  3636. *
  3637. *****************************************************************************)
  3638.       
  3639. PROCEDURE gtItemAddr * (menu: I.MenuPtr; 
  3640.                         data: e.APTR    ): I.MenuItemPtr;
  3641.  
  3642. VAR
  3643.   i,s: I.MenuItemPtr;
  3644. BEGIN  
  3645.   WHILE menu # NIL DO    
  3646.     i := menu.firstItem;
  3647.     WHILE i # NIL DO
  3648.       IF gt.MenuItemUserData (i) = data THEN RETURN i; END;
  3649.       s := i.subItem;
  3650.       WHILE s # NIL DO
  3651.         IF gt.MenuItemUserData (s) = data THEN RETURN s; END;
  3652.         s := s.nextItem;
  3653.       END;  
  3654.       i := i.nextItem;
  3655.     END;  
  3656.     menu := menu.nextMenu;
  3657.   END;  
  3658.   RETURN NIL;
  3659. END gtItemAddr;
  3660.  
  3661. (****** BlackMagic/gtMenuAddr *************************************************
  3662. *
  3663. *   NAME
  3664. *       gtMenuAddr - return the Menu from a GadTools.NewMenu.userData
  3665. *
  3666. *   SYNOPSIS
  3667. *       gtMenuAddr (firstmenu: Intuition.MenuPtr; 
  3668. *                   data     : Exec.APTR         ): Intuition.MenuPtr;
  3669. *
  3670. *   FUNCTION
  3671. *       This function returns the menu that was created by GadTools
  3672. *       from a specific GadTools.NewMenu entry. This is done, employing
  3673. *       the GadTools.NewMenu.userData field, which has to be set to a 
  3674. *       unique value if you want to find the menu using this function.
  3675. *
  3676. *   INPUTS
  3677. *       firstmenu- the Intuition menu that was previously created by 
  3678. *                  GadTools.CreateMenusA() - may be NIL.
  3679. *       data     - the unique userData entry of a GadTools.NewMenu array
  3680. *                  element of GadTools.title type
  3681. *       
  3682. *   RESULT
  3683. *       a valid Intuition.MenuPtr or NIL if the menu was not found in
  3684. *       in the menu chain.
  3685. *       
  3686. *   SEE ALSO
  3687. *       gtItemAddr()
  3688. *
  3689. *****************************************************************************)
  3690.       
  3691. PROCEDURE gtMenuAddr * (firstmenu: I.MenuPtr; 
  3692.                         data    : e.APTR    ): I.MenuPtr;
  3693. BEGIN  
  3694.   WHILE firstmenu # NIL DO    
  3695.     IF gt.MenuUserData (firstmenu) = data THEN RETURN firstmenu; END;
  3696.     firstmenu := firstmenu.nextMenu;
  3697.   END;  
  3698.   RETURN NIL;
  3699. END gtMenuAddr;
  3700.  
  3701.  
  3702. (****** BlackMagic/GadKey *****************************************************
  3703. *
  3704. *   NAME
  3705. *       GadKey / GadKeyA - return the key shortcut for a string.
  3706. *
  3707. *   SYNOPSIS
  3708. *       GadKey (gadstr: ARRAY OF CHAR): CHAR;
  3709. *
  3710. *       GadKeyA (gadstr: Exec.APTR): CHAR;
  3711. *
  3712. *   FUNCTION
  3713. *       These functions return the key shortcut character from a string.
  3714. *       They search for the underscrore character in the string, and
  3715. *       if they find one, return the following charcter as the key
  3716. *       shortcut. Otherwise a nul character is returned. For GadKeyA(),
  3717. *       a NIL pointer may be passed. In that case, the result will be
  3718. *       the nul character as well. These functions use the 
  3719. *       BlackMagic.UnderScore variable for identifiying the underscore
  3720. *       character. By default, this variable is initialized to '_'.
  3721. *       However, you may change that to any character you want.
  3722. *       
  3723. *
  3724. *   INPUTS
  3725. *       gadstr   - the string to be searched for an underscore sequence.
  3726. *                  Either as an ARRAY OF CHAR for GadKey() or as an
  3727. *                  Exec.APTR for GadKeyA().
  3728. *       
  3729. *   RESULT
  3730. *       the key shortcut character or the nul character, if no shortcut
  3731. *       was found.
  3732. *       
  3733. *****************************************************************************)
  3734.       
  3735. VAR
  3736.   UnderScore * : CHAR;
  3737.  
  3738. PROCEDURE GadKey * (gadstr: ARRAY OF CHAR): CHAR;
  3739. VAR
  3740.   j : LONGINT;
  3741. (* $CopyArrays- *)
  3742. BEGIN
  3743.   j := 0;
  3744.   WHILE gadstr[j] # '\000' DO
  3745.     IF gadstr[j] = UnderScore THEN RETURN gadstr[j+1]; END;
  3746.     INC (j);
  3747.   END;
  3748.   RETURN '\000';
  3749. END GadKey;  
  3750.  
  3751. PROCEDURE GadKeyA * (gadstr: e.APTR): CHAR;
  3752. VAR
  3753.   str: LongStrPtr;
  3754. BEGIN
  3755.   IF gadstr = NIL THEN RETURN CHR (0); END;
  3756.   str := gadstr;
  3757.   RETURN GadKey (str^);
  3758. END GadKeyA;  
  3759.  
  3760.   
  3761. (****** BlackMagic/ClearMem ***************************************************
  3762. *
  3763. *   NAME
  3764. *       ClearMem     -- clear memory
  3765. *       ClearMemAPTR --   "     "
  3766. *
  3767. *   SYNOPSIS
  3768. *       ClearMem     (mem: ARRAY OF SYSTEM.BYTE; n: LONGINT);
  3769. *
  3770. *       ClearMemAPTR (mem: Exec.APTR; n: LONGINT);
  3771. *
  3772. *   FUNCTION
  3773. *       These functions clear n bytes of memory starting at
  3774. *       address mem, or in case of ClearMem(), it clears the whole
  3775. *       structure represented by the mem BYTE-ARRAY if -1 is passed
  3776. *       for the n parameter.
  3777. *
  3778. *   INPUTS
  3779. *       mem      - the starting position for the clearing operation
  3780. *                  as an ARRAY OF SYSTEM.BYTE for ClearMem() or as an
  3781. *                  Exec.APTR for ClearMemAPTR()
  3782. *       n        - the number of bytes to be cleared. In case of
  3783. *                  ClearMem(), this parameter may be -1, in which case
  3784. *                  the whole structure represented by the BYTE-ARRAY
  3785. *                  is cleared.
  3786. *       
  3787. *   SEE ALSO
  3788. *       Exec/CopyMem(), Exec.CopyMemAPTR()
  3789. *       
  3790. *****************************************************************************)
  3791.  
  3792. PROCEDURE ClearMem * (mem: ARRAY OF y.BYTE; n: LONGINT);
  3793. (* $CopyArrays- *)
  3794. BEGIN
  3795.   IF n=-1 THEN n := LEN (mem); END;
  3796.   IF n < 1 THEN RETURN; END;
  3797.   WHILE n > 0 DO DEC (n); mem[n] := 0; END;
  3798. END ClearMem;  
  3799.   
  3800. PROCEDURE ClearMemAPTR * (mem: e.APTR; n: LONGINT);
  3801. VAR
  3802.   m: UNTRACED POINTER TO ARRAY 1 OF y.BYTE;
  3803. BEGIN
  3804.   m := mem;
  3805.   IF n < 1 THEN RETURN; END;
  3806.   ClearMem (m^, n);
  3807. END ClearMemAPTR;
  3808.   
  3809.  
  3810. (****** BlackMagic/Max2 *****************************************************
  3811. *
  3812. *   NAME
  3813. *       Max2 - return the maximum of two numbers
  3814. *       Min2 - return the minimum of two numbers
  3815. *
  3816. *   SYNOPSIS
  3817. *       Max2 (x, y: LONGINT): LONGINT;
  3818. *
  3819. *       Min2 (x, y: LONGINT): LONGINT;
  3820. *
  3821. *   FUNCTION
  3822. *       These functions just return the larger / smaller one of two
  3823. *       supplied numbers. As this job is needed very often, and
  3824. *       since many programmers are lazybones;-) who use roundabout
  3825. *       programming instead of implementing these functions, I decided
  3826. *       to supply these trivial functions.
  3827. *
  3828. *   INPUTS
  3829. *       x,y      - two numbers 
  3830. *       
  3831. *   RESULT
  3832. *       the maximum / minimum of the supplied numbers
  3833. *       
  3834. *   NOTES
  3835. *       Max3() etc. can be emulated by code like 'Max2 (Max2 (x, y), z)', 
  3836. *       of course.
  3837. *
  3838. *****************************************************************************)
  3839.  
  3840. PROCEDURE Max2 * (x, y: LONGINT): LONGINT;
  3841. BEGIN
  3842.   IF x > y THEN RETURN x; ELSE RETURN y; END;
  3843. END Max2;  
  3844.  
  3845. PROCEDURE Min2 * (x, y: LONGINT): LONGINT;
  3846. BEGIN
  3847.   IF x < y THEN RETURN x; ELSE RETURN y; END;
  3848. END Min2;  
  3849.  
  3850.  
  3851. (****** BlackMagic/Strlastnicmp **********************************************
  3852. *
  3853. *   NAME
  3854. *       Strlastnicmp - length-limited case-insensitive backward str compare
  3855. *
  3856. *   SYNOPSIS
  3857. *       Strlastnicmp (s1, s2: ARRAY OF CHAR, n: LONGINT): BOOLEAN;
  3858. *
  3859. *   FUNCTION
  3860. *       This function provides the much needed but rarely found
  3861. *       complement for the Utility.Strnicmp() function. It compares
  3862. *       two strings starting from the last character. It returns
  3863. *       TRUE if the last n characters match, or if both strings
  3864. *       are shorter than n characters and match exactly.
  3865. *       The comparisons are performed case-insensitively using the
  3866. *       Utility.library Stricmp() function.
  3867. *
  3868. *   INPUTS
  3869. *       s1,s2    - the strings to be compared
  3870. *       n        - the maximum number of characters that may be taken
  3871. *                  into account
  3872. *
  3873. *   RESULT
  3874. *       TRUE for equality, FALSE otherwise
  3875. *       
  3876. *   SEE ALSO
  3877. *       Strlastncmp(), Utility/Strnicmp()
  3878. *
  3879. *****************************************************************************)
  3880.  
  3881. PROCEDURE Strlastnicmp * (s1, s2: ARRAY OF CHAR; n: LONGINT): BOOLEAN;
  3882. VAR
  3883.   l1, l2: LONGINT;  
  3884. (* $CopyArrays- *)
  3885. BEGIN
  3886.   l1 := st.Length (s1); l2 := st.Length (s2);
  3887.   IF (l1 < n) OR (l2 < n) THEN RETURN u.Stricmp (s1, s2) = 0; END;
  3888.   RETURN u.Stricmp (StrIndex (s1, l1-n)^, StrIndex (s2, l2-n)^) = 0;
  3889. END Strlastnicmp;  
  3890.   
  3891. (****** BlackMagic/Strlastncmp **********************************************
  3892. *
  3893. *   NAME
  3894. *       Strlastncmp - length-limited case-sensitive backward string compare
  3895. *
  3896. *   SYNOPSIS
  3897. *       Strlastncmp (s1, s2: ARRAY OF CHAR, n: LONGINT): BOOLEAN;
  3898. *
  3899. *   FUNCTION
  3900. *       Same as Strlastnicmp(), except that comparisons are made
  3901. *       case-sensitively.
  3902. *       
  3903. *   SEE ALSO
  3904. *       Strlastnicmp()
  3905. *
  3906. *****************************************************************************)
  3907.  
  3908. PROCEDURE Strlastncmp * (s1, s2: ARRAY OF CHAR; n: LONGINT): BOOLEAN;
  3909. VAR
  3910.   l1, l2: LONGINT;  
  3911. (* $CopyArrays- *)
  3912. BEGIN
  3913.   l1 := st.Length (s1); l2 := st.Length (s2);
  3914.   IF (l1 < n) OR (l2 < n) THEN RETURN s1=s2; END;
  3915.   RETURN StrIndex (s1, l1-n)^ = StrIndex (s2, l2-n)^;
  3916. END Strlastncmp;  
  3917.   
  3918. (****** BlackMagic/ScrVPExtra ********************************************
  3919. *
  3920. *   NAME
  3921. *       ScrVPExtra - return a screen's Graphics.ViewPortExtra structure
  3922. *
  3923. *   SYNOPSIS
  3924. *       ScrVPExtra (scr: Intuition.ScreenPtr): Graphics.ViewPortExtraPtr; 
  3925. *
  3926. *   FUNCTION
  3927. *       This function returns the ViewPortExtra structure associated
  3928. *       with a screen's ViewPort. The ViewPortExtra structure holds the
  3929. *       Screen's DisplayClip information in its vpe.displayClip entry.
  3930. *
  3931. *   INPUTS
  3932. *       scr      - the screen whose VPE you want to get - may be NIL
  3933. *       
  3934. *   RESULT
  3935. *       a pointer to the screen's ViewPortExtra structure or NIL for failure
  3936. *       
  3937. *****************************************************************************)
  3938.  
  3939. CONST 
  3940.   vTags = u.Tags2 (g.vTagViewPortExtraGet, NIL, g.vTagEndCM, NIL);
  3941.  
  3942. PROCEDURE ScrVPExtra * (scr: I.ScreenPtr): g.ViewPortExtraPtr;
  3943. VAR
  3944.   VTags: u.Tags2;
  3945.   VPE  : g.ViewPortExtraPtr;
  3946. BEGIN
  3947.   IF scr = NIL THEN RETURN NIL; END;
  3948.   VTags := vTags;
  3949.   IF g.VideoControlA (scr.viewPort.colorMap, VTags) THEN RETURN NIL; END;
  3950.   IF VTags[0].tag # g.vTagViewPortExtraSet THEN RETURN NIL; END;
  3951.   RETURN VTags[0].data;
  3952. END ScrVPExtra;
  3953.  
  3954.   
  3955. (****** BlackMagic/VisibleOfScreen ********************************************
  3956. *
  3957. *   NAME
  3958. *       VisibleOfScreen - return the visible region of a screen
  3959. *
  3960. *   SYNOPSIS
  3961. *       VisibleOfScreen (scr        : Intuition.ScreenPtr; 
  3962. *                        VAR visible: Graphics.Rectangle  ): BOOLEAN;
  3963. *
  3964. *   FUNCTION
  3965. *       This function fills in the supplied Graphics.Rectangle structure
  3966. *       with the bounds of the region of the provided Screen that is
  3967. *       currently visible in the Screen's DisplayClip. It handles
  3968. *       all possible cases of DisplayClip<->Screen dimensions.
  3969. *
  3970. *   INPUTS
  3971. *       scr      - the screen to investigate - may be NIL
  3972. *       visible  - the Graphics.Rectangle strucute that is to be filled
  3973. *                  with the bounds.
  3974. *       
  3975. *   RESULT
  3976. *       TRUE if everything if the supplied Rectangle structure has been
  3977. *       filled with the bounds, FALSE if the necessary information couldn't
  3978. *       be obtained for some reason. Note that the supplied Rectangle
  3979. *       structure's coordinates are all filled with 0 if you pass
  3980. *       a NIL scr Intuition.ScreenPtr, or with the bounds of the whole
  3981. *       screen if the function fails due to another reason.
  3982. *       
  3983. *****************************************************************************)
  3984.  
  3985. PROCEDURE VisibleOfScreen * (scr: I.ScreenPtr; VAR visible: g.Rectangle): BOOLEAN;
  3986. VAR
  3987.   VPE  : g.ViewPortExtraPtr;
  3988. BEGIN
  3989.  
  3990.   visible.minX := 0; visible.minY := 0; visible.maxX := 0; visible.maxY := 0;
  3991.   IF scr = NIL THEN RETURN FALSE; END;
  3992.   visible.maxX := scr.width-1; visible.maxY := scr.height-1;
  3993.   VPE := ScrVPExtra (scr);
  3994.   IF VPE = NIL THEN RETURN FALSE; END;
  3995.   visible.minX := SHORT (Max2 (0, -scr.leftEdge + VPE.displayClip.minX));
  3996.   visible.minY := SHORT (Max2 (0, -scr.topEdge + VPE.displayClip.minY));
  3997.   visible.maxX := SHORT (Min2 (scr.width - 1, -scr.leftEdge + VPE.displayClip.maxX));
  3998.   visible.maxY := SHORT (Min2 (scr.height - 1, -scr.topEdge + VPE.displayClip.maxY));
  3999.   RETURN TRUE;
  4000. END VisibleOfScreen;  
  4001.  
  4002.  
  4003. (****** BlackMagic/SPrintf ****************************************************
  4004. *
  4005. *   NAME
  4006. *       SPrintf ╣ -- varargs sprintf output formatting using Exec.RawDoFmt
  4007. *       SPrintF ╣ -- varargs sprintf output formatting without result code
  4008. *       VSPrintf ╣ -- vector sprintf output formatting using Exec.RawDoFmt
  4009. *       VSPrintF ╣ -- vector sprintf output formatting without result code
  4010. *
  4011. *   SYNOPSIS
  4012. *       BlackMagicVA.SPrintf (buffer: ARRAY OF CHAR;
  4013. *                             format: ARRAY OF CHAR;
  4014. *                             args..: Exec.APTR     ): LONGINT;
  4015. *
  4016. *       BlackMagicVA.SPrintF (buffer: ARRAY OF CHAR;
  4017. *                             format: ARRAY OF CHAR;
  4018. *                             args..: Exec.APTR     );
  4019. *
  4020. *       BlackMagicVA.VSPrintf (buffer: ARRAY OF CHAR;
  4021. *                              format: ARRAY OF CHAR;
  4022. *                              args  : Exec.APTR     ): LONGINT;
  4023. *
  4024. *       BlackMagicVA.VSPrintF (buffer: ARRAY OF CHAR;
  4025. *                              format: ARRAY OF CHAR;
  4026. *                              args  : Exec.APTR     );
  4027. *
  4028. *   FUNCTION
  4029. *       These functions are full featured implementations of sprintf()/
  4030. *       vsprintf(), supporting also the nifty varargs paramters provided
  4031. *       by Amiga-Oberon for library calls. Due to the fact that these
  4032. *       functions are implemented as library functions, you may pass NIL
  4033. *       for the buffer ARRAY OF CHAR parameter which makes this function
  4034. *       doing nothing but returning the length WITHOUT the trailing null
  4035. *       byte of the generated output.
  4036. *
  4037. *   INPUTS
  4038. *       buffer   - the buffer into which the output is written to or
  4039. *                  NIL
  4040. *       format   - the format string with the formatting directives.
  4041. *                  For a detailed description of all possible directives
  4042. *                  have a look at Exec/RawDoFmt(). *ALL* directives
  4043. *                  except of %s/%b require a leading 'l' right before the
  4044. *                  type character, e.g. '%ld', '%08lx' or '%lc' instead of
  4045. *                  '%d', '%08x' or '%c'. This is true for Dos/Printf() and
  4046. *                  similar functions as well.
  4047. *       args     - the arguments to be included into the generated
  4048. *                  string according to the directives specified in the
  4049. *                  format string. Either as varargs for SPrintf()/SPrintF()
  4050. *                  or as a pointer to the arguemnts for VSPrintf()/
  4051. *                  VSPrintF()
  4052. *
  4053. *   RESULT
  4054. *      LONGINT   - the length of the generated output WITHOUT the trailing
  4055. *                  null byte, which is actually written into the buffer
  4056. *                  as the last byte.
  4057. *
  4058. *   NOTES
  4059. *       ╣) All these functions are placed in the BlackMagicVA module!
  4060. *
  4061. *   SEE ALSO
  4062. *       DynAppendFmt(), VDynAppendFmt(), Exec/RawDoFmt(), Dos/VPrintf()
  4063. *
  4064. *****************************************************************************)
  4065.  
  4066. (* refer to BlackMagicVA for sprintf() - code *)
  4067.  
  4068.  
  4069. (****** BlackMagic/DynAppendFmt ***********************************************
  4070. *
  4071. *   NAME
  4072. *       DynAppendFmt/DSPrintf ╣ -- append sprintf str to a dynstr (varargs)
  4073. *       VDynAppendFmt/VDSPrintf -- append sprintf str to dynstr (vector args)
  4074. *
  4075. *   SYNOPSIS
  4076. *       BlackMagicVA.DynAppendFmt 
  4077. *       BlackMagicVA.DSPrintf     (VAR dstr: DynStrPtr;
  4078. *                                  format  : ARRAY OF CHAR;
  4079. *                                  args..  : Exec.APTR     ): BOOLEAN;
  4080. *
  4081. *       VDynAppendFmt
  4082. *       VDSPrintf     (VAR dstr: DynStrPtr;
  4083. *                      format  : ARRAY OF CHAR;
  4084. *                      args    : Exec.APTR     ): BOOLEAN;
  4085. *
  4086. *   FUNCTION
  4087. *       These functions are similar to SPrintF()/VSPrintF(), except that
  4088. *       they act on dynamic strings rather than on simple strings, and
  4089. *       append the resulting string to the dynamic string rather than
  4090. *       overwriting it. Note that the valid string bounds will be _never_
  4091. *       violated.
  4092. *       
  4093. *   INPUTS
  4094. *       dstr     - the handle for the dynamic string, to which the
  4095. *                  resulting string is appended to. May be NIL.
  4096. *       format   - the format string with the formatting directives.
  4097. *                  For a detailed description of all possible directives
  4098. *                  have a look at Exec/RawDoFmt(). *ALL* directives
  4099. *                  except of %s/%b require a leading 'l' right before the
  4100. *                  type character, e.g. '%ld', '%08lx' or '%lc' instead of
  4101. *                  '%d', '%08x' or '%c'. This is true for Dos/Printf() and
  4102. *                  similar functions as well.
  4103. *       args     - the arguments to be included into the generated
  4104. *                  string according to the directives specified in the
  4105. *                  format string. Either as varargs for DynAppendFmt()/
  4106. *                  DSPrintf() or as a pointer to the arguemnts for
  4107. *                  VDynAppendFmt()/VDSPrintf().
  4108. *
  4109. *   RESULT
  4110. *      BOOLEAN   - TRUE if the resulting string was successfully appended to
  4111. *                  the dynamic string, FALSE otherwise. For FALSE, the
  4112. *                  contents of the dynamic string, not necessarily its
  4113. *                  handle, are left unchanged.
  4114. *
  4115. *   NOTES
  4116. *       ╣) The functions with var args parameters are placed in the
  4117. *       BlackMagicVA module! The other functions are exported by both,
  4118. *       BlackMagic and BlackMagicVA.
  4119. *
  4120. *   SEE ALSO
  4121. *       SPrintF(), VSPrintF(), Exec/RawDoFmt(), Dos/VPrintf()
  4122. *
  4123. *****************************************************************************)
  4124.  
  4125. TYPE
  4126.   FmtDataPtr = UNTRACED POINTER TO FmtData;
  4127.   FmtData = STRUCT
  4128.     a5       : e.APTR;
  4129.     dstr     : UNTRACED POINTER TO DynStrPtr;
  4130.     success  : BOOLEAN;
  4131.   END;  
  4132.  
  4133. PROCEDURE FmtFunc1 (VAR data: FmtData; ch: CHAR);
  4134. VAR
  4135.   chrs: ARRAY 2 OF CHAR;
  4136. BEGIN
  4137.   IF ~data.success THEN RETURN; END;
  4138.   chrs[0] := ch; chrs[1] := '\000';
  4139.   data.success := DynAppend (data.dstr^, chrs);
  4140. END FmtFunc1;
  4141.  
  4142. PROCEDURE FmtFunc (VAR data{11}: FmtData; ch{0}: CHAR; SaveA0Kludge{8}: LONGINT);
  4143. VAR
  4144.   c: CHAR;
  4145.  
  4146. (* Amiga-Oberon3.0 does not save A0 with SaveAllRegs+ - The SaveA0Kludge parameter solves that for you *)
  4147. (* 7-Jul-93: Maybe that's not true - I discovered that ADis1.11 - a freeware symbolic *)
  4148. (* reassembler I use - mismatches some MOVEM reglists! *)
  4149.  
  4150. (* $StackChk- $SaveAllRegs+ *)
  4151. BEGIN
  4152.   c := ch; (* d0/d1 volatile! *)
  4153.   y.SETREG (13, data.a5);
  4154.   FmtFunc1 (data, c);
  4155. END FmtFunc;
  4156. (* $StackChk= *)
  4157.   
  4158. PROCEDURE DynAppendFmtInternal1 (dstr  : UNTRACED POINTER TO DynStrPtr;
  4159.                                  format: LongStrPtr;
  4160.                                  args  : e.APTR                        ): BOOLEAN;
  4161. VAR
  4162.   data: FmtData;
  4163.   origLen : LONGINT;
  4164. BEGIN
  4165.   data.a5 := y.REG (13);
  4166.   data.dstr := dstr; data.success := TRUE;
  4167.   origLen := DynStrLen (dstr^);
  4168.   e.OldRawDoFmt (format^, args, y.VAL (e.PROC, FmtFunc), y.ADR (data));
  4169.   IF ~data.success THEN IF dstr^ # NIL THEN dstr^[origLen] := '\000'; END; END;
  4170.   RETURN data.success;
  4171. END DynAppendFmtInternal1;
  4172.   
  4173.  
  4174. PROCEDURE VDynAppendFmt * (VAR dstr: DynStrPtr; 
  4175.                            format  : ARRAY OF CHAR;
  4176.                            args    : e.APTR        ): BOOLEAN;
  4177. (* $CopyArrays- *)                         
  4178. BEGIN
  4179.   RETURN DynAppendFmtInternal1 (y.ADR (dstr), y.ADR (format[0]), args);
  4180. END VDynAppendFmt;  
  4181.                          
  4182. PROCEDURE VDSPrintf * (VAR dstr: DynStrPtr; 
  4183.                        format  : ARRAY OF CHAR;
  4184.                        args    : e.APTR        ): BOOLEAN;
  4185. (* $CopyArrays- *)                         
  4186. BEGIN
  4187.   RETURN DynAppendFmtInternal1 (y.ADR (dstr), y.ADR (format[0]), args);
  4188. END VDSPrintf;
  4189.  
  4190.  
  4191. (****** BlackMagic/DynFmtLocale ***********************************************
  4192. *
  4193. *   NAME
  4194. *       DynFmtLocale ╣ -- do locale/FormatString() with a dynstr (varargs)
  4195. *       VDynFmtLocale -- do locale/FormatString() with dynstr (vector args)
  4196. *
  4197. *   SYNOPSIS
  4198. *       BlackMagicVA.DynFmtLocale (VAR dstr: DynStrPtr;
  4199. *                                  locale  : Locale.LocalePtr;
  4200. *                                  format  : ARRAY OF CHAR;
  4201. *                                  args..  : Exec.APTR     ): BOOLEAN;
  4202. *
  4203. *       VDynFmtLocale (VAR dstr: DynStrPtr;
  4204. *                      locale  : Locale.LocalePtr;
  4205. *                      format  : ARRAY OF CHAR;
  4206. *                      args    : Exec.APTR     ): BOOLEAN;
  4207. *
  4208. *   FUNCTION
  4209. *       These functions offer a dynamic string interface to locale.library's
  4210. *       FormatString() function, which is a RawDoFmt() / xxxprintf() - like
  4211. *       string formatting function with some additional support for
  4212. *       localization. Both functions append the resulting string to the
  4213. *       dynamic string represented by the dstr handle. The valid string
  4214. *       bounds of dstr will never be violated, it rather returns failure
  4215. *       if not enough string space  could be allocated. If Locale.base is
  4216. *       NIL, these functions perform a fallback to (V)DynAppendFmt().
  4217. *
  4218. *   INPUTS
  4219. *       dstr     - the handle for the dynamic string, to which the
  4220. *                  resulting string is appended to. May be NIL.
  4221. *       locale   - the locale structure to use for formatting. May be NIL,
  4222. *                  in which case the system's default locale is used.
  4223. *       format   - the format string with the formatting directives.
  4224. *                  For a detailed description of all possible directives
  4225. *                  have a look at Locale/FormatString(). *ALL* directives
  4226. *                  except of %s/%b require a leading 'l' right before the
  4227. *                  type character, e.g. '%ld', '%08lx' or '%lc' instead of
  4228. *                  '%d', '%08x' or '%c'. This is true for Dos/Printf() and
  4229. *                  similar functions as well.
  4230. *       args     - the arguments to be included into the generated
  4231. *                  string according to the directives specified in the
  4232. *                  format string. Either as varargs for DynFmtLocale()
  4233. *                  or as a pointer to the arguemnts for VDynFmtLocale().
  4234. *
  4235. *   RESULT
  4236. *      BOOLEAN   - TRUE if the resulting string was successfully appended
  4237. *                  to the dynamic string, FALSE otherwise (Probably failed
  4238. *                  memory allocation for the dynamic string or a NIL-
  4239. *                  Locale.base). For FALSE, the contents of the dynamic 
  4240. *                  string, not necessarily its handle, are left unchanged.
  4241. *
  4242. *   NOTES
  4243. *       ╣) The functions with var args parameters are placed in the
  4244. *       BlackMagicVA module! The other functions are exported by both,
  4245. *       BlackMagic and BlackMagicVA.
  4246. *
  4247. *   SEE ALSO
  4248. *       DynAppendFmt(), Locale/FormatString(), FLPrintf()
  4249. *
  4250. *****************************************************************************)
  4251.  
  4252. PROCEDURE FmtLocaleHookFunc1 (VAR data: FmtData; ch: LONGINT);
  4253. VAR
  4254.   c2  : ARRAY 2 OF CHAR;
  4255. BEGIN
  4256.   IF ~data.success THEN RETURN; END;
  4257.   c2[0] := CHR (ch); c2[1] := '\000';
  4258.   data.success := DynAppend (data.dstr^, c2);
  4259. END FmtLocaleHookFunc1;
  4260.   
  4261. PROCEDURE FmtLocaleHookFunc (hk{8}: u.HookPtr; ch{9}: LONGINT);
  4262. VAR
  4263.   data: FmtDataPtr;
  4264. (* $StackChk- $SaveRegs+ *)
  4265. BEGIN
  4266.   data := hk.data;
  4267.   y.SETREG (13, data.a5);
  4268.   FmtLocaleHookFunc1 (data^, ch);
  4269. END FmtLocaleHookFunc;
  4270. (* $StackChk= *)  
  4271.  
  4272. TYPE HookEntryProc = PROCEDURE(hook{8}   : u.HookPtr;
  4273.                                object{10}: e.APTR;
  4274.                                message{9}: e.APTR): LONGINT; 
  4275.  
  4276. PROCEDURE DynFmtLocaleInternal1 (dstr  : UNTRACED POINTER TO DynStrPtr;
  4277.                                  locale: loc.LocalePtr;
  4278.                                  format: LongStrPtr;
  4279.                                  args  : e.APTR                        ): BOOLEAN;
  4280. VAR
  4281.   hk      : u.Hook;                                
  4282.   data    : FmtData;
  4283.   origLen : LONGINT;
  4284.   locale1 : loc.LocalePtr;  
  4285. BEGIN
  4286.   IF ~DynExpand (dstr^, 0) THEN RETURN FALSE; END;
  4287.   IF format = NIL THEN RETURN TRUE; END;
  4288.   IF loc.base = NIL THEN 
  4289.     RETURN VDSPrintf (dstr^, format^, args); 
  4290.   END;
  4291.   IF locale = NIL THEN locale1 := loc.OpenLocale (NIL); ELSE locale1 := locale; END;
  4292.   hk.entry := y.VAL (HookEntryProc, FmtLocaleHookFunc);
  4293.   data.a5 := y.REG (13); hk.subEntry := NIL; hk.data := y.ADR (data);
  4294.   data.dstr := dstr; data.success := TRUE;
  4295.   origLen := DynStrLen (dstr^);
  4296.   y.SETREG (0, loc.FormatString (locale1, format^, args, y.ADR (hk)));
  4297.   IF ~data.success THEN IF dstr^ # NIL THEN dstr^[origLen] := '\000'; END; END;
  4298.   IF locale = NIL THEN loc.CloseLocale (locale1); END;
  4299.   RETURN data.success;
  4300. END DynFmtLocaleInternal1;
  4301.  
  4302. PROCEDURE VDynFmtLocale * (VAR dstr: DynStrPtr;
  4303.                            locale  : loc.LocalePtr;
  4304.                            format  : ARRAY OF CHAR;
  4305.                            args    : e.APTR        ): BOOLEAN;
  4306. (* $CopyArrays- *)
  4307. BEGIN
  4308.   RETURN DynFmtLocaleInternal1 (y.ADR (dstr), locale, y.ADR (format[0]), args);
  4309. END VDynFmtLocale;  
  4310.  
  4311.  
  4312. (****** BlackMagic/FLPrintf ***************************************************
  4313. *
  4314. *   NAME
  4315. *       FLPrintf ╣ -- equivalent to Dos/FPrintf() with localization support
  4316. *       FLPrintF ╣ -- equivalent to FLPrintf without return code
  4317. *       VFLPrintF -- equivalent to FLPrintf with vector args
  4318. *
  4319. *   SYNOPSIS
  4320. *       BlackMagicVA.FLPrintf (fh    : d.FileHandlePtr;
  4321. *                              locale: loc.LocalePtr;
  4322. *                              format: ARRAY OF CHAR;
  4323. *                              args..: e.APTR        ): BOOLEAN;
  4324. *       
  4325. *       BlackMagicVA.FLPrintF (fh    : d.FileHandlePtr;
  4326. *                              locale: loc.LocalePtr;
  4327. *                              format: ARRAY OF CHAR;
  4328. *                              args..: e.APTR        );
  4329. *       
  4330. *       VFLPrintf (fh    : d.FileHandlePtr;
  4331. *                  locale: loc.LocalePtr;
  4332. *                  format: ARRAY OF CHAR;
  4333. *                  args  : e.APTR        ): BOOLEAN;
  4334. *       
  4335. *   FUNCTION
  4336. *       These functions use VDynFmtLocale() to build a string according
  4337. *       to the provided arguments and if this succeeded, they write it
  4338. *       to the fh file.
  4339. *
  4340. *   INPUTS
  4341. *       fh       - the file to write the resulting string to.
  4342. *                  May be NIL, in which case stdout is used.
  4343. *  
  4344. *       Other:   - see DynFmtLocale()
  4345. *
  4346. *   RESULT
  4347. *      BOOLEAN   - TRUE if the resulting string was successfully generated
  4348. *                  and written, FALSE otherwise.
  4349. *
  4350. *   NOTES
  4351. *       ╣) The functions with var args parameters are placed in the
  4352. *       BlackMagicVA module! The other functions are exported by both,
  4353. *       BlackMagic and BlackMagicVA.
  4354. *
  4355. *   SEE ALSO
  4356. *       DynAppendFmt(), Locale/FormatString(), DynFmtLocale()
  4357. *
  4358. *****************************************************************************)
  4359.  
  4360. PROCEDURE FLPrintfInternal1 (fh    : d.FileHandlePtr;
  4361.                              locale: loc.LocalePtr;
  4362.                              format: LongStrPtr;
  4363.                              args  : e.APTR          ): BOOLEAN;
  4364. VAR
  4365.   ds: DynStrPtr;
  4366.   r : BOOLEAN;
  4367. BEGIN  
  4368.   ds := NIL;
  4369.   IF fh = NIL THEN fh := d.Output(); END;
  4370.   IF format = NIL THEN RETURN FALSE; END;
  4371.   r := VDynFmtLocale (ds, locale, format^, args);
  4372.   IF r THEN
  4373.     IF d.FPrintf (fh, "%s", StrIndex (ds^, 0)) # DynStrLen (ds) THEN r := FALSE; END;
  4374.   END;  
  4375.   DISPOSE (ds);
  4376.   RETURN r;
  4377. END FLPrintfInternal1;  
  4378.  
  4379. PROCEDURE VFLPrintf * (fh      : d.FileHandlePtr;
  4380.                        locale  : loc.LocalePtr;
  4381.                        format  : ARRAY OF CHAR;
  4382.                        args    : e.APTR          ): BOOLEAN;
  4383. (* $CopyArrays- *)
  4384. BEGIN
  4385.   RETURN FLPrintfInternal1 (fh, locale, y.ADR (format[0]), args);
  4386. END VFLPrintf;
  4387.  
  4388.   
  4389. (****** BlackMagic/SimpleRequest **********************************************
  4390. *
  4391. *   NAME
  4392. *       SimpleRequest ╣ -- Easy altern. to Intuition.EasyRequest() (varargs)
  4393. *       SimpleRequestArgs -- Easy alternative to Intuition.EasyRequestArgs()
  4394. *
  4395. *   SYNOPSIS
  4396. *       BlackMagicVA.SimpleRequest (win    : Intuition.WindowPtr;
  4397. *                                   flags  : LONGSET;
  4398. *                                   title  : ARRAY OF CHAR;
  4399. *                                   txtfmt : ARRAY OF CHAR;
  4400. *                                   gadfmt : ARRAY OF CHAR;
  4401. *                                   args.. : Exec.APTR           ): LONGINT;
  4402. *                                       
  4403. *       SimpleRequestArgs (win    : Intuition.WindowPtr;
  4404. *                          flags  : LONGSET;
  4405. *                          title  : ARRAY OF CHAR;
  4406. *                          txtfmt : ARRAY OF CHAR;
  4407. *                          gadfmt : ARRAY OF CHAR;
  4408. *                          args   : Exec.APTR           ): LONGINT;
  4409. *                                       
  4410. *   FUNCTION
  4411. *       Simplifies invokation of Intuition.EasyRequestArgs() to the
  4412. *       Oberon user. You may specify most of Intuition.EasyRequestArgs()'
  4413. *       possible parameters (window, easyStruct.title, easyStruct.txtfmt,
  4414. *       easyStruct.gadfmt and args (as varargs for SimpleRequest() or as
  4415. *       vector args for SimpleRequestArgs()). Furthermore, the possibility
  4416. *       of automatically locking the parent window is available.
  4417. *       
  4418. *   INPUTS
  4419. *       win      - the requester's 'parent window.' Corresponds to
  4420. *                  EasyRequestArgs()' window parameter.
  4421. *       flags    - currently two flags are defined for this parameter:
  4422. *                  - lockWindow: if you specify it, and you pass a 
  4423. *                    non-NIL win parameter, that window is locked and
  4424. *                    set to busy state while the requester is displayed.
  4425. *                  - ignoreTitle: if this flag is set, the title parameter
  4426. *                    is ignored, behaviour is the same as described for
  4427. *                    a NIL-title parameter.
  4428. *       title    - the title text for the requester. For the functions
  4429. *                  exported from BlackMagicVA, this parameter may be NIL
  4430. *                  in which case the parent window's title is used, or
  4431. *                  if no parent window is supplied, the system's default
  4432. *                  title. Corresponds to EasyRequestArgs()'
  4433. *                  easyStruct.title parameter.
  4434. *       txtfmt   - the sprintf()-like text format string. Corresponds to
  4435. *                  EasyRequestArgs()' easyStruct.textFormat parameter.
  4436. *       gadfmt   - the sprintf()-like gadgets format string. Corresponds
  4437. *                  to EasyRequestArgs()' easyStruct.gadgetFormat parameter.
  4438. *                  The '|' character is used as the gadget separator
  4439. *                  character.
  4440. *       args     - the arguments for the txtfmt and gadfmt formatting
  4441. *                  directives. Corresponds to EasyRequestArgs()' parameter
  4442. *                  of the same name. Either as varargs for SimpleRequest()
  4443. *                  or as vector args for SimpleRequestArgs().
  4444. *       
  4445. *   RESULT
  4446. *       0 for the rightmost gadget, otherwise the triggered gadget's
  4447. *       ordinal number from the left, starting at one.
  4448. *
  4449. *   NOTES
  4450. *       ╣) The functions with var args parameters are placed in the
  4451. *       BlackMagicVA module! The other functions are exported by both,
  4452. *       BlackMagic and BlackMagicVA.
  4453. *
  4454. *   SEE ALSO
  4455. *       Intuition/EasyRequestArgs()
  4456. *
  4457. *****************************************************************************)
  4458.  
  4459. CONST
  4460.   lockWindow * = 0;
  4461.   ignoreTitle * = 1;
  4462.  
  4463.   simpleEasyStruct = I.EasyStruct (
  4464.     SIZE (I.EasyStruct), LONGSET{}, 
  4465.     NIL, NIL, NIL);
  4466.  
  4467. PROCEDURE SimpleRequestInternal1 (win   : I.WindowPtr;
  4468.                                   flags : LONGSET;
  4469.                                   title : e.APTR;
  4470.                                   txtfmt: e.APTR;
  4471.                                   gadfmt: e.APTR;
  4472.                                   args  : e.APTR      ): LONGINT;
  4473. VAR
  4474.   es: I.EasyStruct;                                  
  4475.   r : LONGINT;
  4476.   wl: WinLockPtr;
  4477. BEGIN                                  
  4478.   wl := NIL;
  4479.   IF ignoreTitle IN flags THEN title := NIL; END;
  4480.   es := simpleEasyStruct;
  4481.   es.textFormat := txtfmt;
  4482.   es.gadgetFormat := gadfmt;
  4483.   es.title := title;
  4484.   IF lockWindow IN flags THEN wl := LockWindow (win, wl); END;
  4485.   r := I.EasyRequestArgs (win, y.ADR (es), NIL, args);
  4486.   UnlockWindow (wl);
  4487.   RETURN r;
  4488. END SimpleRequestInternal1;
  4489.  
  4490. PROCEDURE SimpleRequestArgs * (win    : I.WindowPtr;
  4491.                                flags  : LONGSET;
  4492.                                 title : ARRAY OF CHAR;
  4493.                                 txtfmt: ARRAY OF CHAR;
  4494.                                 gadfmt: ARRAY OF CHAR;
  4495.                                 args  : e.APTR        ): LONGINT;
  4496. (* $CopyArrays- *)                                
  4497. BEGIN
  4498.   RETURN SimpleRequestInternal1 (win, flags, y.ADR (title[0]), 
  4499.                                  y.ADR (txtfmt[0]), y.ADR (gadfmt[0]), args);
  4500. END SimpleRequestArgs;                                 
  4501.  
  4502.   
  4503. (****** BlackMagic/GetTTYScreen ***********************************************
  4504. *
  4505. *   NAME
  4506. *       GetTTYScreen -- returns the screen of a console's window
  4507. *
  4508. *   SYNOPSIS
  4509. *       GetTTYScreen (tty: Dos.FileHandlePtr): Intuition.ScreenPtr;
  4510. *                                       
  4511. *   FUNCTION
  4512. *       GetTTYScreen returns a valid Intuition.ScreenPtr to the
  4513. *       screen, the passed console has a window opened on. The ScreenPtr
  4514. *       is guaranteed to be valid on the machine this function is invoked
  4515. *       from. If the passed FileHandle does not refer to a console with a
  4516. *       screen on the invoking machine, NIL is returned.
  4517. *       
  4518. *   INPUTS
  4519. *       tty      - A valid FileHandle, may be NIL.
  4520. *       
  4521. *   RESULT
  4522. *       A valid Intuition.ScreenPtr of fhe invoking machine or NIL.
  4523. *
  4524. *****************************************************************************)
  4525.  
  4526. PROCEDURE GetTTYScreen * (tty: d.FileHandlePtr): I.ScreenPtr;
  4527. VAR
  4528.   pr : e.MsgPortPtr;
  4529.   w  : I.WindowPtr;
  4530.   id : d.InfoDataPtr;
  4531. BEGIN  
  4532.   w := NIL;
  4533.   IF tty = NIL THEN RETURN NIL; END;
  4534.   IF ~d.IsInteractive (tty) THEN RETURN NIL; END;  
  4535.   pr := tty.type;
  4536.   IF PtrToInt (pr) <= 0 THEN RETURN NIL; END;
  4537.   id := e.AllocVec (SIZE (id^), LONGSET {e.memClear, e.public}); 
  4538.   IF id = NIL THEN RETURN NIL; END;
  4539.   IF d.DoPkt1 (pr, d.diskInfo, BPtrVal (id)) = d.DOSTRUE THEN 
  4540.     w := y.VAL (I.WindowPtr, id.volumeNode);
  4541.   END;  
  4542.   e.FreeVec (id);
  4543.   IF w # NIL THEN RETURN w.wScreen; END;
  4544.   RETURN NIL;
  4545. END GetTTYScreen;  
  4546.  
  4547. (****** BlackMagic/SetDynamicExtra ********************************************
  4548. *
  4549. *   NAME
  4550. *       SetDynamicExtra -- set BlackMagic's DynamicExtra var
  4551. *
  4552. *   SYNOPSIS
  4553. *       SetDynamicExtra (extra: LONGINT);
  4554. *                                       
  4555. *   FUNCTION
  4556. *       This functions allows you to set BlackMagic's DynamicExtra (which is
  4557. *       exported for reading). DynamicExtra specifies the extra 'units'
  4558. *       BlackMagic should allocate whenever (re-)allocating Dynamic Strings
  4559. *       or Dynamic ToolType arrays. The default for DynamicExtra is currently
  4560. *       sixty-four. However, this may well change in the future.
  4561. *       
  4562. *   INPUTS
  4563. *       extra    - the new DynamicExtra value. Negative values are ignored.
  4564. *       
  4565. *   RESULT
  4566. *       DynamicExtra will hold the specified positive (>= 0) extra value.
  4567. *
  4568. *   SEE ALSO
  4569. *       DynAppend(), DynAppendTT()
  4570. *
  4571. *****************************************************************************)
  4572.  
  4573. PROCEDURE SetDynamicExtra * (extra: LONGINT);
  4574. BEGIN
  4575.   IF extra >= 0 THEN DynamicExtra := extra; END;
  4576. END SetDynamicExtra;
  4577.  
  4578.                                         
  4579. (****** BlackMagic/MemReqs ****************************************************
  4580. *
  4581. *   NOTES
  4582. *       In this module's startup code, the OberonLib.MemReqs variable is
  4583. *       ensured to include the flags Exec.memClear _and_ Exec.public. This
  4584. *       effect is documented, so you can use NEW(), SYSTEM.ALLOCATE(),
  4585. *       OberonLib.New() and OberonLib.Allocate() for allocating all system
  4586. *       structures (only with _untraced_ pointers, of course) unless they are
  4587. *       in use beyond your program's termination. Note that it is of vital
  4588. *       importance for future compatability and things like virtual memory
  4589. *       management to have the Exec.public flag set when allocating several
  4590. *       system structures like MsgPorts, etc. In the current OberonLib
  4591. *       startup, the Exec.public flag is not set in OberonLib.MemReqs.
  4592. *       However, if you allocate vast amounts of data records that are
  4593. *       private to your application, it is recommended to clear the
  4594. *       Exec.public flag for these allocations with 
  4595. *       'EXCL (OberonLib.MemReqs, Exec.public);' because otherwise possible
  4596. *       virtual memory ressources would be disabled from being used by your
  4597. *       program. 'Manual' inclusion of Exec.public can be achieved by 
  4598. *       'INCL (OberonLib.MemReqs, Exec.public);'
  4599. *
  4600. *       Finally, it must be stated, that you can only be sure that the 
  4601. *       Exec.memClear & Exec.public flags are set in OberonLib.MemReqs if
  4602. *       you don't import modules that clear these flags in their startup
  4603. *       code (Usually, decent modules don't do things like that!).
  4604. *       
  4605. *   SEE ALSO
  4606. *       Exec/AllocMem()
  4607. *
  4608. *****************************************************************************)
  4609.  
  4610. BEGIN
  4611.   DynamicExtra := defaultDynamicExtra;
  4612.   o.MemReqs := o.MemReqs + LONGSET{e.public,e.memClear};
  4613.   UnderScore := '_';
  4614.   req := e.OpenLibrary ("reqtools.library", 38);
  4615.  
  4616. CLOSE
  4617.   IF req # NIL THEN e.CloseLibrary (req); req := NIL; END;
  4618.   IF loc.base # NIL THEN IF DefaultCatalog # NIL THEN 
  4619.     loc.CloseCatalog (DefaultCatalog); DefaultCatalog := NIL;
  4620.   END; END;  
  4621.   IF waitPointer # NIL THEN e.FreeVec (waitPointer); waitPointer := NIL; END;
  4622. END BlackMagic.
  4623.  
  4624.