home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / EFFO / pd3.lzh / SBPROLOG2.2 / MODLIB / MODLIB_SRC / $db.P < prev    next >
Text File  |  1991-08-10  |  16KB  |  423 lines

  1. /************************************************************************
  2. *                                    *
  3. *    The SB-Prolog System                        *
  4. *    Copyright SUNY at Stony Brook, 1986                *
  5. *                                    *
  6. ************************************************************************/
  7.  
  8. /*-----------------------------------------------------------------
  9. SB-Prolog is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY.  No author or distributor
  11. accepts responsibility to anyone for the consequences of using it
  12. or for whether it serves any particular purpose or works at all,
  13. unless he says so in writing.  Refer to the SB-Prolog General Public
  14. License for full details.
  15.  
  16. Everyone is granted permission to copy, modify and redistribute
  17. SB-Prolog, but only under the conditions described in the
  18. SB-Prolog General Public License.   A copy of this license is
  19. supposed to have been given to you along with SB-Prolog so you
  20. can know your rights and responsibilities.  It should be in a
  21. file named COPYING.  Among other things, the copyright notice
  22. and this notice must be preserved on all copies. 
  23. ------------------------------------------------------------------ */
  24.  
  25.  
  26. /*
  27. These are the basic routines that support assert and retract in our system.
  28.  
  29. The system supports a concept of a Prref, a predicate reference.
  30. A Prref is a database reference to a sequence of asserted clauses.
  31. Normally a Prref is associated with a psc-entry (in the e.p.  field),
  32. the psc entry of the main functor symbol of all the clauses.  But that
  33. need not be the case. A Prref can be created, asserted to, and
  34. called explicitly. 
  35.  
  36. The system also supports a concept of Clref, a clause reference.
  37. These are quite similar to the db references in CProlog.  A Clref is
  38. a reference to a single clause.  A Clref can also be called.
  39. Normally a Clref is chained into a Prref.  
  40. */
  41.  
  42. $db_export([$db_new_prref/1,$db_assert_fact/5,$db_assert_fact/6,
  43.     $db_assert_fact/7, $db_assert_fact/8, $db_add_clref/6,
  44.     $db_call_prref/2,$db_call_prref_s/2,$db_call_prref_s/3,
  45.     $db_call_clref/2,$db_get_clauses/3,$db_kill_clause/1]).
  46.  
  47. $db_use($dbcmpl,[$db_cmpl/5,$db_cmpl/6,$db_putbuffop/4,$db_putbuffbyte/4,
  48.     $db_putbuffnum/4]).
  49.  
  50. $db_use($buff,
  51.     [$alloc_perm/2,$alloc_heap/2,$trimbuff/3,$buff_code/4,$symtype/2,
  52.         $substring/6,$subnumber/6,$subdelim/6,$conlength/2,
  53.         $pred_undefined/1, $hashval/3]).
  54.  
  55. $db_use($bmeta,[$atom/1,$atomic/1,$integer/1,$number/1,$structure/1,
  56.     $functor0/2,$bldstr/3,$arg/3,$arity/2,$real/1,$floor/2]).
  57.  
  58.  
  59. $db_use($bio,[$writename/1,$writeqname/1,$put/1,$nl/0,$tab/1,
  60.     $tell/1,$tell/2,$telling/1,$told/0,$get/1,$get0/1,$see/1,$seeing/1,
  61.     $seen/0]).
  62.  
  63.  
  64. /* $db_new_prref(Prref):  creates an empty Prref, i.e.  one with no
  65. clauses in it.  If called, it will simply fail.  Prref must be a
  66. variable at the time of call.  */
  67.  
  68. $db_new_prref(Prref) :- $db_new_prref(Prref,0,0).
  69. $db_new_prref(Prref,Where,Supbuff) :-
  70.     $alloc_buff(16,Prref,Where,Supbuff,0),
  71.         /* disp 12 for pointer to last clause */
  72.     $buff_code(Prref,0,14 /*ptv*/ ,Prref), /*set back pointer*/
  73.     $buff_code(Prref,4,3 /*pb*/ ,248 /* fail*/ ),
  74.     $buff_code(Prref,5,3 /*pb*/ ,0),
  75.     $buff_code(Prref,10,3 /*pb*/ ,248 /* fail*/ ),
  76.     $buff_code(Prref,11,3 /*pb*/ ,0).
  77.  
  78.  
  79.  
  80. /* $db_assert_fact(Fact,Prref,AZ,Index,Clref):  where Fact is a fact to
  81. be asserted; Prref is a predicate reference to which to add the
  82. asserted fact; AZ is either 0 indicating the fact should be inserted
  83. as the first clause in Prref, or 1 indicating it should be inserted
  84. as the last; Index is 0 if no index is to be built, or n if an index
  85. on the nth argument of the fact is to be used; Clref is returned and
  86. it is the clause reference of the asserted fact. */
  87.  
  88. $db_assert_fact(Fact,Prref,AZ,Index,Clref) :- 
  89.     $db_assert_fact(Fact,Prref,AZ,Index,Clref,1,0,0).
  90.  
  91. $db_assert_fact(Fact,Prref,AZ,Index,Clref,Where,Supbuff) :-
  92.     $db_assert_fact(Fact,Prref,AZ,Index,Clref,1,Where,Supbuff).
  93.  
  94. $db_assert_fact(Fact,Prref,AZ,Index,Clref,Flatten) :- 
  95.     $db_assert_fact(Fact,Prref,AZ,Index,Clref,Flatten,0,0).
  96.  
  97. $db_assert_fact(Clause,Prref,AZ,Index,Clref,Flatten,Where,Supbuff) :- 
  98.     $db_cmpl(Clause,Clref,Index,Where,Supbuff,Flatten),
  99.     (var(Prref) -> $db_new_prref(Prref,Where,Supbuff) ; true),
  100.     (Clause = (Head:-_) -> $arity(Head,Arity);
  101.             (Clause=Head,$arity(Head,Ar1),Arity is Ar1+1)
  102.     ),
  103.     $db_add_clref(Head,Arity,Prref,AZ,Index,Clref,Where,Supbuff).
  104.  
  105. /* $db_add_clref(Fact,Arity,Prref,AZ,Index,Clref) adds a clause buffer to a
  106. prref. So Prref and Clref must be bound. Arity is the number of registers
  107. to save in a choice point (if Fact is a fact, it is Arity(Fact)+1, for cut)
  108. The other parameters are as above.
  109. */
  110.  
  111. $db_add_clref(Fact,Arity,Prref,AZ,Index,Clref) :-
  112.     $db_add_clref(Fact,Arity,Prref,AZ,Index,Clref,0,0).
  113. $db_add_clref(Fact,Arity,Prref,AZ,Index,Clref,Where,Supbuff) :-
  114.     Index =< 0 ->
  115.       (AZ =:= 0 ->
  116.         $db_addbuffa(Arity,Clref,Prref);
  117.         $db_addbuffz(Arity,Clref,Prref));
  118.       (AZ =:= 0 -> 
  119.         $writename('Indexed add to beginning not supported'),$nl,fail
  120.        ;
  121.         $arg(Index, Fact, Arg),
  122.         (var(Arg) -> 
  123.            $db_addbuffz(Arity,Clref,Prref)
  124.            ;
  125.            $db_addbuffz_i(Arity,Clref,Prref,Index,Arg,Where,Supbuff)
  126.         )
  127.       ).
  128.  
  129. /* Add Clref to empty Prref */
  130. $db_addbuffonly(Arity,Clref,Prref) :-
  131.      $buff_code(Prref,4,3 /*pb*/ ,170 /*jump and save breg */ ),
  132.      $buff_code(Prref,5,3 /*pb*/ ,Arity),
  133.      $buff_code(Prref,6,10 /*pbr*/ ,Clref),
  134.      $buff_code(Prref,12,10 /*pbr*/ ,Clref), /* ptr to last clause */
  135.      $buff_code(Clref,4,3 /*pb*/ ,249 /*noop*/ ),
  136.      $buff_code(Clref,5,3 /*pb*/ ,2).
  137.  
  138. /* add Clref to end of Prref */
  139. $db_addbuffz(Arity,Clref,Prref) :-
  140.         /* Prref must be dummy header */
  141.     $buff_code(Prref,4,6 /*gb*/ ,Op),
  142.     (Op =:= 248,    /*fail*/
  143.      $db_addbuffonly(Arity,Clref,Prref)
  144.     ;
  145.      Op =\= 248,
  146.       (Op =:= 170,    /* must be a jump-and-save-breg to next clause */
  147.        $buff_code(Prref,12,8 /*gpb*/ ,Lbuff), /* last buff */
  148.        $buff_code(Lbuff,4,6 /*gb*/ ,Sop),
  149.        (Sop =:= 249, /* noop, change to try */
  150.         $buff_code(Lbuff,4,3 /*pb*/ ,160 /*trymeelse*/)
  151.        ;
  152.         Sop =\= 249,
  153.         Sop =:= 162,        /* must be a trustmeelsefail */
  154.         $buff_code(Lbuff,4,3 /*pb*/ ,161 /*retrymeelse*/)
  155.        ),
  156.        $buff_code(Lbuff,5,3 /*pb*/ ,Arity),
  157.        $buff_code(Lbuff,6,10 /*pbr*/ ,Clref),
  158.        $buff_code(Clref,4,3 /*pb*/ ,162 /*trustmeelsefail*/ ),
  159.        $buff_code(Clref,5,3 /*pb*/ ,Arity),
  160.        $buff_code(Clref,6,3 /*pb*/ ,249 /*noop*/ ),
  161.        $buff_code(Clref,7,3 /*pb*/ ,1),
  162.        $buff_code(Prref,12,10 /*pbr*/ ,Clref) /* point to new last */
  163.       )
  164.     ).
  165.  
  166.  
  167. /* add a buffer to the beginning of the chain */
  168. $db_addbuffa(Arity,Clref,Prref) :-
  169.     $buff_code(Prref,4,6 /*gb*/ ,Op),
  170.     (Op =:= 248,                /* fail */
  171.         /* only dummy clause there */
  172.      $db_addbuffonly(Arity,Clref,Prref)
  173.     ;
  174.      Op =\= 248,
  175.       (Op =:= 170,    /* must be a jump-and-save-breg, otw fail */
  176.        $buff_code(Prref,6,8 /*gpb*/ ,Sbuff), /* next buff */
  177.        $buff_code(Sbuff,4,6 /*gb*/ ,Sop),
  178.        (Sop =:= 249, /* noop, change to trust */
  179.         $buff_code(Sbuff,4,3 /*pb*/ ,162),
  180.         $buff_code(Sbuff,5,3 /*pb*/ ,Arity),
  181.         $buff_code(Sbuff,6,3 /*pb*/ ,249 /*noop*/ ),
  182.         $buff_code(Sbuff,7,3 /*pb*/ ,1)
  183.        ;
  184.         Sop =\= 249, /* not noop */
  185.         Sop =:= 160, /* must be try, else fail */
  186.         $buff_code(Sbuff,4,3 /*pb*/ ,161) /* make retry */
  187.        ),
  188.        $buff_code(Prref,6,10 /*pbr*/ , Clref), /* point first to new */
  189.        $buff_code(Clref,4,3 /*pb*/ ,160 /*trymeelse*/), 
  190.        $buff_code(Clref,5,3 /*pb*/ ,Arity),
  191.        $buff_code(Clref,6,10 /*pbr*/ , Sbuff) /* point new to old 2nd*/
  192.      )
  193.     ).
  194.  
  195. /* adds a buffer to an index chain */
  196. $db_addbuffz_i(Arity,Clref,Prref,Index,Arg,_,_) :-
  197.     $buff_code(Prref,4,6 /*gb*/ ,Op),Op =\= 248, /* fail if no clrefs */
  198.     $buff_code(Prref, 12,8 /*gpb*/ ,Lbuff), /* last buff */
  199.     $buff_code(Lbuff,10,6 /*gb*/ ,249),    /* noop if SOB */
  200.     $buff_code(Lbuff,16,6 /*gb*/ ,179),    /* op code must be sob */
  201.     $buff_code(Lbuff,17,6,Index),        /* must be same arg */
  202.     !,
  203.     $buff_code(Lbuff,22,5 /*gn*/, N), /* tabsize */
  204.     $db_proc_all_chain(Arity,Lbuff,Clref),
  205.     $db_proc_hash_chain(Arg,Arity,Lbuff,Clref,N).
  206.  
  207. $db_addbuffz_i(Arity,Clref,Prref,Index,Arg,Where,Supbuff) :-
  208.          /* must add new sop buffer */
  209.     $db_create_sob(Sbuff,N,Where,Supbuff), /* get sob buffer */
  210.     $db_gen_sobcode(Index, Sbuff, Clref, N),
  211.     $db_proc_hash_chain(Arg, Arity, Sbuff, Clref, N),
  212.     $db_addbuffz(Arity,Sbuff,Prref).
  213.  
  214. $db_create_sob(Sbuff,N,Where,Supbuff) :-
  215.     '_$tab_size'(N), Size is 10 + 6 + 10 + 6 + 4 * N + 4,
  216.     $alloc_buff(Size,Sbuff,Where,Supbuff,0),
  217.     $buff_code(Sbuff, 0, 14 /*ptv*/, Sbuff). /* backptr */
  218.  
  219. $db_gen_sobcode(Narg, Sbuff, Clref, N) :-
  220.         $buff_code(Sbuff, 10, 3, 249 /*noop*/),
  221.         $buff_code(Sbuff, 11, 3, 2),
  222.     $buff_code(Sbuff, 12, 10 /*pbr*/ ,Clref),
  223.         $buff_code(Sbuff, 16, 3, 179 /*switchonbound*/),
  224.         $buff_code(Sbuff, 17, 3, Narg),
  225.         $buff_code(Sbuff, 32, 4, AddrTab), /* get addr of tab */
  226.         $buff_code(Sbuff, 18, 2, AddrTab), /* store addr of tab */
  227.         $buff_code(Sbuff, 22, 2, N /* size of hashtab */),
  228.         $buff_code(Sbuff, 26, 3, 240 /* jump */),
  229.         $buff_code(Sbuff, 27, 3, 0),
  230.         $buff_code(Sbuff, 28, 10, Clref),
  231.         $buff_code(Clref, 4, 3 /*pb*/, 249 /*noop*/),
  232.         $buff_code(Clref, 5, 3 /*pb*/, 2),
  233.         $db_init_tab(Sbuff, N).
  234.  
  235. $db_init_tab(Clref, N) :-
  236.         Disp is 32 + 4 * N, 
  237.         $buff_code(Clref, Disp, 3, 248 /*fail*/),
  238.         Disp1 is Disp + 1,
  239.         $buff_code(Clref, Disp1, 3, 0),
  240.         $buff_code(Clref, Disp, 4, FailAddr),
  241.         $db_init_hashtab(0, 32, N, Clref, FailAddr).
  242.  
  243. $db_init_hashtab(N, Lin, Size, Clref, FailAddr) :-
  244.         N >= Size;
  245.         N < Size,
  246.         $buff_code(Clref, Lin, 2 /* word num */, FailAddr),
  247.         Lout is Lin + 4,
  248.         N1 is N + 1,
  249.         $db_init_hashtab(N1, Lout, Size, Clref, FailAddr).
  250.  
  251. $db_proc_all_chain(Arity, Sbuff, Clref) :-
  252.         $buff_code(Sbuff, 12, 8, Lbuff), /* last buff on all chain */
  253.     $buff_code(Lbuff,4,6 /*gb*/ ,Sop),
  254.     (Sop =:= 249, /* noop, change to try */
  255.      $buff_code(Lbuff,4,3 /*pb*/ ,160 /*trymeelse*/)
  256.     ;
  257.      Sop =\= 249,
  258.      Sop =:= 162,        /* must be a trustmeelsefail */
  259.      $buff_code(Lbuff,4,3 /*pb*/ ,161 /*retrymeelse*/)
  260.     ),
  261.     $buff_code(Lbuff,5,3 /*pb*/ ,Arity),
  262.     $buff_code(Lbuff,6,10 /*pbr*/ ,Clref),
  263.     $buff_code(Clref,4,3 /*pb*/ ,162 /*trustmeelsefail*/ ),
  264.     $buff_code(Clref,5,3 /*pb*/ ,Arity),
  265.      $buff_code(Clref,6,3 /*pb*/ ,249 /*noop*/ ),
  266.     $buff_code(Clref,7,3 /*pb*/ ,1), 
  267.     $buff_code(Sbuff,12,10 /*pbr*/ ,Clref). /* point to new last */
  268.  
  269. $db_proc_hash_chain(Arg, Arity, Tbuff, Buff, N) :-
  270.         nonvar(Arg), 
  271.         $hashval(Arg, N, Hashval),
  272.         Bucket is 32 + 4 * Hashval,
  273.         $buff_code(Tbuff, Bucket, 5, Addr),
  274.         Faild is 32 + 4 * N,
  275.         $buff_code(Tbuff, Faild, 4, Faddr),
  276.         ((Addr = Faddr, $db_link_first(Bucket, Tbuff, Buff), !);
  277.          ($db_get_hash_next(Bucket, Tbuff, NextBuff, Disp, B),
  278.           $db_link_all(Arity, NextBuff, Disp, Buff, B))
  279.         ).
  280.  
  281. $db_link_first(Bucket, Tbuff, Buff) :-
  282.         $db_get_addr(Buff, _, Hash_addr),
  283.         $buff_code(Tbuff, Bucket, 2, Hash_addr).
  284.  
  285.  
  286. $db_get_addr(Buff, Disp, Hash_addr) :-
  287.         $conlength(Buff, Len),
  288.         Disp is Len - 12,
  289.         $buff_code(Buff, Disp, 4, Hash_addr).
  290.  
  291. $db_get_hash_next(Bucket, Tbuff, NextBuff, Disp, B) :-
  292.         /* get buffer pointed to by the bucket        */
  293.         $buff_code(Tbuff, Bucket, 21 /* gnb */, NextBuff), 
  294.         $conlength(NextBuff, Len),
  295.         Disp is Len - 12,
  296.         $buff_code(NextBuff, Disp, 6, B).
  297.  
  298. $db_link_all(Arity, NextBuff, Disp, Buff, B) :-
  299.         ((B =:= 249, /* noop */
  300.           $db_putbuffop(160 /* trymeelse */, NextBuff, Disp, L1),
  301.           $db_putbuffbyte(Arity, NextBuff, L1, L2),
  302.           $db_get_addr(Buff, BuffDisp, Hash_addr),
  303.           $db_putbuffnum(Hash_addr, NextBuff, L2, _),
  304.           $db_set_index_trust(Arity, Buff, BuffDisp));
  305.          (B =\= 249, B =:= 160, /* trymeelse */
  306.           Loc is Disp + 2,
  307.           $db_get_hash_next(Loc, NextBuff, Clref, NewDisp, NewB),
  308.           $db_link_rest(Arity, Clref, NewDisp, Buff, NewB))
  309.         ).
  310.  
  311. $db_link_rest(Arity, NextBuff, Disp, Buff, B) :-
  312.         ((B =:= 161, /* retrymeelse */
  313.           Loc is Disp + 2,
  314.           $db_get_hash_next(Loc, NextBuff, Clref, NewDisp, NewB),
  315.           $db_link_rest(Arity, Clref, NewDisp, Buff, NewB));
  316.          (B =\= 161, B =:= 162, /* trustmeelsefail */
  317.           $db_get_addr(Buff, BDisp, Hash_addr),
  318.           $db_set_index_retry(Arity, NextBuff, Disp, Hash_addr),
  319.           $db_set_index_trust(Arity, Buff, BDisp))
  320.         ).
  321.  
  322. $db_set_index_trust(Arity, Buff, Disp) :-
  323.         $db_putbuffop(162, Buff, Disp, L1),
  324.         $db_putbuffbyte(Arity, Buff, L1, L2),
  325.         $db_putbuffop(249, Buff, L2, L3),
  326.         $db_putbuffbyte(1, Buff, L3, _).
  327.  
  328. $db_set_index_retry(Arity, Buff, Disp, Addr) :-
  329.         $db_putbuffop(161, Buff, Disp, L1),
  330.         $db_putbuffbyte(Arity, Buff, L1, L2),
  331.         $db_putbuffnum(Addr, Buff, L2, _).
  332.  
  333.  
  334. /* $db_call_prref(Call,Prref):  where Call is a literal and Prref is a
  335. predicate reference.  This calls the Prref using Call as the call.
  336. The call is done by simply branching to the first clause.  Thus the
  337. trust optimization is used, and so new facts added to the Prref after
  338. the last fact is retrieved but before the call is failed through will
  339. NOT be used. */
  340.  
  341. $db_call_prref(Call,Prref) :- $buff_code(Prref,4,13 /*execb*/ ,Call).
  342.  
  343.  
  344. /* $db_call_prref_s(Call,Prref):  with the same arguments as the
  345. previous and also calling the clauses.  The difference from 
  346. $db_call_prref is that it does not use the trust optimization so that any
  347. new fact addd before final failure will be used.  */
  348.  
  349. $db_call_prref_s(Goal,Prref) :- $db_call_prref_s(Goal,Prref,_).
  350.  
  351. /* same as above, but also returns cl_ref of successful clause */
  352. $db_call_prref_s(Goal,Prref,Cur_clref) :-
  353.     $db_get_first_clref(Prref,Clref),$db_get_clrefs(Clref,Cur_clref,0),
  354.     $db_call_clref(Goal,Cur_clref).
  355.  
  356.  
  357. /* $db_call_clref(Call,Clref): will call the clause referenced by Clref
  358. using the literal Call as the call. */
  359.  
  360. $db_call_clref(Call,Clref) :- $buff_code(Clref,10,13 /*execb*/ ,Call).
  361.  
  362.  
  363. /* $db_get_clauses(Prref,Clref,Dir): This returns nondeterministically all
  364. the clause references for clauses asserted to Prref. If Dir is 0, then
  365. the first on the list is returned first; if Dir is 1, then they are 
  366. returned in reverse order.
  367. */
  368.  
  369. $db_get_clauses(Prref,Clref,Dir) :- 
  370.     $db_get_first_clref(Prref,Fclref),
  371.     $db_get_clrefs(Fclref,Clref,Dir).
  372.  
  373.  
  374. /* given a pr_ref, get the cl_ref for the first clause. */
  375. $db_get_first_clref(Prref,Clref) :- 
  376.     $buff_code(Prref,4,6 /*gb*/ ,170), /* must be jump-and-save-breg */
  377.     $buff_code(Prref,6,8 /*gpb*/ ,Clref).
  378.  
  379. /* return, through backtracking, the sequence of cl_refs chained from
  380. the given one, returning given one first */
  381.  
  382. $db_get_clrefs(Clref,N_clref,1) :- 
  383.     $db_get_next_clref(Clref,Nxt_clref),
  384.     $db_get_clrefs(Nxt_clref,N_clref,1).
  385.  
  386. $db_get_clrefs(Clref,N_clref,Dir) :-
  387.     $buff_code(Clref,10,6,Nop),         /* if sob, is noop */
  388.     (Nop =:= 249 ->
  389.       $buff_code(Clref,16,6 /*gb*/ ,Sop),    /* op code must be sob */
  390.       (Sop =:= 179 ->                /* sob buffer */
  391.         $buff_code(Clref,28,8 /*gpb*/ ,Tclref),    /* first of all */
  392.         $db_get_clrefs(Tclref,N_clref,Dir)    /* and recurse */
  393.         ;
  394.         N_clref=Clref            /* not a sob buffer */
  395.       )
  396.       ;
  397.       N_clref=Clref
  398.     ).
  399.  
  400. $db_get_clrefs(Clref,N_clref,0) :- 
  401.     $db_get_next_clref(Clref,Nxt_clref),
  402.     $db_get_clrefs(Nxt_clref,N_clref,0).
  403.  
  404. /* get the next cl_ref following the given one. */
  405. $db_get_next_clref(Clref,Nxt_clref) :-
  406.     $buff_code(Clref,4,6 /*gb*/ ,B), 
  407.     (B =:= 161, /* retrymeelse, so there is another clause */
  408.         $buff_code(Clref,6,8 /*gpb*/ ,Nxt_clref)
  409.      ;
  410.      B =\= 161,
  411.       B =:= 160, /* trymeelse, so ditto */
  412.       $buff_code(Clref,6,8 /*gpb*/ ,Nxt_clref)
  413.     ).
  414.  
  415.  
  416. /* $db_kill_clause(Clref):  retracts the fact referenced by Clref.  It
  417. does this by simply making the first instruction of the clause a
  418. fail instruction. */
  419.  
  420. $db_kill_clause(Clref) :- $buff_code(Clref,10,3 /*pb*/ ,248 /*fail*/ ).
  421.  
  422. /* ---------------------------------------------------------------------- */
  423.