/[dtapublic]/projs/ets/trunk/src/c_tclxtens_7_5/arblenints.c
ViewVC logotype

Diff of /projs/ets/trunk/src/c_tclxtens_7_5/arblenints.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

sf_code/esrgpcpj/shared/tclxtens/arblenints.c revision 25 by dashley, Sat Oct 8 06:43:03 2016 UTC projs/ets/trunk/src/c_tclxtens_7_5/arblenints.c revision 220 by dashley, Sun Jul 22 15:58:07 2018 UTC
# Line 1  Line 1 
1  /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tclxtens/arblenints.c,v 1.12 2001/08/18 09:47:00 dtashley Exp $ */  //$Header$
2    //-------------------------------------------------------------------------------------------------
3  //--------------------------------------------------------------------------------  //This file is part of "David T. Ashley's Shared Source Code", a set of shared components
4  //Copyright 2001 David T. Ashley  //integrated into many of David T. Ashley's projects.
5  //-------------------------------------------------------------------------------------------------  //-------------------------------------------------------------------------------------------------
6  //This source code and any program in which it is compiled/used is provided under the GNU GENERAL  //This source code and any program in which it is compiled/used is provided under the MIT License,
7  //PUBLIC LICENSE, Version 3, full license text below.  //reproduced below.
8  //-------------------------------------------------------------------------------------------------  //-------------------------------------------------------------------------------------------------
9  //                    GNU GENERAL PUBLIC LICENSE  //Permission is hereby granted, free of charge, to any person obtaining a copy of
10  //                       Version 3, 29 June 2007  //this software and associated documentation files(the "Software"), to deal in the
11  //  //Software without restriction, including without limitation the rights to use,
12  // Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>  //copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the
13  // Everyone is permitted to copy and distribute verbatim copies  //Software, and to permit persons to whom the Software is furnished to do so,
14  // of this license document, but changing it is not allowed.  //subject to the following conditions :
15  //  //
16  //                            Preamble  //The above copyright notice and this permission notice shall be included in all
17  //  //copies or substantial portions of the Software.
18  //  The GNU General Public License is a free, copyleft license for  //
19  //software and other kinds of works.  //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  //  //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  //  The licenses for most software and other practical works are designed  //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
22  //to take away your freedom to share and change the works.  By contrast,  //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  //the GNU General Public License is intended to guarantee your freedom to  //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  //share and change all versions of a program--to make sure it remains free  //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  //software for all its users.  We, the Free Software Foundation, use the  //SOFTWARE.
26  //GNU General Public License for most of our software; it applies also to  //-------------------------------------------------------------------------------------------------
27  //any other work released this way by its authors.  You can apply it to  #define MODULE_ARBLENINTS
28  //your programs, too.  
29  //  #include <assert.h>
30  //  When we speak of free software, we are referring to freedom, not  #include <string.h>
31  //price.  Our General Public Licenses are designed to make sure that you  
32  //have the freedom to distribute copies of free software (and charge for  #include "tcl.h"
33  //them if you wish), that you receive source code or can get it if you  #include "tcldecls.h"
34  //want it, that you can change the software or use pieces of it in new  
35  //free programs, and that you know you can do these things.  #include "arblenints.h"
36  //  #include "bstrfunc.h"
37  //  To protect your rights, we need to prevent others from denying you  #include "extninit.h"
38  //these rights or asking you to surrender the rights.  Therefore, you have  #include "gmp_ints.h"
39  //certain responsibilities if you distribute copies of the software, or if  #include "gmp_rats.h"
40  //you modify it: responsibilities to respect the freedom of others.  #include "gmp_ralg.h"
41  //  #include "intfunc.h"
42  //  For example, if you distribute copies of such a program, whether  #include "tclalloc.h"
43  //gratis or for a fee, you must pass on to the recipients the same  
44  //freedoms that you received.  You must make sure that they, too, receive  
45  //or can get the source code.  And you must show them these terms so they  //Handles the "cfbrapab" subextension.
46  //know their rights.  //08/16/01: Visual inspection OK.
47  //  static
48  //  Developers that use the GNU GPL protect your rights with two steps:  int ARBLENINTS_cfbrapab_handler(ClientData dummy,
49  //(1) assert copyright on the software, and (2) offer you this License                                  Tcl_Interp *interp,
50  //giving you legal permission to copy, distribute and/or modify it.                                  int objc,
51  //                                  Tcl_Obj *objv[])
52  //  For the developers' and authors' protection, the GPL clearly explains     {
53  //that there is no warranty for this free software.  For both users' and     Tcl_Obj *rv;
54  //authors' sake, the GPL requires that modified versions be marked as  
55  //changed, so that their problems will not be attributed erroneously to     //We must have at least two additional arguments
56  //authors of previous versions.     //to this extension.
57  //     if (objc < 4)
58  //  Some devices are designed to deny users access to install or run        {
59  //modified versions of the software inside them, although the manufacturer        Tcl_WrongNumArgs(interp,
60  //can do so.  This is fundamentally incompatible with the aim of                         2,
61  //protecting users' freedom to change the software.  The systematic                         objv,
62  //pattern of such abuse occurs in the area of products for individuals to                         "srn uint_kmax ?uint_hmax? ?options?");
63  //use, which is precisely where it is most unacceptable.  Therefore, we        return(TCL_ERROR);
64  //have designed this version of the GPL to prohibit the practice for those        }
65  //products.  If such problems arise substantially in other domains, we     else
66  //stand ready to extend this provision to those domains in future versions        {
67  //of the GPL, as needed to protect the freedom of users.        char *input_arg;
68  //        int failure, first_dashed_parameter;
69  //  Finally, every program is threatened constantly by software patents.        char *string_result;
70  //States should not allow patents to restrict development and use of        int string_result_n_allocd;
71  //software on general-purpose computers, but in those that do, we wish to        int chars_reqd;
72  //avoid the special danger that patents applied to a free program could        int i;
73  //make it effectively proprietary.  To prevent this, the GPL assures that        int pred_option_specified         = 0;
74  //patents cannot be used to render the program non-free.        int succ_option_specified         = 0;
75  //        int neversmaller_option_specified = 0;
76  //  The precise terms and conditions for copying, distribution and        int neverlarger_option_specified  = 0;
77  //modification follow.        int n_option_specified            = 0;
78  //        unsigned n                        = 0;
79  //                       TERMS AND CONDITIONS  
80  //        GMP_RATS_mpq_struct q_rn;
81  //  0. Definitions.        GMP_INTS_mpz_struct z_kmax;
82  //        GMP_INTS_mpz_struct z_hmax;
83  //  "This License" refers to version 3 of the GNU General Public License.  
84  //        //Allocate dynamic memory.
85  //  "Copyright" also means copyright-like laws that apply to other kinds of        GMP_RATS_mpq_init(&q_rn);
86  //works, such as semiconductor masks.        GMP_INTS_mpz_init(&z_kmax);
87  //        GMP_INTS_mpz_init(&z_hmax);
88  //  "The Program" refers to any copyrightable work licensed under this  
89  //License.  Each licensee is addressed as "you".  "Licensees" and        //Grab a pointer to the string representation of
90  //"recipients" may be individuals or organizations.        //the first input argument.  The storage does not belong to us.
91  //        input_arg = Tcl_GetString(objv[2]);
92  //  To "modify" a work means to copy from or adapt all or part of the work        assert(input_arg != NULL);
93  //in a fashion requiring copyright permission, other than the making of an  
94  //exact copy.  The resulting work is called a "modified version" of the        //Try to parse our first input string as a rational number.
95  //earlier work or a work "based on" the earlier work.        //If we are not successful in this, must abort.
96  //        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
97  //  A "covered work" means either the unmodified Program or a work based                                            &failure,
98  //on the Program.                                            &q_rn);
99  //  
100  //  To "propagate" a work means to do anything with it that, without        if (failure)
101  //permission, would make you directly or secondarily liable for           {
102  //infringement under applicable copyright law, except executing it on a           rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);
103  //computer or modifying a private copy.  Propagation includes copying,           Tcl_AppendToObj(rv, input_arg, -1);
104  //distribution (with or without modification), making available to the  
105  //public, and in some countries other activities as well.           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
106  //           Tcl_SetObjResult(interp, rv);
107  //  To "convey" a work means any kind of propagation that enables other  
108  //parties to make or receive copies.  Mere interaction with a user through           GMP_RATS_mpq_clear(&q_rn);
109  //a computer network, with no transfer of a copy, is not conveying.           GMP_INTS_mpz_clear(&z_kmax);
110  //           GMP_INTS_mpz_clear(&z_hmax);
111  //  An interactive user interface displays "Appropriate Legal Notices"  
112  //to the extent that it includes a convenient and prominently visible           return(TCL_ERROR);
113  //feature that (1) displays an appropriate copyright notice, and (2)           }
114  //tells the user that there is no warranty for the work (except to the  
115  //extent that warranties are provided), that licensees may convey the        //Try to parse our next argument as an integer, which
116  //work under this License, and how to view a copy of this License.  If        //will be KMAX.  This must be specified.
117  //the interface presents a list of user commands or options, such as a        //
118  //menu, a prominent item in the list meets this criterion.        //Get string pointer.  Storage does not belong to us.
119  //        input_arg = Tcl_GetString(objv[3]);
120  //  1. Source Code.        assert(input_arg != NULL);
121  //  
122  //  The "source code" for a work means the preferred form of the work        //Try to convert KMAX to an integer.  Fatal if an error,
123  //for making modifications to it.  "Object code" means any non-source        //and fatal if the argument is zero or negative.
124  //form of a work.        GMP_INTS_mpz_set_general_int(&z_kmax, &failure, input_arg);
125  //  
126  //  A "Standard Interface" means an interface that either is an official        //If there was a parse failure or if the integer is zero
127  //standard defined by a recognized standards body, or, in the case of        //or negative, must flag error.
128  //interfaces specified for a particular programming language, one that        if (failure || GMP_INTS_mpz_is_neg(&z_kmax) || GMP_INTS_mpz_is_zero(&z_kmax))
129  //is widely used among developers working in that language.           {
130  //           rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);
131  //  The "System Libraries" of an executable work include anything, other           Tcl_AppendToObj(rv, input_arg, -1);
132  //than the work as a whole, that (a) is included in the normal form of           Tcl_AppendToObj(rv, "\" is not a recognized positive integer.", -1);
133  //packaging a Major Component, but which is not part of that Major           Tcl_SetObjResult(interp, rv);
134  //Component, and (b) serves only to enable use of the work with that  
135  //Major Component, or to implement a Standard Interface for which an           GMP_RATS_mpq_clear(&q_rn);
136  //implementation is available to the public in source code form.  A           GMP_INTS_mpz_clear(&z_kmax);
137  //"Major Component", in this context, means a major essential component           GMP_INTS_mpz_clear(&z_hmax);
138  //(kernel, window system, and so on) of the specific operating system  
139  //(if any) on which the executable work runs, or a compiler used to           return(TCL_ERROR);
140  //produce the work, or an object code interpreter used to run it.           }
141  //  
142  //  The "Corresponding Source" for a work in object code form means all        //We need to look for HMAX as the next parameter, if it exists.
143  //the source code needed to generate, install, and (for an executable        //The way we will figure this out is by whether the
144  //work) run the object code and to modify the work, including scripts to        //parameter begins with a "-" or not.
145  //control those activities.  However, it does not include the work's        if (objc >= 5)
146  //System Libraries, or general-purpose tools or generally available free           {
147  //programs which are used unmodified in performing those activities but           input_arg = Tcl_GetString(objv[4]);
148  //which are not part of the work.  For example, Corresponding Source           assert(input_arg != NULL);
149  //includes interface definition files associated with source files for  
150  //the work, and the source code for shared libraries and dynamically           if (input_arg[0] == '-')
151  //linked subprograms that the work is specifically designed to require,              {
152  //such as by intimate data communication or control flow between those              first_dashed_parameter = 4;
153  //subprograms and other parts of the work.              }
154  //           else
155  //  The Corresponding Source need not include anything that users              {
156  //can regenerate automatically from other parts of the Corresponding              first_dashed_parameter = 5;
157  //Source.              }
158  //           }
159  //  The Corresponding Source for a work in source code form is that        else
160  //same work.           {
161  //           first_dashed_parameter = 4;
162  //  2. Basic Permissions.           }
163  //  
164  //  All rights granted under this License are granted for the term of        //If there is another parameter and it
165  //copyright on the Program, and are irrevocable provided the stated        //doesn't begin with a dash, try to parse
166  //conditions are met.  This License explicitly affirms your unlimited        //it as HMAX.  We don't explicitly record whether
167  //permission to run the unmodified Program.  The output from running a        //HMAX is specified, because zero is a signal
168  //covered work is covered by this License only if the output, given its        //when calculating Farey neighbors that HMAX isn't
169  //content, constitutes a covered work.  This License acknowledges your        //to be considered.
170  //rights of fair use or other equivalent, as provided by copyright law.        if ((objc >= 5) && (first_dashed_parameter == 5))
171  //           {
172  //  You may make, run and propagate covered works that you do not           //Get string pointer.  Storage does not belong to us.
173  //convey, without conditions so long as your license otherwise remains           input_arg = Tcl_GetString(objv[4]);
174  //in force.  You may convey covered works to others for the sole purpose           assert(input_arg != NULL);
175  //of having them make modifications exclusively for you, or provide you  
176  //with facilities for running those works, provided that you comply with           //Try to convert HMAX to an integer.  Fatal if an error,
177  //the terms of this License in conveying all material for which you do           //and fatal if the argument is zero or negative.
178  //not control copyright.  Those thus making or running the covered works           GMP_INTS_mpz_set_general_int(&z_hmax, &failure, input_arg);
179  //for you must do so exclusively on your behalf, under your direction  
180  //and control, on terms that prohibit them from making any copies of           //If there was a parse failure or if the integer is zero
181  //your copyrighted material outside their relationship with you.           //or negative, must flag error.
182  //           if (failure || GMP_INTS_mpz_is_neg(&z_hmax) || GMP_INTS_mpz_is_zero(&z_hmax))
183  //  Conveying under any other circumstances is permitted solely under              {
184  //the conditions stated below.  Sublicensing is not allowed; section 10              rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);
185  //makes it unnecessary.              Tcl_AppendToObj(rv, input_arg, -1);
186  //              Tcl_AppendToObj(rv, "\" is not a recognized positive integer.", -1);
187  //  3. Protecting Users' Legal Rights From Anti-Circumvention Law.              Tcl_SetObjResult(interp, rv);
188  //  
189  //  No covered work shall be deemed part of an effective technological              GMP_RATS_mpq_clear(&q_rn);
190  //measure under any applicable law fulfilling obligations under article              GMP_INTS_mpz_clear(&z_kmax);
191  //11 of the WIPO copyright treaty adopted on 20 December 1996, or              GMP_INTS_mpz_clear(&z_hmax);
192  //similar laws prohibiting or restricting circumvention of such  
193  //measures.              return(TCL_ERROR);
194  //              }
195  //  When you convey a covered work, you waive any legal power to forbid           }
196  //circumvention of technological measures to the extent such circumvention  
197  //is effected by exercising rights under this License with respect to        //Process all of the dashed command-line arguments.
198  //the covered work, and you disclaim any intention to limit operation or        //This involves iterating through all of the
199  //modification of the work as a means of enforcing, against the work's        //parameters and processing them.
200  //users, your or third parties' legal rights to forbid circumvention of        for (i=first_dashed_parameter; i<objc; i++)
201  //technological measures.           {
202  //           input_arg = Tcl_GetString(objv[i]);
203  //  4. Conveying Verbatim Copies.           assert(input_arg != NULL);
204  //  
205  //  You may convey verbatim copies of the Program's source code as you           if (!strcmp("-pred", input_arg))
206  //receive it, in any medium, provided that you conspicuously and              {
207  //appropriately publish on each copy an appropriate copyright notice;              pred_option_specified = 1;
208  //keep intact all notices stating that this License and any              }
209  //non-permissive terms added in accord with section 7 apply to the code;           else if (!strcmp("-succ", input_arg))
210  //keep intact all notices of the absence of any warranty; and give all              {
211  //recipients a copy of this License along with the Program.              succ_option_specified = 1;
212  //              }
213  //  You may charge any price or no price for each copy that you convey,           else if (!strcmp("-neversmaller", input_arg))
214  //and you may offer support or warranty protection for a fee.              {
215  //              neversmaller_option_specified = 1;
216  //  5. Conveying Modified Source Versions.              }
217  //           else if (!strcmp("-neverlarger", input_arg))
218  //  You may convey a work based on the Program, or the modifications to              {
219  //produce it from the Program, in the form of source code under the              neverlarger_option_specified = 1;
220  //terms of section 4, provided that you also meet all of these conditions:              }
221  //           else if (!strcmp("-n", input_arg))
222  //    a) The work must carry prominent notices stating that you modified              {
223  //    it, and giving a relevant date.              n_option_specified = 1;
224  //  
225  //    b) The work must carry prominent notices stating that it is              //If -n was specified, there must be a following
226  //    released under this License and any conditions added under section              //parameter which supplies the integer.  First
227  //    7.  This requirement modifies the requirement in section 4 to              //check for existence of an additional parameter.
228  //    "keep intact all notices".              if (i >= (objc - 1))
229  //                 {
230  //    c) You must license the entire work, as a whole, under this                 rv = Tcl_NewStringObj("arbint cfbrapab: -n option specified without following integer.", -1);
231  //    License to anyone who comes into possession of a copy.  This                 Tcl_SetObjResult(interp, rv);
232  //    License will therefore apply, along with any applicable section 7  
233  //    additional terms, to the whole of the work, and all its parts,                 GMP_RATS_mpq_clear(&q_rn);
234  //    regardless of how they are packaged.  This License gives no                 GMP_INTS_mpz_clear(&z_kmax);
235  //    permission to license the work in any other way, but it does not                 GMP_INTS_mpz_clear(&z_hmax);
236  //    invalidate such permission if you have separately received it.  
237  //                 return(TCL_ERROR);
238  //    d) If the work has interactive user interfaces, each must display                 }
239  //    Appropriate Legal Notices; however, if the Program has interactive  
240  //    interfaces that do not display Appropriate Legal Notices, your              //We have at least one additional parameter.  Try
241  //    work need not make them do so.              //to parse out the next parameter as the integer
242  //              //we need for n.
243  //  A compilation of a covered work with other separate and independent              i++;
244  //works, which are not by their nature extensions of the covered work,  
245  //and which are not combined with it such as to form a larger program,              input_arg = Tcl_GetString(objv[i]);
246  //in or on a volume of a storage or distribution medium, is called an              assert(input_arg != NULL);
247  //"aggregate" if the compilation and its resulting copyright are not  
248  //used to limit the access or legal rights of the compilation's users              GMP_INTS_mpz_parse_into_uint32(&n, &failure, input_arg);
249  //beyond what the individual works permit.  Inclusion of a covered work  
250  //in an aggregate does not cause this License to apply to the other              //If the parse was unsuccessful, terminate.
251  //parts of the aggregate.              if (failure)
252  //                 {
253  //  6. Conveying Non-Source Forms.                 rv = Tcl_NewStringObj("arbint cfbrapab: -n option followed by invalid integer.", -1);
254  //                 Tcl_SetObjResult(interp, rv);
255  //  You may convey a covered work in object code form under the terms  
256  //of sections 4 and 5, provided that you also convey the                 GMP_RATS_mpq_clear(&q_rn);
257  //machine-readable Corresponding Source under the terms of this License,                 GMP_INTS_mpz_clear(&z_kmax);
258  //in one of these ways:                 GMP_INTS_mpz_clear(&z_hmax);
259  //  
260  //    a) Convey the object code in, or embodied in, a physical product                 return(TCL_ERROR);
261  //    (including a physical distribution medium), accompanied by the                 }
262  //    Corresponding Source fixed on a durable physical medium  
263  //    customarily used for software interchange.              //Clip the integer into a 24-bit quantity.
264  //              n &= 0x00FFFFFF;
265  //    b) Convey the object code in, or embodied in, a physical product              }
266  //    (including a physical distribution medium), accompanied by a           else
267  //    written offer, valid for at least three years and valid for as              {
268  //    long as you offer spare parts or customer support for that product              //Unrecognized option.  Crash out.
269  //    model, to give anyone who possesses the object code either (1) a              rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);
270  //    copy of the Corresponding Source for all the software in the              Tcl_AppendToObj(rv, input_arg, -1);
271  //    product that is covered by this License, on a durable physical              Tcl_AppendToObj(rv, "\" is not a recognized option.", -1);
272  //    medium customarily used for software interchange, for a price no              Tcl_SetObjResult(interp, rv);
273  //    more than your reasonable cost of physically performing this  
274  //    conveying of source, or (2) access to copy the              GMP_RATS_mpq_clear(&q_rn);
275  //    Corresponding Source from a network server at no charge.              GMP_INTS_mpz_clear(&z_kmax);
276  //              GMP_INTS_mpz_clear(&z_hmax);
277  //    c) Convey individual copies of the object code with a copy of the  
278  //    written offer to provide the Corresponding Source.  This              return(TCL_ERROR);
279  //    alternative is allowed only occasionally and noncommercially, and              }
280  //    only if you received the object code with such an offer, in accord           }
281  //    with subsection 6b.  
282  //        //Look for any mutually exclusive options.  Give a catchall if any of
283  //    d) Convey the object code by offering access from a designated        //them specified.  Because we set them all to 1, addition is the easiest
284  //    place (gratis or for a charge), and offer equivalent access to the        //way to do this.
285  //    Corresponding Source in the same way through the same place at no        if ((pred_option_specified + succ_option_specified + neversmaller_option_specified
286  //    further charge.  You need not require recipients to copy the             + neverlarger_option_specified + n_option_specified) > 1)
287  //    Corresponding Source along with the object code.  If the place to           {
288  //    copy the object code is a network server, the Corresponding Source           rv = Tcl_NewStringObj("arbint cfbrapab: -pred, -succ, -neversmaller, -neverlarger, and -n are mutually exclusive options.", -1);
289  //    may be on a different server (operated by you or a third party)           Tcl_SetObjResult(interp, rv);
290  //    that supports equivalent copying facilities, provided you maintain  
291  //    clear directions next to the object code saying where to find the           GMP_RATS_mpq_clear(&q_rn);
292  //    Corresponding Source.  Regardless of what server hosts the           GMP_INTS_mpz_clear(&z_kmax);
293  //    Corresponding Source, you remain obligated to ensure that it is           GMP_INTS_mpz_clear(&z_hmax);
294  //    available for as long as needed to satisfy these requirements.  
295  //           return(TCL_ERROR);
296  //    e) Convey the object code using peer-to-peer transmission, provided           }
297  //    you inform other peers where the object code and Corresponding  
298  //    Source of the work are being offered to the general public at no        //Split into cases based on what we're doing.  This is wasteful of code,
299  //    charge under subsection 6d.        //but this is a PC application, not an embedded application.  In all cases
300  //        //create a hard error if something goes wrong.  Any anomalies should trash
301  //  A separable portion of the object code, whose source code is excluded        //a script.
302  //from the Corresponding Source as a System Library, need not be        if (!pred_option_specified && !succ_option_specified && !n_option_specified)
303  //included in conveying the object code work.           {
304  //           //This is the traditional best approximation case, with the possibility of
305  //  A "User Product" is either (1) a "consumer product", which means any           //the -neverlarger or -neversmaller being specified.  This is the most messy
306  //tangible personal property which is normally used for personal, family,           //of all the cases.  We must gather neighbors and figure out which is closer,
307  //or household purposes, or (2) anything designed or sold for incorporation           //and if there is a tie, which has the smaller magnitude.  It is fairly
308  //into a dwelling.  In determining whether a product is a consumer product,           //messy.
309  //doubtful cases shall be resolved in favor of coverage.  For a particular           GMP_RALG_fab_neighbor_collection_struct neighbor_data;
310  //product received by a particular user, "normally used" refers to a           GMP_RATS_mpq_struct left_neigh, right_neigh, diff_left, diff_right, closer_neighbor;
311  //typical or common use of that class of product, regardless of the status           int dist_cmp;
312  //of the particular user or of the way in which the particular user           int mag_cmp;
313  //actually uses, or expects or is expected to use, the product.  A product  
314  //is a consumer product regardless of whether the product has substantial           //Allocate inner dynamic variables.
315  //commercial, industrial or non-consumer uses, unless such uses represent           GMP_RATS_mpq_init(&left_neigh);
316  //the only significant mode of use of the product.           GMP_RATS_mpq_init(&right_neigh);
317  //           GMP_RATS_mpq_init(&diff_left);
318  //  "Installation Information" for a User Product means any methods,           GMP_RATS_mpq_init(&diff_right);
319  //procedures, authorization keys, or other information required to install           GMP_RATS_mpq_init(&closer_neighbor);
320  //and execute modified versions of a covered work in that User Product from  
321  //a modified version of its Corresponding Source.  The information must           //Form up the neighbor data.  We're only looking for up to one neighbor on each
322  //suffice to ensure that the continued functioning of the modified object           //side.
323  //code is in no case prevented or interfered with solely because           GMP_RALG_consecutive_fab_terms(
324  //modification has been made.                                         &q_rn,
325  //                                         &z_kmax,
326  //  If you convey an object code work under this section in, or with, or                                         &z_hmax,
327  //specifically for use in, a User Product, and the conveying occurs as                                         1,
328  //part of a transaction in which the right of possession and use of the                                         1,
329  //User Product is transferred to the recipient in perpetuity or for a                                         &neighbor_data
330  //fixed term (regardless of how the transaction is characterized), the                                         );
331  //Corresponding Source conveyed under this section must be accompanied  
332  //by the Installation Information.  But this requirement does not apply           //If there was an error or we couldn't get any neighbors to play with, give
333  //if neither you nor any third party retains the ability to install           //an error return.  As long as we have one neighbor on either side, we can definitely
334  //modified object code on the User Product (for example, the work has           //complete.
335  //been installed in ROM).           if (neighbor_data.error || (!neighbor_data.equality && (!neighbor_data.n_left_out || !neighbor_data.n_right_out)))
336  //              {
337  //  The requirement to provide Installation Information does not include a              rv = Tcl_NewStringObj("arbint cfbrapab: unable to form neighbors.", -1);
338  //requirement to continue to provide support service, warranty, or updates              Tcl_SetObjResult(interp, rv);
339  //for a work that has been modified or installed by the recipient, or for  
340  //the User Product in which it has been modified or installed.  Access to a              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
341  //network may be denied when the modification itself materially and              GMP_RATS_mpq_clear(&q_rn);
342  //adversely affects the operation of the network or violates the rules and              GMP_INTS_mpz_clear(&z_kmax);
343  //protocols for communication across the network.              GMP_INTS_mpz_clear(&z_hmax);
344  //  
345  //  Corresponding Source conveyed, and Installation Information provided,              GMP_RATS_mpq_clear(&left_neigh);
346  //in accord with this section must be in a format that is publicly              GMP_RATS_mpq_clear(&right_neigh);
347  //documented (and with an implementation available to the public in              GMP_RATS_mpq_clear(&diff_left);
348  //source code form), and must require no special password or key for              GMP_RATS_mpq_clear(&diff_right);
349  //unpacking, reading or copying.              GMP_RATS_mpq_clear(&closer_neighbor);
350  //  
351  //  7. Additional Terms.              return(TCL_ERROR);
352  //              }
353  //  "Additional permissions" are terms that supplement the terms of this  
354  //License by making exceptions from one or more of its conditions.           if (neighbor_data.equality)
355  //Additional permissions that are applicable to the entire Program shall              {
356  //be treated as though they were included in this License, to the extent              //The equality case takes precedence, always.
357  //that they are valid under applicable law.  If additional permissions              GMP_RATS_mpq_copy(&closer_neighbor, &(neighbor_data.norm_rn));
358  //apply only to part of the Program, that part may be used separately              }
359  //under those permissions, but the entire Program remains governed by           else
360  //this License without regard to the additional permissions.              {
361  //              //The boolean test somewhat above guaranteed that we have both left
362  //  When you convey a copy of a covered work, you may at your option              //and right neighbors.  We can assume this.
363  //remove any additional permissions from that copy, or from any part of              GMP_RATS_mpq_copy(&left_neigh,  &(neighbor_data.lefts[0].neighbor));
364  //it.  (Additional permissions may be written to require their own              GMP_RATS_mpq_copy(&right_neigh, &(neighbor_data.rights[0].neighbor));
365  //removal in certain cases when you modify the work.)  You may place  
366  //additional permissions on material, added by you to a covered work,              GMP_RATS_mpq_sub(&diff_left,  &left_neigh,  &(neighbor_data.norm_rn));
367  //for which you have or can give appropriate copyright permission.              GMP_RATS_mpq_sub(&diff_right, &right_neigh, &(neighbor_data.norm_rn));
368  //              GMP_INTS_mpz_abs(&(diff_left.num));
369  //  Notwithstanding any other provision of this License, for material you              GMP_INTS_mpz_abs(&(diff_right.num));
370  //add to a covered work, you may (if authorized by the copyright holders of              dist_cmp = GMP_RATS_mpq_cmp(&diff_left, &diff_right, NULL);
371  //that material) supplement the terms of this License with terms:  
372  //              //If we have a tie on the distance, will need to revert to magnitude of the neighbors.
373  //    a) Disclaiming warranty or limiting liability differently from the              GMP_INTS_mpz_abs(&(left_neigh.num));
374  //    terms of sections 15 and 16 of this License; or              GMP_INTS_mpz_abs(&(right_neigh.num));
375  //              mag_cmp = GMP_RATS_mpq_cmp(&left_neigh, &right_neigh, NULL);
376  //    b) Requiring preservation of specified reasonable legal notices or  
377  //    author attributions in that material or in the Appropriate Legal              if (!neversmaller_option_specified
378  //    Notices displayed by works containing it; or                 &&
379  //                 (neverlarger_option_specified || (dist_cmp < 0) || ((dist_cmp==0) && (mag_cmp < 0))))
380  //    c) Prohibiting misrepresentation of the origin of that material, or                 {
381  //    requiring that modified versions of such material be marked in                 GMP_RATS_mpq_copy(&closer_neighbor, &(neighbor_data.lefts[0].neighbor));
382  //    reasonable ways as different from the original version; or                 }
383  //              else
384  //    d) Limiting the use for publicity purposes of names of licensors or                 {
385  //    authors of the material; or                 GMP_RATS_mpq_copy(&closer_neighbor, &(neighbor_data.rights[0].neighbor));
386  //                 }
387  //    e) Declining to grant rights under trademark law for use of some              }
388  //    trade names, trademarks, or service marks; or  
389  //           //Stuff our variable of choice into a string ...
390  //    f) Requiring indemnification of licensors and authors of that           chars_reqd = INTFUNC_max(
391  //    material by anyone who conveys the material (or modified versions of                                   GMP_INTS_mpz_size_in_base_10(&(closer_neighbor.num)),
392  //    it) with contractual assumptions of liability to the recipient, for                                   GMP_INTS_mpz_size_in_base_10(&(closer_neighbor.den))
393  //    any liability that these contractual assumptions directly impose on                                   );
394  //    those licensors and authors.           string_result = TclpAlloc(sizeof(char) * chars_reqd);
395  //           assert(string_result != NULL);
396  //  All other non-permissive additional terms are considered "further  
397  //restrictions" within the meaning of section 10.  If the Program as you           GMP_INTS_mpz_to_string(string_result, &(closer_neighbor.num));
398  //received it, or any part of it, contains a notice stating that it is           rv = Tcl_NewStringObj(string_result, -1);
399  //governed by this License along with a term that is a further           Tcl_AppendToObj(rv, "/", -1);
400  //restriction, you may remove that term.  If a license document contains           GMP_INTS_mpz_to_string(string_result, &(closer_neighbor.den));
401  //a further restriction but permits relicensing or conveying under this           Tcl_AppendToObj(rv, string_result, -1);
402  //License, you may add to a covered work material governed by the terms  
403  //of that license document, provided that the further restriction does           Tcl_SetObjResult(interp, rv);
404  //not survive such relicensing or conveying.  
405  //           //Deallocate variables, make normal return.
406  //  If you add terms to a covered work in accord with this section, you           TclpFree(string_result);
407  //must place, in the relevant source files, a statement of the           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
408  //additional terms that apply to those files, or a notice indicating           GMP_RATS_mpq_clear(&q_rn);
409  //where to find the applicable terms.           GMP_INTS_mpz_clear(&z_kmax);
410  //           GMP_INTS_mpz_clear(&z_hmax);
411  //  Additional terms, permissive or non-permissive, may be stated in the  
412  //form of a separately written license, or stated as exceptions;           GMP_RATS_mpq_clear(&left_neigh);
413  //the above requirements apply either way.           GMP_RATS_mpq_clear(&right_neigh);
414  //           GMP_RATS_mpq_clear(&diff_left);
415  //  8. Termination.           GMP_RATS_mpq_clear(&diff_right);
416  //           GMP_RATS_mpq_clear(&closer_neighbor);
417  //  You may not propagate or modify a covered work except as expressly  
418  //provided under this License.  Any attempt otherwise to propagate or           return(TCL_OK);
419  //modify it is void, and will automatically terminate your rights under           }
420  //this License (including any patent licenses granted under the third        else if (n_option_specified)
421  //paragraph of section 11).           {
422  //           char sbuf[50];
423  //  However, if you cease all violation of this License, then your              //Static buffer just to stage 32-bit integers.
424  //license from a particular copyright holder is reinstated (a)            
425  //provisionally, unless and until the copyright holder explicitly and           //Multiple neighbors.  Must iterate through.
426  //finally terminates your license, and (b) permanently, if the copyright  
427  //holder fails to notify you of the violation by some reasonable means           GMP_RALG_fab_neighbor_collection_struct neighbor_data;
428  //prior to 60 days after the cessation.  
429  //           //Form up the neighbor data.      
430  //  Moreover, your license from a particular copyright holder is           GMP_RALG_consecutive_fab_terms(
431  //reinstated permanently if the copyright holder notifies you of the                                         &q_rn,
432  //violation by some reasonable means, this is the first time you have                                         &z_kmax,
433  //received notice of violation of this License (for any work) from that                                         &z_hmax,
434  //copyright holder, and you cure the violation prior to 30 days after                                         n,
435  //your receipt of the notice.                                         n,
436  //                                         &neighbor_data
437  //  Termination of your rights under this section does not terminate the                                         );
438  //licenses of parties who have received copies or rights from you under  
439  //this License.  If your rights have been terminated and not permanently           //If there was an error forming up the neighbor data, create a hard error.
440  //reinstated, you do not qualify to receive new licenses for the same           if (neighbor_data.error)
441  //material under section 10.              {
442  //              rv = Tcl_NewStringObj("arbint cfbrapab: unable to form neighbors.", -1);
443  //  9. Acceptance Not Required for Having Copies.              Tcl_SetObjResult(interp, rv);
444  //  
445  //  You are not required to accept this License in order to receive or              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
446  //run a copy of the Program.  Ancillary propagation of a covered work              GMP_RATS_mpq_clear(&q_rn);
447  //occurring solely as a consequence of using peer-to-peer transmission              GMP_INTS_mpz_clear(&z_kmax);
448  //to receive a copy likewise does not require acceptance.  However,              GMP_INTS_mpz_clear(&z_hmax);
449  //nothing other than this License grants you permission to propagate or  
450  //modify any covered work.  These actions infringe copyright if you do              return(TCL_ERROR);
451  //not accept this License.  Therefore, by modifying or propagating a              }
452  //covered work, you indicate your acceptance of this License to do so.  
453  //           //Allocate a default buffer of 10K for the ASCII representation of integers.
454  //  10. Automatic Licensing of Downstream Recipients.           //In the vast majority of cases, there will be only one allocation, because it
455  //           //takes a mean integer to exceed 10K.  However, the logic allows it to grow.
456  //  Each time you convey a covered work, the recipient automatically           string_result_n_allocd = 10000;
457  //receives a license from the original licensors, to run, modify and           string_result = TclpAlloc(sizeof(char) * string_result_n_allocd);
458  //propagate that work, subject to this License.  You are not responsible           assert(string_result != NULL);
459  //for enforcing compliance by third parties with this License.  
460  //           //Start off with a return value of the null string.
461  //  An "entity transaction" is a transaction transferring control of an           rv = Tcl_NewStringObj("", -1);
462  //organization, or substantially all assets of one, or subdividing an  
463  //organization, or merging organizations.  If propagation of a covered           //Loop through, spitting out the left neighbors.
464  //work results from an entity transaction, each party to that           for (i = neighbor_data.n_left_out-1; i >= 0; i--)
465  //transaction who receives a copy of the work also receives whatever              {
466  //licenses to the work the party's predecessor in interest had or could              //The protocol here is everyone spits out one space before
467  //give under the previous paragraph, plus a right to possession of the              //they print anything.  Must skip this on first loop iteration.
468  //Corresponding Source of the work from the predecessor in interest, if              if (i != neighbor_data.n_left_out-1)
469  //the predecessor has it or can get it with reasonable efforts.                 Tcl_AppendToObj(rv, " ", -1);
470  //  
471  //  You may not impose any further restrictions on the exercise of the              //The index will be the negative of the iteration variable minus one.
472  //rights granted or affirmed under this License.  For example, you may              sprintf(sbuf, "%d", -i - 1);
473  //not impose a license fee, royalty, or other charge for exercise of              Tcl_AppendToObj(rv, sbuf, -1);
474  //rights granted under this License, and you may not initiate litigation              
475  //(including a cross-claim or counterclaim in a lawsuit) alleging that              //Force the buffer to have enough space for the components of the rational
476  //any patent claim is infringed by making, using, selling, offering for              //number.
477  //sale, or importing the Program or any portion of it.              chars_reqd = INTFUNC_max(
478  //                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[i].neighbor.num)),
479  //  11. Patents.                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[i].neighbor.den))
480  //                                      );
481  //  A "contributor" is a copyright holder who authorizes use under this              if (chars_reqd > string_result_n_allocd)
482  //License of the Program or a work on which the Program is based.  The                 {
483  //work thus licensed is called the contributor's "contributor version".                 string_result_n_allocd = chars_reqd;
484  //                 string_result = TclpRealloc(string_result, sizeof(char) * string_result_n_allocd);
485  //  A contributor's "essential patent claims" are all patent claims                 assert(string_result != NULL);
486  //owned or controlled by the contributor, whether already acquired or                 }
487  //hereafter acquired, that would be infringed by some manner, permitted  
488  //by this License, of making, using, or selling its contributor version,              //Print the rational number out to the Tcl object.
489  //but do not include claims that would be infringed only as a              Tcl_AppendToObj(rv, " ", -1);
490  //consequence of further modification of the contributor version.  For              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[i].neighbor.num));
491  //purposes of this definition, "control" includes the right to grant              Tcl_AppendToObj(rv, string_result, -1);
492  //patent sublicenses in a manner consistent with the requirements of              Tcl_AppendToObj(rv, "/", -1);
493  //this License.              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[i].neighbor.den));
494  //              Tcl_AppendToObj(rv, string_result, -1);
495  //  Each contributor grants you a non-exclusive, worldwide, royalty-free              }
496  //patent license under the contributor's essential patent claims, to  
497  //make, use, sell, offer for sale, import and otherwise run, modify and           //Spit out the equality case if appropriate.
498  //propagate the contents of its contributor version.           if (neighbor_data.equality)
499  //              {
500  //  In the following three paragraphs, a "patent license" is any express              if (neighbor_data.n_left_out)
501  //agreement or commitment, however denominated, not to enforce a patent                 Tcl_AppendToObj(rv, " ", -1);
502  //(such as an express permission to practice a patent or covenant not to  
503  //sue for patent infringement).  To "grant" such a patent license to a              Tcl_AppendToObj(rv, "0", -1);
504  //party means to make such an agreement or commitment not to enforce a          
505  //patent against the party.              //Force the buffer to have enough space for the components of the rational
506  //              //number.
507  //  If you convey a covered work, knowingly relying on a patent license,              chars_reqd = INTFUNC_max(
508  //and the Corresponding Source of the work is not available for anyone                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.norm_rn.num)),
509  //to copy, free of charge and under the terms of this License, through a                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.norm_rn.den))
510  //publicly available network server or other readily accessible means,                                      );
511  //then you must either (1) cause the Corresponding Source to be so              if (chars_reqd > string_result_n_allocd)
512  //available, or (2) arrange to deprive yourself of the benefit of the                 {
513  //patent license for this particular work, or (3) arrange, in a manner                 string_result_n_allocd = chars_reqd;
514  //consistent with the requirements of this License, to extend the patent                 string_result = TclpRealloc(string_result, sizeof(char) * string_result_n_allocd);
515  //license to downstream recipients.  "Knowingly relying" means you have                 assert(string_result != NULL);
516  //actual knowledge that, but for the patent license, your conveying the                 }
517  //covered work in a country, or your recipient's use of the covered work  
518  //in a country, would infringe one or more identifiable patents in that              //Print the rational number out to the Tcl object.
519  //country that you have reason to believe are valid.              Tcl_AppendToObj(rv, " ", -1);
520  //              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.norm_rn.num));
521  //  If, pursuant to or in connection with a single transaction or              Tcl_AppendToObj(rv, string_result, -1);
522  //arrangement, you convey, or propagate by procuring conveyance of, a              Tcl_AppendToObj(rv, "/", -1);
523  //covered work, and grant a patent license to some of the parties              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.norm_rn.den));
524  //receiving the covered work authorizing them to use, propagate, modify              Tcl_AppendToObj(rv, string_result, -1);
525  //or convey a specific copy of the covered work, then the patent license              }
526  //you grant is automatically extended to all recipients of the covered  
527  //work and works based on it.           //Loop through, spitting out the right neighbors.
528  //           for (i = 0; i < neighbor_data.n_right_out; i++)
529  //  A patent license is "discriminatory" if it does not include within              {
530  //the scope of its coverage, prohibits the exercise of, or is              //The protocol here is everyone spits out one space before
531  //conditioned on the non-exercise of one or more of the rights that are              //they print anything.  Must skip this on first loop iteration.
532  //specifically granted under this License.  You may not convey a covered              if (neighbor_data.n_left_out || neighbor_data.equality || i)
533  //work if you are a party to an arrangement with a third party that is                 Tcl_AppendToObj(rv, " ", -1);
534  //in the business of distributing software, under which you make payment  
535  //to the third party based on the extent of your activity of conveying              //The index will be the iteration variable plus one.
536  //the work, and under which the third party grants, to any of the              sprintf(sbuf, "%d", i+1);
537  //parties who would receive the covered work from you, a discriminatory              Tcl_AppendToObj(rv, sbuf, -1);
538  //patent license (a) in connection with copies of the covered work              
539  //conveyed by you (or copies made from those copies), or (b) primarily              //Force the buffer to have enough space for the components of the rational
540  //for and in connection with specific products or compilations that              //number.
541  //contain the covered work, unless you entered into that arrangement,              chars_reqd = INTFUNC_max(
542  //or that patent license was granted, prior to 28 March 2007.                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[i].neighbor.num)),
543  //                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[i].neighbor.den))
544  //  Nothing in this License shall be construed as excluding or limiting                                      );
545  //any implied license or other defenses to infringement that may              if (chars_reqd > string_result_n_allocd)
546  //otherwise be available to you under applicable patent law.                 {
547  //                 string_result_n_allocd = chars_reqd;
548  //  12. No Surrender of Others' Freedom.                 string_result = TclpRealloc(string_result, sizeof(char) * string_result_n_allocd);
549  //                 assert(string_result != NULL);
550  //  If conditions are imposed on you (whether by court order, agreement or                 }
551  //otherwise) that contradict the conditions of this License, they do not  
552  //excuse you from the conditions of this License.  If you cannot convey a              //Print the rational number out to the Tcl object.
553  //covered work so as to satisfy simultaneously your obligations under this              Tcl_AppendToObj(rv, " ", -1);
554  //License and any other pertinent obligations, then as a consequence you may              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[i].neighbor.num));
555  //not convey it at all.  For example, if you agree to terms that obligate you              Tcl_AppendToObj(rv, string_result, -1);
556  //to collect a royalty for further conveying from those to whom you convey              Tcl_AppendToObj(rv, "/", -1);
557  //the Program, the only way you could satisfy both those terms and this              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[i].neighbor.den));
558  //License would be to refrain entirely from conveying the Program.              Tcl_AppendToObj(rv, string_result, -1);
559  //              }
560  //  13. Use with the GNU Affero General Public License.  
561  //           //Set up for a normal return.
562  //  Notwithstanding any other provision of this License, you have           Tcl_SetObjResult(interp, rv);
563  //permission to link or combine any covered work with a work licensed  
564  //under version 3 of the GNU Affero General Public License into a single           TclpFree(string_result);
565  //combined work, and to convey the resulting work.  The terms of this           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
566  //License will continue to apply to the part which is the covered work,           GMP_RATS_mpq_clear(&q_rn);
567  //but the special requirements of the GNU Affero General Public License,           GMP_INTS_mpz_clear(&z_kmax);
568  //section 13, concerning interaction through a network will apply to the           GMP_INTS_mpz_clear(&z_hmax);
569  //combination as such.  
570  //           return(TCL_OK);
571  //  14. Revised Versions of this License.           }
572  //        else if (pred_option_specified)
573  //  The Free Software Foundation may publish revised and/or new versions of           {
574  //the GNU General Public License from time to time.  Such new versions will           //Simple predecessor case.
575  //be similar in spirit to the present version, but may differ in detail to  
576  //address new problems or concerns.           GMP_RALG_fab_neighbor_collection_struct neighbor_data;
577  //  
578  //  Each version is given a distinguishing version number.  If the           //Form up the neighbor data.      
579  //Program specifies that a certain numbered version of the GNU General           GMP_RALG_consecutive_fab_terms(
580  //Public License "or any later version" applies to it, you have the                                         &q_rn,
581  //option of following the terms and conditions either of that numbered                                         &z_kmax,
582  //version or of any later version published by the Free Software                                         &z_hmax,
583  //Foundation.  If the Program does not specify a version number of the                                         1,
584  //GNU General Public License, you may choose any version ever published                                         0,
585  //by the Free Software Foundation.                                         &neighbor_data
586  //                                         );
587  //  If the Program specifies that a proxy can decide which future  
588  //versions of the GNU General Public License can be used, that proxy's           //If there was an error forming up the neighbor data or there are no left neighbors,
589  //public statement of acceptance of a version permanently authorizes you           //create a hard error.
590  //to choose that version for the Program.           if (neighbor_data.error || !neighbor_data.n_left_out)
591  //              {
592  //  Later license versions may give you additional or different              rv = Tcl_NewStringObj("arbint cfbrapab: unable to find predecessor.", -1);
593  //permissions.  However, no additional obligations are imposed on any              Tcl_SetObjResult(interp, rv);
594  //author or copyright holder as a result of your choosing to follow a  
595  //later version.              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
596  //              GMP_RATS_mpq_clear(&q_rn);
597  //  15. Disclaimer of Warranty.              GMP_INTS_mpz_clear(&z_kmax);
598  //              GMP_INTS_mpz_clear(&z_hmax);
599  //  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY  
600  //APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT              return(TCL_ERROR);
601  //HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY              }
602  //OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,  
603  //THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR           //The test above confirmed that we have at least one left neighbor calculated.
604  //PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM           //We can dump it to a string and finish up.
605  //IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF           chars_reqd = INTFUNC_max(
606  //ALL NECESSARY SERVICING, REPAIR OR CORRECTION.                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[0].neighbor.num)),
607  //                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[0].neighbor.den))
608  //  16. Limitation of Liability.                                   );
609  //           string_result = TclpAlloc(sizeof(char) * chars_reqd);
610  //  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING           assert(string_result != NULL);
611  //WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS  
612  //THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[0].neighbor.num));
613  //GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE           rv = Tcl_NewStringObj(string_result, -1);
614  //USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF           Tcl_AppendToObj(rv, "/", -1);
615  //DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[0].neighbor.den));
616  //PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),           Tcl_AppendToObj(rv, string_result, -1);
617  //EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF  
618  //SUCH DAMAGES.           Tcl_SetObjResult(interp, rv);
619  //  
620  //  17. Interpretation of Sections 15 and 16.           TclpFree(string_result);
621  //           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
622  //  If the disclaimer of warranty and limitation of liability provided           GMP_RATS_mpq_clear(&q_rn);
623  //above cannot be given local legal effect according to their terms,           GMP_INTS_mpz_clear(&z_kmax);
624  //reviewing courts shall apply local law that most closely approximates           GMP_INTS_mpz_clear(&z_hmax);
625  //an absolute waiver of all civil liability in connection with the  
626  //Program, unless a warranty or assumption of liability accompanies a           return(TCL_OK);
627  //copy of the Program in return for a fee.           }
628  //        else if (succ_option_specified)
629  //                     END OF TERMS AND CONDITIONS           {
630  //           //Simple successor.
631  //            How to Apply These Terms to Your New Programs  
632  //           GMP_RALG_fab_neighbor_collection_struct neighbor_data;
633  //  If you develop a new program, and you want it to be of the greatest  
634  //possible use to the public, the best way to achieve this is to make it           //Form up the neighbor data.      
635  //free software which everyone can redistribute and change under these terms.           GMP_RALG_consecutive_fab_terms(
636  //                                         &q_rn,
637  //  To do so, attach the following notices to the program.  It is safest                                         &z_kmax,
638  //to attach them to the start of each source file to most effectively                                         &z_hmax,
639  //state the exclusion of warranty; and each file should have at least                                         0,
640  //the "copyright" line and a pointer to where the full notice is found.                                         1,
641  //                                         &neighbor_data
642  //    <one line to give the program's name and a brief idea of what it does.>                                         );
643  //    Copyright (C) <year>  <name of author>  
644  //           //If there was an error forming up the neighbor data or there are no right neighbors,
645  //    This program is free software: you can redistribute it and/or modify           //create a hard error.
646  //    it under the terms of the GNU General Public License as published by           if (neighbor_data.error || !neighbor_data.n_right_out)
647  //    the Free Software Foundation, either version 3 of the License, or              {
648  //    (at your option) any later version.              rv = Tcl_NewStringObj("arbint cfbrapab: unable to find successor.", -1);
649  //              Tcl_SetObjResult(interp, rv);
650  //    This program is distributed in the hope that it will be useful,  
651  //    but WITHOUT ANY WARRANTY; without even the implied warranty of              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
652  //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              GMP_RATS_mpq_clear(&q_rn);
653  //    GNU General Public License for more details.              GMP_INTS_mpz_clear(&z_kmax);
654  //              GMP_INTS_mpz_clear(&z_hmax);
655  //    You should have received a copy of the GNU General Public License  
656  //    along with this program.  If not, see <http://www.gnu.org/licenses/>.              return(TCL_ERROR);
657  //              }
658  //Also add information on how to contact you by electronic and paper mail.  
659  //           //The test above confirmed that we have at least one right neighbor calculated.
660  //  If the program does terminal interaction, make it output a short           //We can dump it to a string and finish up.
661  //notice like this when it starts in an interactive mode:           chars_reqd = INTFUNC_max(
662  //                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[0].neighbor.num)),
663  //    <program>  Copyright (C) <year>  <name of author>                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[0].neighbor.den))
664  //    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.                                   );
665  //    This is free software, and you are welcome to redistribute it           string_result = TclpAlloc(sizeof(char) * chars_reqd);
666  //    under certain conditions; type `show c' for details.           assert(string_result != NULL);
667  //  
668  //The hypothetical commands `show w' and `show c' should show the appropriate           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[0].neighbor.num));
669  //parts of the General Public License.  Of course, your program's commands           rv = Tcl_NewStringObj(string_result, -1);
670  //might be different; for a GUI interface, you would use an "about box".           Tcl_AppendToObj(rv, "/", -1);
671  //           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[0].neighbor.den));
672  //  You should also get your employer (if you work as a programmer) or school,           Tcl_AppendToObj(rv, string_result, -1);
673  //if any, to sign a "copyright disclaimer" for the program, if necessary.  
674  //For more information on this, and how to apply and follow the GNU GPL, see           Tcl_SetObjResult(interp, rv);
675  //<http://www.gnu.org/licenses/>.  
676  //           TclpFree(string_result);
677  //  The GNU General Public License does not permit incorporating your program           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);
678  //into proprietary programs.  If your program is a subroutine library, you           GMP_RATS_mpq_clear(&q_rn);
679  //may consider it more useful to permit linking proprietary applications with           GMP_INTS_mpz_clear(&z_kmax);
680  //the library.  If this is what you want to do, use the GNU Lesser General           GMP_INTS_mpz_clear(&z_hmax);
681  //Public License instead of this License.  But first, please read  
682  //<http://www.gnu.org/philosophy/why-not-lgpl.html>.           return(TCL_OK);
683  //-------------------------------------------------------------------------------------------------           }
684  //--------------------------------------------------------------------------------  
685  #define MODULE_ARBLENINTS        //Free up all dynamic memory.
686          GMP_RATS_mpq_clear(&q_rn);
687  #include <assert.h>        GMP_INTS_mpz_clear(&z_kmax);
688  #include <string.h>        GMP_INTS_mpz_clear(&z_hmax);
689    
690  #include "tcl.h"        //Return
691  #include "tcldecls.h"        return(TCL_OK);
692          }
693  #include "arblenints.h"     }
694  #include "bstrfunc.h"  
695  #include "extninit.h"  
696  #include "gmp_ints.h"  //Handles the "cfratnum" subextension.
697  #include "gmp_rats.h"  //08/07/01:  Visually inspected, OK.
698  #include "gmp_ralg.h"  static
699  #include "intfunc.h"  int ARBLENINTS_cfratnum_handler(ClientData dummy,
700  #include "tclalloc.h"                                Tcl_Interp *interp,
701                                  int objc,
702                                  Tcl_Obj *objv[])
703  //Handles the "cfbrapab" subextension.     {
704  //08/16/01: Visual inspection OK.     Tcl_Obj *rv;
705  static  
706  int ARBLENINTS_cfbrapab_handler(ClientData dummy,     //We must have exactly one additional argument
707                                  Tcl_Interp *interp,     //to this function, which is the rational number
708                                  int objc,     //whose continued fraction decomposition is to be
709                                  Tcl_Obj *objv[])     //calculated.
710     {     if (objc != 3)
711     Tcl_Obj *rv;        {
712          Tcl_WrongNumArgs(interp,
713     //We must have at least two additional arguments                         2,
714     //to this extension.                         objv,
715     if (objc < 4)                         "urn");
716        {        return(TCL_ERROR);
717        Tcl_WrongNumArgs(interp,        }
718                         2,     else
719                         objv,        {
720                         "srn uint_kmax ?uint_hmax? ?options?");        char *input_arg;
721        return(TCL_ERROR);        int failure;
722        }        unsigned chars_reqd;
723     else        char *string_result;
724        {        int n_string_result;
725        char *input_arg;        int i;
726        int failure, first_dashed_parameter;        GMP_RATS_mpq_struct rn;
727        char *string_result;        GMP_RALG_cf_app_struct decomp;
728        int string_result_n_allocd;  
729        int chars_reqd;        //In this function, we are going to return a string
730        int i;        //result formed by starting with a string and then
731        int pred_option_specified         = 0;        //concatenating  to it again and again.  We start
732        int succ_option_specified         = 0;        //off believing that 10,000 characters of space is enough,
733        int neversmaller_option_specified = 0;        //but we may need to revise upward and reallocate.  
734        int neverlarger_option_specified  = 0;        //A 10,000 character block is chosen because it is quick
735        int n_option_specified            = 0;        //to allocate and most times won't go beyond that.
736        unsigned n                        = 0;        n_string_result = 10000;
737          string_result = TclpAlloc(sizeof(char) * n_string_result);
738        GMP_RATS_mpq_struct q_rn;        assert(string_result != NULL);
739        GMP_INTS_mpz_struct z_kmax;  
740        GMP_INTS_mpz_struct z_hmax;        //We will need a rational number to hold the return value
741          //from the parsing function.  Allocate that now.
742        //Allocate dynamic memory.        GMP_RATS_mpq_init(&rn);
743        GMP_RATS_mpq_init(&q_rn);  
744        GMP_INTS_mpz_init(&z_kmax);        //Grab a pointer to the string representation of
745        GMP_INTS_mpz_init(&z_hmax);        //the input argument.  The storage does not belong to us.
746          input_arg = Tcl_GetString(objv[2]);
747        //Grab a pointer to the string representation of        assert(input_arg != NULL);
748        //the first input argument.  The storage does not belong to us.  
749        input_arg = Tcl_GetString(objv[2]);        //Try to parse our input string as a rational number.
750        assert(input_arg != NULL);        //If we are not successful in this, must abort.
751          GMP_RATS_mpq_set_all_format_rat_num(input_arg,
752        //Try to parse our first input string as a rational number.                                            &failure,
753        //If we are not successful in this, must abort.                                            &rn);
754        GMP_RATS_mpq_set_all_format_rat_num(input_arg,  
755                                            &failure,        if (failure)
756                                            &q_rn);           {
757             rv = Tcl_NewStringObj("arbint cfratnum: \"", -1);
758        if (failure)           Tcl_AppendToObj(rv, input_arg, -1);
759           {  
760           rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);           Tcl_AppendToObj(rv, "\" is not a recognized non-negative rational number.", -1);
761           Tcl_AppendToObj(rv, input_arg, -1);           Tcl_SetObjResult(interp, rv);
762    
763           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);           TclpFree(string_result);
764           Tcl_SetObjResult(interp, rv);           GMP_RATS_mpq_clear(&rn);
765    
766           GMP_RATS_mpq_clear(&q_rn);           return(TCL_ERROR);
767           GMP_INTS_mpz_clear(&z_kmax);           }
768           GMP_INTS_mpz_clear(&z_hmax);  
769          //OK, we have a rational number, but there is a possibility
770           return(TCL_ERROR);        //it is negative, which is a no-no.  Normalize the signs
771           }        //for easier testing.
772          GMP_RATS_mpq_normalize_sign(&rn);
773        //Try to parse our next argument as an integer, which        if (GMP_INTS_mpz_is_neg(&(rn.num)))
774        //will be KMAX.  This must be specified.           {
775        //           rv = Tcl_NewStringObj("arbint cfratnum: \"", -1);
776        //Get string pointer.  Storage does not belong to us.           Tcl_AppendToObj(rv, input_arg, -1);
777        input_arg = Tcl_GetString(objv[3]);  
778        assert(input_arg != NULL);           Tcl_AppendToObj(rv, "\" is negative.", -1);
779             Tcl_SetObjResult(interp, rv);
780        //Try to convert KMAX to an integer.  Fatal if an error,  
781        //and fatal if the argument is zero or negative.           TclpFree(string_result);
782        GMP_INTS_mpz_set_general_int(&z_kmax, &failure, input_arg);           GMP_RATS_mpq_clear(&rn);
783    
784        //If there was a parse failure or if the integer is zero           return(TCL_ERROR);
785        //or negative, must flag error.           }
786        if (failure || GMP_INTS_mpz_is_neg(&z_kmax) || GMP_INTS_mpz_is_zero(&z_kmax))  
787           {        //OK, we have a rational number.  Form the continued fraction
788           rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);        //decomposition of it.  The function called is set up so that
789           Tcl_AppendToObj(rv, input_arg, -1);        //one must deallocate, even in an error condition.
790           Tcl_AppendToObj(rv, "\" is not a recognized positive integer.", -1);        GMP_RALG_cfdecomp_init(&decomp,
791           Tcl_SetObjResult(interp, rv);                               &failure,
792                                 &(rn.num),
793           GMP_RATS_mpq_clear(&q_rn);                               &(rn.den));
794           GMP_INTS_mpz_clear(&z_kmax);  
795           GMP_INTS_mpz_clear(&z_hmax);        //If we failed in the decomposition (don't know why that would
796          //happen) use the general error flag "NAN".
797           return(TCL_ERROR);        if (failure)
798           }           {
799             rv = Tcl_NewStringObj("NAN", -1);
800        //We need to look for HMAX as the next parameter, if it exists.  
801        //The way we will figure this out is by whether the           Tcl_SetObjResult(interp, rv);
802        //parameter begins with a "-" or not.  
803        if (objc >= 5)           TclpFree(string_result);
804           {           GMP_RATS_mpq_clear(&rn);
805           input_arg = Tcl_GetString(objv[4]);           GMP_RALG_cfdecomp_destroy(&decomp);
806           assert(input_arg != NULL);  
807             return(TCL_ERROR);
808           if (input_arg[0] == '-')           }
809              {  
810              first_dashed_parameter = 4;        //OK, that really is the last error we could have.
811              }        //Iterate, adding the partial quotients and convergents
812           else        //to the string which we'll return.  We need to watch out
813              {        //for running over our 10K buffer.
814              first_dashed_parameter = 5;        rv = Tcl_NewStringObj("", -1);
815              }        for (i=0; i<decomp.n; i++)
816           }           {
817        else           //Partial quotient.
818           {           chars_reqd = GMP_INTS_mpz_size_in_base_10(&(decomp.a[i]));
819           first_dashed_parameter = 4;           if (chars_reqd > (unsigned)n_string_result)
820           }              {
821                n_string_result = chars_reqd;
822        //If there is another parameter and it              string_result = TclpRealloc(string_result,
823        //doesn't begin with a dash, try to parse                                          sizeof(char) * n_string_result);
824        //it as HMAX.  We don't explicitly record whether              }
825        //HMAX is specified, because zero is a signal           GMP_INTS_mpz_to_string(string_result, &(decomp.a[i]));
826        //when calculating Farey neighbors that HMAX isn't           Tcl_AppendToObj(rv, string_result, -1);
827        //to be considered.           Tcl_AppendToObj(rv, " ", -1);
828        if ((objc >= 5) && (first_dashed_parameter == 5))  
829           {           //Numerator of convergent.
830           //Get string pointer.  Storage does not belong to us.           chars_reqd = GMP_INTS_mpz_size_in_base_10(&(decomp.p[i]));
831           input_arg = Tcl_GetString(objv[4]);           if (chars_reqd > (unsigned)n_string_result)
832           assert(input_arg != NULL);              {
833                n_string_result = chars_reqd;
834           //Try to convert HMAX to an integer.  Fatal if an error,              string_result = TclpRealloc(string_result,
835           //and fatal if the argument is zero or negative.                                          sizeof(char) * n_string_result);
836           GMP_INTS_mpz_set_general_int(&z_hmax, &failure, input_arg);              }
837             GMP_INTS_mpz_to_string(string_result, &(decomp.p[i]));
838           //If there was a parse failure or if the integer is zero           Tcl_AppendToObj(rv, string_result, -1);
839           //or negative, must flag error.           Tcl_AppendToObj(rv, " ", -1);
840           if (failure || GMP_INTS_mpz_is_neg(&z_hmax) || GMP_INTS_mpz_is_zero(&z_hmax))  
841              {           //Denominator of convergent.
842              rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);           chars_reqd = GMP_INTS_mpz_size_in_base_10(&(decomp.q[i]));
843              Tcl_AppendToObj(rv, input_arg, -1);           if (chars_reqd > (unsigned)n_string_result)
844              Tcl_AppendToObj(rv, "\" is not a recognized positive integer.", -1);              {
845              Tcl_SetObjResult(interp, rv);              n_string_result = chars_reqd;
846                string_result = TclpRealloc(string_result,
847              GMP_RATS_mpq_clear(&q_rn);                                          sizeof(char) * n_string_result);
848              GMP_INTS_mpz_clear(&z_kmax);              }
849              GMP_INTS_mpz_clear(&z_hmax);           GMP_INTS_mpz_to_string(string_result, &(decomp.q[i]));
850             Tcl_AppendToObj(rv, string_result, -1);
851              return(TCL_ERROR);           if (i != (decomp.n - 1)) //No space after last number.
852              }              Tcl_AppendToObj(rv, " ", -1);
853           }           }
854    
855        //Process all of the dashed command-line arguments.        //Assign the result to be the return value.
856        //This involves iterating through all of the        Tcl_SetObjResult(interp, rv);
857        //parameters and processing them.  
858        for (i=first_dashed_parameter; i<objc; i++)        //Free up all dynamic memory.
859           {        TclpFree(string_result);
860           input_arg = Tcl_GetString(objv[i]);        GMP_RATS_mpq_clear(&rn);
861           assert(input_arg != NULL);        GMP_RALG_cfdecomp_destroy(&decomp);
862    
863           if (!strcmp("-pred", input_arg))        //Return
864              {        return(TCL_OK);
865              pred_option_specified = 1;        }
866              }     }
867           else if (!strcmp("-succ", input_arg))  
868              {  
869              succ_option_specified = 1;  //Handles the "commanate" subextension.
870              }  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this
871           else if (!strcmp("-neversmaller", input_arg))  //from memory an intuition as far as how to set return results and so forth.
872              {  static
873              neversmaller_option_specified = 1;  int ARBLENINTS_commanate_handler(ClientData dummy,
874              }                                Tcl_Interp *interp,
875           else if (!strcmp("-neverlarger", input_arg))                                int objc,
876              {                                Tcl_Obj *objv[])
877              neverlarger_option_specified = 1;     {
878              }     Tcl_Obj *rv;
879           else if (!strcmp("-n", input_arg))  
880              {     //We must have one and exactly one additional argument
881              n_option_specified = 1;     //to this function, which is the string we want to
882       //commanate.
883              //If -n was specified, there must be a following     if (objc != 3)
884              //parameter which supplies the integer.  First        {
885              //check for existence of an additional parameter.        Tcl_WrongNumArgs(interp,
886              if (i >= (objc - 1))                         2,
887                 {                         objv,
888                 rv = Tcl_NewStringObj("arbint cfbrapab: -n option specified without following integer.", -1);                         "sint");
889                 Tcl_SetObjResult(interp, rv);        return(TCL_ERROR);
890          }
891                 GMP_RATS_mpq_clear(&q_rn);     else
892                 GMP_INTS_mpz_clear(&z_kmax);        {
893                 GMP_INTS_mpz_clear(&z_hmax);        char *string_arg;
894    
895                 return(TCL_ERROR);        //Grab a pointer to the string representation of
896                 }        //the input argument.  The storage does not belong to us.
897          string_arg = Tcl_GetString(objv[2]);
898              //We have at least one additional parameter.  Try        assert(string_arg != NULL);
899              //to parse out the next parameter as the integer  
900              //we need for n.        //Try to parse the string as one of the error tags.
901              i++;        //If it is one of those, it isn't an error, but don't
902          //want to touch the string.
903              input_arg = Tcl_GetString(objv[i]);        if (GMP_INTS_identify_nan_string(string_arg) >= 0)
904              assert(input_arg != NULL);           {
905             rv = Tcl_NewStringObj(string_arg, -1);
906              GMP_INTS_mpz_parse_into_uint32(&n, &failure, input_arg);           Tcl_SetObjResult(interp, rv);
907             return(TCL_OK);
908              //If the parse was unsuccessful, terminate.           }
909              if (failure)        //Try to parse it as a signed integer with commas already.
910                 {        //If it already has commas, there is no need to add any.
911                 rv = Tcl_NewStringObj("arbint cfbrapab: -n option followed by invalid integer.", -1);        else if (BSTRFUNC_is_sint_w_commas(string_arg))
912                 Tcl_SetObjResult(interp, rv);           {
913             //This is already an acceptable commanated signed integer.  Send it
914                 GMP_RATS_mpq_clear(&q_rn);           //back as the return value.
915                 GMP_INTS_mpz_clear(&z_kmax);           rv = Tcl_NewStringObj(string_arg, -1);
916                 GMP_INTS_mpz_clear(&z_hmax);           Tcl_SetObjResult(interp, rv);
917             return(TCL_OK);
918                 return(TCL_ERROR);           }
919                 }        //Try to parse the argument as a signed integer without commas.
920          //If it is one of those, commanate it and return it.
921              //Clip the integer into a 24-bit quantity.        else if (BSTRFUNC_is_sint_wo_commas(string_arg))
922              n &= 0x00FFFFFF;           {
923              }           size_t len;
924           else           char *buffer;
925              {  
926              //Unrecognized option.  Crash out.           len = strlen(string_arg);
927              rv = Tcl_NewStringObj("arbint cfbrapab: \"", -1);           buffer = TclpAlloc(((sizeof(char) * 4 * len) / 3) + 10);
928              Tcl_AppendToObj(rv, input_arg, -1);           strcpy(buffer, string_arg);
929              Tcl_AppendToObj(rv, "\" is not a recognized option.", -1);           BSTRFUNC_commanate(buffer);
930              Tcl_SetObjResult(interp, rv);           rv = Tcl_NewStringObj(buffer, -1);
931             TclpFree(buffer);
932              GMP_RATS_mpq_clear(&q_rn);           Tcl_SetObjResult(interp, rv);
933              GMP_INTS_mpz_clear(&z_kmax);           return(TCL_OK);
934              GMP_INTS_mpz_clear(&z_hmax);           }
935          else
936              return(TCL_ERROR);           {
937              }           //Error case.  Must give error message.
938           }           rv = Tcl_NewStringObj("arbint commanate: \"", -1);
939             Tcl_AppendToObj(rv, string_arg, -1);
940        //Look for any mutually exclusive options.  Give a catchall if any of           Tcl_AppendToObj(rv, "\" is not a recognized integer.", -1);
941        //them specified.  Because we set them all to 1, addition is the easiest           Tcl_SetObjResult(interp, rv);
942        //way to do this.           return(TCL_ERROR);
943        if ((pred_option_specified + succ_option_specified + neversmaller_option_specified           }
944             + neverlarger_option_specified + n_option_specified) > 1)        }
945           {     }
946           rv = Tcl_NewStringObj("arbint cfbrapab: -pred, -succ, -neversmaller, -neverlarger, and -n are mutually exclusive options.", -1);  
947           Tcl_SetObjResult(interp, rv);  
948    //Handles the "const" subextension.
949           GMP_RATS_mpq_clear(&q_rn);  //08/17/01: Visual inspection OK.
950           GMP_INTS_mpz_clear(&z_kmax);  static
951           GMP_INTS_mpz_clear(&z_hmax);  int ARBLENINTS_const_handler(ClientData dummy,
952                                 Tcl_Interp *interp,
953           return(TCL_ERROR);                               int objc,
954           }                               Tcl_Obj *objv[])
955       {
956        //Split into cases based on what we're doing.  This is wasteful of code,     //Table of constants used.
957        //but this is a PC application, not an embedded application.  In all cases     static struct
958        //create a hard error if something goes wrong.  Any anomalies should trash        {
959        //a script.        char *tag;
960        if (!pred_option_specified && !succ_option_specified && !n_option_specified)           //The symbolic tag used to identify the number.
961           {        char *desc;
962           //This is the traditional best approximation case, with the possibility of           //The full description of the number.  It must consist
963           //the -neverlarger or -neversmaller being specified.  This is the most messy           //of a string with lines no longer than about 70 chars,
964           //of all the cases.  We must gather neighbors and figure out which is closer,           //separated by newlines, and indented by 6 spaces.
965           //and if there is a tie, which has the smaller magnitude.  It is fairly        char *minmant;
966           //messy.           //The minimum mantissa or minimum representation.
967           GMP_RALG_fab_neighbor_collection_struct neighbor_data;           //May not be empty or NULL.
968           GMP_RATS_mpq_struct left_neigh, right_neigh, diff_left, diff_right, closer_neighbor;        char *mantrem;
969           int dist_cmp;           //The remaining mantissa or remaining portion of
970           int mag_cmp;           //number.  May be empty, but may not be NULL.
971          char *exp;
972           //Allocate inner dynamic variables.           //The exponent portion, if any, or NULL otherwise.
973           GMP_RATS_mpq_init(&left_neigh);        int deflen;
974           GMP_RATS_mpq_init(&right_neigh);           //The default number of digits for the constant
975           GMP_RATS_mpq_init(&diff_left);           //if none is specified.
976           GMP_RATS_mpq_init(&diff_right);        int digit_count_offset;
977           GMP_RATS_mpq_init(&closer_neighbor);           //The offset to go from string length of mantissa
978             //portions to number of digits.  Cheap way to adjust
979           //Form up the neighbor data.  We're only looking for up to one neighbor on each           //for - sign and decimal point.
980           //side.        } tbl[] =
981           GMP_RALG_consecutive_fab_terms(        {
982                                         &q_rn,        //e--the transcendental number e.
983                                         &z_kmax,           {
984                                         &z_hmax,           //tag
985                                         1,           "e",
986                                         1,           //desc
987                                         &neighbor_data           "      Historically significant transcendental constant.  Digits obtained\n"
988                                         );           "      from http://fermi.udw.ac.za/physics/e.html on 08/17/01.",
989             //minmant
990           //If there was an error or we couldn't get any neighbors to play with, give           "2.7",
991           //an error return.  As long as we have one neighbor on either side, we can definitely           //mantrem
992           //complete.           "182818284590452353602874713526624977572470936999595749669676277240766303535"
993           if (neighbor_data.error || (!neighbor_data.equality && (!neighbor_data.n_left_out || !neighbor_data.n_right_out)))           "475945713821785251664274274663919320030599218174135966290435729003342952605956"
994              {           "307381323286279434907632338298807531952510190115738341879307021540891499348841"
995              rv = Tcl_NewStringObj("arbint cfbrapab: unable to form neighbors.", -1);           "675092447614606680822648001684774118537423454424371075390777449920695517027618"
996              Tcl_SetObjResult(interp, rv);           "386062613313845830007520449338265602976067371132007093287091274437470472306969"
997             "772093101416928368190255151086574637721112523897844250569536967707854499699679"
998              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);           "468644549059879316368892300987931277361782154249992295763514822082698951936680"
999              GMP_RATS_mpq_clear(&q_rn);           "331825288693984964651058209392398294887933203625094431173012381970684161403970"
1000              GMP_INTS_mpz_clear(&z_kmax);           "198376793206832823764648042953118023287825098194558153017567173613320698112509"
1001              GMP_INTS_mpz_clear(&z_hmax);           "961818815930416903515988885193458072738667385894228792284998920868058257492796"
1002             "104841984443634632449684875602336248270419786232090021609902353043699418491463"
1003              GMP_RATS_mpq_clear(&left_neigh);           "140934317381436405462531520961836908887070167683964243781405927145635490613031"
1004              GMP_RATS_mpq_clear(&right_neigh);           "07208510383750510115747704171898610687396965521267154688957035035",
1005              GMP_RATS_mpq_clear(&diff_left);           //exp
1006              GMP_RATS_mpq_clear(&diff_right);           NULL,
1007              GMP_RATS_mpq_clear(&closer_neighbor);           //deflen
1008             30,
1009              return(TCL_ERROR);           //digit_count_offset
1010              }           1
1011             },
1012           if (neighbor_data.equality)        //g_metric
1013              {           {
1014              //The equality case takes precedence, always.           //tag
1015              GMP_RATS_mpq_copy(&closer_neighbor, &(neighbor_data.norm_rn));           "g_si",
1016              }           //desc
1017           else           "      Gravitational acceleration in SI units, meters per second**2.\n"
1018              {           "      Obtained from NIST Special Publication 811 on 08/17/01.",
1019              //The boolean test somewhat above guaranteed that we have both left           //minmant
1020              //and right neighbors.  We can assume this.           "9.80665",
1021              GMP_RATS_mpq_copy(&left_neigh,  &(neighbor_data.lefts[0].neighbor));           //mantrem
1022              GMP_RATS_mpq_copy(&right_neigh, &(neighbor_data.rights[0].neighbor));           "",
1023             //exp
1024              GMP_RATS_mpq_sub(&diff_left,  &left_neigh,  &(neighbor_data.norm_rn));           NULL,
1025              GMP_RATS_mpq_sub(&diff_right, &right_neigh, &(neighbor_data.norm_rn));           //deflen
1026              GMP_INTS_mpz_abs(&(diff_left.num));           30,
1027              GMP_INTS_mpz_abs(&(diff_right.num));           //digit_count_offset
1028              dist_cmp = GMP_RATS_mpq_cmp(&diff_left, &diff_right, NULL);           1
1029             },
1030              //If we have a tie on the distance, will need to revert to magnitude of the neighbors.        //in2m
1031              GMP_INTS_mpz_abs(&(left_neigh.num));           {
1032              GMP_INTS_mpz_abs(&(right_neigh.num));           //tag
1033              mag_cmp = GMP_RATS_mpq_cmp(&left_neigh, &right_neigh, NULL);           "in2m",
1034             //desc
1035              if (!neversmaller_option_specified           "      Multiplicative conversion factor from inches to meters.\n"
1036                 &&           "      Obtained from NIST Special Publication 811 on 08/17/01.",
1037                 (neverlarger_option_specified || (dist_cmp < 0) || ((dist_cmp==0) && (mag_cmp < 0))))           //minmant
1038                 {           "2.54",
1039                 GMP_RATS_mpq_copy(&closer_neighbor, &(neighbor_data.lefts[0].neighbor));           //mantrem
1040                 }           "",
1041              else           //exp
1042                 {           "e-2",
1043                 GMP_RATS_mpq_copy(&closer_neighbor, &(neighbor_data.rights[0].neighbor));           //deflen
1044                 }           30,
1045              }           //digit_count_offset
1046             1
1047           //Stuff our variable of choice into a string ...           },
1048           chars_reqd = INTFUNC_max(        //mi2km
1049                                   GMP_INTS_mpz_size_in_base_10(&(closer_neighbor.num)),           {
1050                                   GMP_INTS_mpz_size_in_base_10(&(closer_neighbor.den))           //tag
1051                                   );           "mi2km",
1052           string_result = TclpAlloc(sizeof(char) * chars_reqd);           //desc
1053           assert(string_result != NULL);           "      Multiplicative conversion factor from miles to kilometers.\n"
1054             "      Obtained from NIST Special Publication 811 on 08/17/01.",
1055           GMP_INTS_mpz_to_string(string_result, &(closer_neighbor.num));           //minmant
1056           rv = Tcl_NewStringObj(string_result, -1);           "1.609344",
1057           Tcl_AppendToObj(rv, "/", -1);           //mantrem
1058           GMP_INTS_mpz_to_string(string_result, &(closer_neighbor.den));           "",
1059           Tcl_AppendToObj(rv, string_result, -1);           //exp
1060             NULL,
1061           Tcl_SetObjResult(interp, rv);           //deflen
1062             30,
1063           //Deallocate variables, make normal return.           //digit_count_offset
1064           TclpFree(string_result);           1
1065           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);           },
1066           GMP_RATS_mpq_clear(&q_rn);        //pi--the transcendental number PI.
1067           GMP_INTS_mpz_clear(&z_kmax);           {
1068           GMP_INTS_mpz_clear(&z_hmax);           //tag
1069             "pi",
1070           GMP_RATS_mpq_clear(&left_neigh);           //desc
1071           GMP_RATS_mpq_clear(&right_neigh);           "      Transcendental constant supplying ratio of a circle's circumference\n"
1072           GMP_RATS_mpq_clear(&diff_left);           "      to its diameter.  Digits obtained from http://www.joyofpi.com/\n"
1073           GMP_RATS_mpq_clear(&diff_right);           "      pi.htm on 08/17/01.",
1074           GMP_RATS_mpq_clear(&closer_neighbor);           //minmant
1075             "3.14",
1076           return(TCL_OK);           //mantrem
1077           }           "15926535897932384626433832795028841971"
1078        else if (n_option_specified)           "6939937510582097494459230781640628620899"
1079           {           "8628034825342117067982148086513282306647"
1080           char sbuf[50];           "0938446095505822317253594081284811174502"
1081              //Static buffer just to stage 32-bit integers.           "8410270193852110555964462294895493038196"
1082                       "4428810975665933446128475648233786783165"
1083           //Multiple neighbors.  Must iterate through.           "2712019091456485669234603486104543266482"
1084             "1339360726024914127372458700660631558817"
1085           GMP_RALG_fab_neighbor_collection_struct neighbor_data;           "4881520920962829254091715364367892590360"
1086             "0113305305488204665213841469519415116094"
1087           //Form up the neighbor data.                 "3305727036575959195309218611738193261179"
1088           GMP_RALG_consecutive_fab_terms(           "3105118548074462379962749567351885752724"
1089                                         &q_rn,           "8912279381830119491298336733624406566430"
1090                                         &z_kmax,           "8602139494639522473719070217986094370277"
1091                                         &z_hmax,           "0539217176293176752384674818467669405132"
1092                                         n,           "0005681271452635608277857713427577896091"
1093                                         n,           "7363717872146844090122495343014654958537"
1094                                         &neighbor_data           "1050792279689258923542019956112129021960"
1095                                         );           "8640344181598136297747713099605187072113"
1096             "4999999837297804995105973173281609631859"
1097           //If there was an error forming up the neighbor data, create a hard error.           "5024459455346908302642522308253344685035"
1098           if (neighbor_data.error)           "2619311881710100031378387528865875332083"
1099              {           "8142061717766914730359825349042875546873"
1100              rv = Tcl_NewStringObj("arbint cfbrapab: unable to form neighbors.", -1);           "1159562863882353787593751957781857780532"
1101              Tcl_SetObjResult(interp, rv);           "1712268066130019278766111959092164201989"
1102             "3809525720106548586327886593615338182796"
1103              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);           "8230301952035301852968995773622599413891"
1104              GMP_RATS_mpq_clear(&q_rn);           "2497217752834791315155748572424541506959"
1105              GMP_INTS_mpz_clear(&z_kmax);           "5082953311686172785588907509838175463746"
1106              GMP_INTS_mpz_clear(&z_hmax);           "4939319255060400927701671139009848824012",
1107             //exp
1108              return(TCL_ERROR);           NULL,
1109              }           //deflen
1110             30,
1111           //Allocate a default buffer of 10K for the ASCII representation of integers.           //digit_count_offset
1112           //In the vast majority of cases, there will be only one allocation, because it           1
1113           //takes a mean integer to exceed 10K.  However, the logic allows it to grow.           },
1114           string_result_n_allocd = 10000;        //sqrt5--the square root of 5.
1115           string_result = TclpAlloc(sizeof(char) * string_result_n_allocd);           {
1116           assert(string_result != NULL);           //tag
1117             "sqrt5",
1118           //Start off with a return value of the null string.           //desc
1119           rv = Tcl_NewStringObj("", -1);           "      The square root of 5.  Digits obtained from\n"
1120             "      http://home.earthlink.net/~maryski/sqrt51000000.txt on 08/17/01.",
1121           //Loop through, spitting out the left neighbors.           //minmant
1122           for (i = neighbor_data.n_left_out-1; i >= 0; i--)           "2.236",
1123              {           //mantrem
1124              //The protocol here is everyone spits out one space before           "0679774997896964091736687312762354406183596115257242708972454105209256378048"
1125              //they print anything.  Must skip this on first loop iteration.           "99414414408378782274969508176150773783504253267724447073863586360121533452708866"
1126              if (i != neighbor_data.n_left_out-1)           "77817319187916581127664532263985658053576135041753378500342339241406444208643253"
1127                 Tcl_AppendToObj(rv, " ", -1);           "90972525926272288762995174024406816117759089094984923713907297288984820886415426"
1128             "89894099131693577019748678884425089754132956183176921499977424801530434115035957"
1129              //The index will be the negative of the iteration variable minus one.           "66833251249881517813940800056242085524354223555610630634282023409333198293395974"
1130              sprintf(sbuf, "%d", -i - 1);           "63522712013417496142026359047378855043896870611356600457571399565955669569175645"
1131              Tcl_AppendToObj(rv, sbuf, -1);           "78221952500060539231234005009286764875529722056766253666074485853505262330678494"
1132                         "63342224231763727702663240768010444331582573350589309813622634319868647194698997"
1133              //Force the buffer to have enough space for the components of the rational           "01808189524264459620345221411922329125981963258111041704958070481204034559949435"
1134              //number.           "06855551855572512388641655010262436312571024449618789424682903404474716115455723"
1135              chars_reqd = INTFUNC_max(           "20173767659046091852957560357798439805415538077906439363972302875606299948221385"
1136                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[i].neighbor.num)),           "21773485924535151210463455550407072278724215347787529112121211843317893351910380",
1137                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[i].neighbor.den))           //exp
1138                                      );           NULL,
1139              if (chars_reqd > string_result_n_allocd)           //deflen
1140                 {           30,
1141                 string_result_n_allocd = chars_reqd;           //digit_count_offset
1142                 string_result = TclpRealloc(string_result, sizeof(char) * string_result_n_allocd);           1
1143                 assert(string_result != NULL);           },
1144                 }        };
1145          
1146              //Print the rational number out to the Tcl object.     Tcl_Obj *rv;
1147              Tcl_AppendToObj(rv, " ", -1);        //Value that will be returned to caller.
1148              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[i].neighbor.num));     int i;
1149              Tcl_AppendToObj(rv, string_result, -1);        //Iteration variable.
1150              Tcl_AppendToObj(rv, "/", -1);     int tbl_idx;
1151              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[i].neighbor.den));        //Index into lookup table, of -1 if not found.
1152              Tcl_AppendToObj(rv, string_result, -1);     int ndigits;
1153              }        //The number of digits to supply.
1154       int result_code;
1155           //Spit out the equality case if appropriate.        //Return value from Tcl library function.
1156           if (neighbor_data.equality)  
1157              {     //We must have either one or two additional arguments.
1158              if (neighbor_data.n_left_out)     if ((objc != 3) && (objc != 4))
1159                 Tcl_AppendToObj(rv, " ", -1);        {
1160          Tcl_WrongNumArgs(interp,
1161              Tcl_AppendToObj(rv, "0", -1);                         2,
1162                                   objv,
1163              //Force the buffer to have enough space for the components of the rational                         "constant_tag ?ndigits?");
1164              //number.        return(TCL_ERROR);
1165              chars_reqd = INTFUNC_max(        }
1166                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.norm_rn.num)),     else
1167                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.norm_rn.den))        {
1168                                      );        char *string_arg;
1169              if (chars_reqd > string_result_n_allocd)  
1170                 {        //Grab a pointer to the string representation of
1171                 string_result_n_allocd = chars_reqd;        //the input argument.  The storage does not belong to us.
1172                 string_result = TclpRealloc(string_result, sizeof(char) * string_result_n_allocd);        string_arg = Tcl_GetString(objv[2]);
1173                 assert(string_result != NULL);        assert(string_arg != NULL);
1174                 }  
1175          //Try to look up the string argument in the table.
1176              //Print the rational number out to the Tcl object.        tbl_idx = -1;
1177              Tcl_AppendToObj(rv, " ", -1);        for (i=0; i<sizeof(tbl)/sizeof(tbl[0]); i++)
1178              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.norm_rn.num));           {
1179              Tcl_AppendToObj(rv, string_result, -1);           if (!strcmp(string_arg, tbl[i].tag))
1180              Tcl_AppendToObj(rv, "/", -1);              {
1181              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.norm_rn.den));              tbl_idx = i;
1182              Tcl_AppendToObj(rv, string_result, -1);              break;
1183              }              }
1184             }
1185           //Loop through, spitting out the right neighbors.  
1186           for (i = 0; i < neighbor_data.n_right_out; i++)        //If the tag was not found in the table, print a hostile
1187              {        //message and abort.
1188              //The protocol here is everyone spits out one space before        if (tbl_idx == -1)
1189              //they print anything.  Must skip this on first loop iteration.           {
1190              if (neighbor_data.n_left_out || neighbor_data.equality || i)           char buf[100];
1191                 Tcl_AppendToObj(rv, " ", -1);  
1192             //Error case.  Must give error message.    
1193              //The index will be the iteration variable plus one.           //Must also list the constants available.
1194              sprintf(sbuf, "%d", i+1);           rv = Tcl_NewStringObj("arbint const: \"", -1);
1195              Tcl_AppendToObj(rv, sbuf, -1);           Tcl_AppendToObj(rv, string_arg, -1);
1196                         Tcl_AppendToObj(rv, "\" is not a recognized constant.\n", -1);
1197              //Force the buffer to have enough space for the components of the rational  
1198              //number.           Tcl_AppendToObj(rv, "Available constants are:\n", -1);
1199              chars_reqd = INTFUNC_max(  
1200                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[i].neighbor.num)),           for (i=0; i<sizeof(tbl)/sizeof(tbl[0]); i++)
1201                                      GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[i].neighbor.den))              {
1202                                      );              Tcl_AppendToObj(rv, "   ", -1);
1203              if (chars_reqd > string_result_n_allocd)              Tcl_AppendToObj(rv, tbl[i].tag, -1);
1204                 {              sprintf(buf, " (%d digits available)\n",
1205                 string_result_n_allocd = chars_reqd;                      strlen(tbl[i].minmant) + strlen(tbl[i].mantrem) - tbl[i].digit_count_offset);
1206                 string_result = TclpRealloc(string_result, sizeof(char) * string_result_n_allocd);              Tcl_AppendToObj(rv, buf, -1);
1207                 assert(string_result != NULL);              Tcl_AppendToObj(rv, tbl[i].desc, -1);
1208                 }              if (i != (sizeof(tbl)/sizeof(tbl[0]) - 1))
1209                   Tcl_AppendToObj(rv, "\n", -1);
1210              //Print the rational number out to the Tcl object.              }
1211              Tcl_AppendToObj(rv, " ", -1);  
1212              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[i].neighbor.num));           Tcl_SetObjResult(interp, rv);
1213              Tcl_AppendToObj(rv, string_result, -1);           return(TCL_ERROR);
1214              Tcl_AppendToObj(rv, "/", -1);           }
1215              GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[i].neighbor.den));  
1216              Tcl_AppendToObj(rv, string_result, -1);        //Make assertions about the string pointers.
1217              }        assert(tbl[tbl_idx].tag     != NULL);
1218          assert(tbl[tbl_idx].desc    != NULL);
1219           //Set up for a normal return.        assert(tbl[tbl_idx].minmant != NULL);
1220           Tcl_SetObjResult(interp, rv);        assert(tbl[tbl_idx].mantrem != NULL);
1221    
1222           TclpFree(string_result);        //Assume the default number of digits by default.
1223           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);        ndigits = tbl[tbl_idx].deflen;
1224           GMP_RATS_mpq_clear(&q_rn);  
1225           GMP_INTS_mpz_clear(&z_kmax);        //If there is an additional parameter, try to interpret
1226           GMP_INTS_mpz_clear(&z_hmax);        //that as the number of digits.
1227          if (objc == 4)
1228           return(TCL_OK);           {
1229           }           //SetIntFromAny(interp, objPtr)
1230        else if (pred_option_specified)           result_code = Tcl_GetIntFromObj(NULL, objv[3], &ndigits);
1231           {  
1232           //Simple predecessor case.           if (result_code != TCL_OK)
1233                {
1234           GMP_RALG_fab_neighbor_collection_struct neighbor_data;              //Could not obtain an integer.  Use hostile error
1235                //message and abort.
1236           //Form up the neighbor data.                    string_arg = Tcl_GetString(objv[3]);
1237           GMP_RALG_consecutive_fab_terms(              assert(string_arg != NULL);
1238                                         &q_rn,  
1239                                         &z_kmax,              rv = Tcl_NewStringObj("arbint const: \"", -1);
1240                                         &z_hmax,              Tcl_AppendToObj(rv, string_arg, -1);
1241                                         1,              Tcl_AppendToObj(rv, "\" is not a recognized integer.", -1);
1242                                         0,              Tcl_SetObjResult(interp, rv);
1243                                         &neighbor_data              return(TCL_ERROR);
1244                                         );              }
1245             }
1246           //If there was an error forming up the neighbor data or there are no left neighbors,  
1247           //create a hard error.        //Ndigits may be corrupt.  We have to be careful below to not
1248           if (neighbor_data.error || !neighbor_data.n_left_out)        //allow any funny stuff.
1249              {        rv = Tcl_NewStringObj(tbl[tbl_idx].minmant, -1);
1250              rv = Tcl_NewStringObj("arbint cfbrapab: unable to find predecessor.", -1);        ndigits = ndigits - strlen(tbl[tbl_idx].minmant) + tbl[tbl_idx].digit_count_offset;
1251              Tcl_SetObjResult(interp, rv);        if (ndigits > 0)
1252             {
1253              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);           if (ndigits >= (int)strlen(tbl[tbl_idx].mantrem))
1254              GMP_RATS_mpq_clear(&q_rn);              {
1255              GMP_INTS_mpz_clear(&z_kmax);              Tcl_AppendToObj(rv, tbl[tbl_idx].mantrem, -1);
1256              GMP_INTS_mpz_clear(&z_hmax);              }
1257             else
1258              return(TCL_ERROR);              {
1259              }              Tcl_AppendToObj(rv, tbl[tbl_idx].mantrem, ndigits);
1260                }
1261           //The test above confirmed that we have at least one left neighbor calculated.           }
1262           //We can dump it to a string and finish up.  
1263           chars_reqd = INTFUNC_max(        //Append the exponent portion.
1264                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[0].neighbor.num)),        if (tbl[tbl_idx].exp)
1265                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.lefts[0].neighbor.den))           Tcl_AppendToObj(rv, tbl[tbl_idx].exp, -1);
1266                                   );  
1267           string_result = TclpAlloc(sizeof(char) * chars_reqd);        //Default successful return.
1268           assert(string_result != NULL);        Tcl_SetObjResult(interp, rv);
1269          return(TCL_OK);
1270           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[0].neighbor.num));        }
1271           rv = Tcl_NewStringObj(string_result, -1);     }
1272           Tcl_AppendToObj(rv, "/", -1);  
1273           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.lefts[0].neighbor.den));  
1274           Tcl_AppendToObj(rv, string_result, -1);  //Handles the "decommanate" subextension.
1275    //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this
1276           Tcl_SetObjResult(interp, rv);  //from memory an intuition as far as how to set return results and so forth.
1277    static
1278           TclpFree(string_result);  int ARBLENINTS_decommanate_handler(ClientData dummy,
1279           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);                                Tcl_Interp *interp,
1280           GMP_RATS_mpq_clear(&q_rn);                                int objc,
1281           GMP_INTS_mpz_clear(&z_kmax);                                Tcl_Obj *objv[])
1282           GMP_INTS_mpz_clear(&z_hmax);     {
1283       Tcl_Obj *rv;
1284           return(TCL_OK);  
1285           }     //We must have one and exactly one additional argument
1286        else if (succ_option_specified)     //to this function, which is the string we want to
1287           {     //decommanate.
1288           //Simple successor.     if (objc != 3)
1289          {
1290           GMP_RALG_fab_neighbor_collection_struct neighbor_data;        Tcl_WrongNumArgs(interp,
1291                           2,
1292           //Form up the neighbor data.                               objv,
1293           GMP_RALG_consecutive_fab_terms(                         "sint");
1294                                         &q_rn,        return(TCL_ERROR);
1295                                         &z_kmax,        }
1296                                         &z_hmax,     else
1297                                         0,        {
1298                                         1,        char *string_arg;
1299                                         &neighbor_data  
1300                                         );        //Grab a pointer to the string representation of
1301          //the input argument.  The storage does not belong to us.
1302           //If there was an error forming up the neighbor data or there are no right neighbors,        string_arg = Tcl_GetString(objv[2]);
1303           //create a hard error.        assert(string_arg != NULL);
1304           if (neighbor_data.error || !neighbor_data.n_right_out)  
1305              {        //Try to parse the string as one of the error tags.
1306              rv = Tcl_NewStringObj("arbint cfbrapab: unable to find successor.", -1);        //If it is one of those, it isn't an error, but don't
1307              Tcl_SetObjResult(interp, rv);        //want to touch the string.
1308          if (GMP_INTS_identify_nan_string(string_arg) >= 0)
1309              GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);           {
1310              GMP_RATS_mpq_clear(&q_rn);           rv = Tcl_NewStringObj(string_arg, -1);
1311              GMP_INTS_mpz_clear(&z_kmax);           Tcl_SetObjResult(interp, rv);
1312              GMP_INTS_mpz_clear(&z_hmax);           return(TCL_OK);
1313             }
1314              return(TCL_ERROR);        //Try to parse it as a signed integer without commas.
1315              }        //If it has no commas, there is no need to decommanate it.
1316          else if (BSTRFUNC_is_sint_wo_commas(string_arg))
1317           //The test above confirmed that we have at least one right neighbor calculated.           {
1318           //We can dump it to a string and finish up.           //This is already an acceptable commanated signed integer.  Send it
1319           chars_reqd = INTFUNC_max(           //back as the return value.
1320                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[0].neighbor.num)),           rv = Tcl_NewStringObj(string_arg, -1);
1321                                   GMP_INTS_mpz_size_in_base_10(&(neighbor_data.rights[0].neighbor.den))           Tcl_SetObjResult(interp, rv);
1322                                   );           return(TCL_OK);
1323           string_result = TclpAlloc(sizeof(char) * chars_reqd);           }
1324           assert(string_result != NULL);        //Try to parse the argument as a signed integer with commas.
1325          //If it is one of those, decommanate it and return it.
1326           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[0].neighbor.num));        else if (BSTRFUNC_is_sint_w_commas(string_arg))
1327           rv = Tcl_NewStringObj(string_result, -1);           {
1328           Tcl_AppendToObj(rv, "/", -1);           size_t len;
1329           GMP_INTS_mpz_to_string(string_result, &(neighbor_data.rights[0].neighbor.den));           char *buffer;
1330           Tcl_AppendToObj(rv, string_result, -1);  
1331             len = strlen(string_arg);
1332           Tcl_SetObjResult(interp, rv);           buffer = TclpAlloc(sizeof(char) * len + 1);
1333             strcpy(buffer, string_arg);
1334           TclpFree(string_result);           BSTRFUNC_decommanate(buffer);
1335           GMP_RALG_consecutive_fab_terms_result_free(&neighbor_data);           rv = Tcl_NewStringObj(buffer, -1);
1336           GMP_RATS_mpq_clear(&q_rn);           TclpFree(buffer);
1337           GMP_INTS_mpz_clear(&z_kmax);           Tcl_SetObjResult(interp, rv);
1338           GMP_INTS_mpz_clear(&z_hmax);           return(TCL_OK);
1339             }
1340           return(TCL_OK);        else
1341           }           {
1342             //Error case.  Must give error message.
1343        //Free up all dynamic memory.           rv = Tcl_NewStringObj("arbint decommanate: \"", -1);
1344        GMP_RATS_mpq_clear(&q_rn);           Tcl_AppendToObj(rv, string_arg, -1);
1345        GMP_INTS_mpz_clear(&z_kmax);           Tcl_AppendToObj(rv, "\" is not a recognized integer.", -1);
1346        GMP_INTS_mpz_clear(&z_hmax);           Tcl_SetObjResult(interp, rv);
1347             return(TCL_ERROR);
1348        //Return           }
1349        return(TCL_OK);        }
1350        }     }
1351     }  
1352    
1353    //Handles the "intadd" subextension.
1354  //Handles the "cfratnum" subextension.  //08/06/01:  Visual inspection OK.
1355  //08/07/01:  Visually inspected, OK.  static
1356  static  int ARBLENINTS_intadd_handler(ClientData dummy,
1357  int ARBLENINTS_cfratnum_handler(ClientData dummy,                                Tcl_Interp *interp,
1358                                Tcl_Interp *interp,                                int objc,
1359                                int objc,                                Tcl_Obj *objv[])
1360                                Tcl_Obj *objv[])     {
1361     {     Tcl_Obj *rv;
1362     Tcl_Obj *rv;  
1363       //We must have two and exactly two additional arguments
1364     //We must have exactly one additional argument     //to this function, which are the integers whose
1365     //to this function, which is the rational number     //sum is to be calculated.
1366     //whose continued fraction decomposition is to be     if (objc != 4)
1367     //calculated.        {
1368     if (objc != 3)        Tcl_WrongNumArgs(interp,
1369        {                         2,
1370        Tcl_WrongNumArgs(interp,                         objv,
1371                         2,                         "sint sint");
1372                         objv,        return(TCL_ERROR);
1373                         "urn");        }
1374        return(TCL_ERROR);     else
1375        }        {
1376     else        GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;
1377        {        char *add_arg1, *add_arg2;
1378        char *input_arg;        int failure1, failure2;
1379        int failure;        unsigned chars_reqd;
1380        unsigned chars_reqd;        char *string_result;
1381        char *string_result;        int i, j;
1382        int n_string_result;  
1383        int i;        //Allocate space for the arbitrary-length integer result.
1384        GMP_RATS_mpq_struct rn;        GMP_INTS_mpz_init(&arb_arg1);
1385        GMP_RALG_cf_app_struct decomp;        GMP_INTS_mpz_init(&arb_arg2);
1386          GMP_INTS_mpz_init(&arb_result);
1387        //In this function, we are going to return a string  
1388        //result formed by starting with a string and then        //Grab pointers to the string representation of
1389        //concatenating  to it again and again.  We start        //the input arguments.  The storage does not belong to us.
1390        //off believing that 10,000 characters of space is enough,        add_arg1 = Tcl_GetString(objv[2]);
1391        //but we may need to revise upward and reallocate.          assert(add_arg1 != NULL);
1392        //A 10,000 character block is chosen because it is quick        add_arg2 = Tcl_GetString(objv[3]);
1393        //to allocate and most times won't go beyond that.        assert(add_arg2 != NULL);
1394        n_string_result = 10000;  
1395        string_result = TclpAlloc(sizeof(char) * n_string_result);        //Try to interpret either of the  strings as one of the NAN tags.
1396        assert(string_result != NULL);        //If it is one, return the appropriate result for
1397          //a binary operation.
1398        //We will need a rational number to hold the return value        i = GMP_INTS_identify_nan_string(add_arg1);
1399        //from the parsing function.  Allocate that now.        j = GMP_INTS_identify_nan_string(add_arg2);
1400        GMP_RATS_mpq_init(&rn);  
1401          if ((i >= 0) || (j >= 0))
1402        //Grab a pointer to the string representation of           {
1403        //the input argument.  The storage does not belong to us.           const char *p;
1404        input_arg = Tcl_GetString(objv[2]);  
1405        assert(input_arg != NULL);           //Find the max of i and j.  This isn't a scientific way to tag the
1406             //result, but will be OK.  Some information is lost no matter what
1407        //Try to parse our input string as a rational number.           //we do.
1408        //If we are not successful in this, must abort.           if (i > j)
1409        GMP_RATS_mpq_set_all_format_rat_num(input_arg,              ;
1410                                            &failure,           else
1411                                            &rn);              i = j;
1412    
1413        if (failure)           //i now contains the max.
1414           {           switch (i)
1415           rv = Tcl_NewStringObj("arbint cfratnum: \"", -1);              {
1416           Tcl_AppendToObj(rv, input_arg, -1);              case 0:  p = GMP_INTS_supply_nan_string(2);
1417                         break;
1418           Tcl_AppendToObj(rv, "\" is not a recognized non-negative rational number.", -1);              case 1:  p = GMP_INTS_supply_nan_string(3);
1419           Tcl_SetObjResult(interp, rv);                       break;
1420                case 2:  p = GMP_INTS_supply_nan_string(2);
1421           TclpFree(string_result);                       break;
1422           GMP_RATS_mpq_clear(&rn);              case 3:  p = GMP_INTS_supply_nan_string(3);
1423                         break;
1424           return(TCL_ERROR);              default:
1425           }                       assert(0);
1426                         break;
1427        //OK, we have a rational number, but there is a possibility              }
1428        //it is negative, which is a no-no.  Normalize the signs  
1429        //for easier testing.           rv = Tcl_NewStringObj(p, -1);
1430        GMP_RATS_mpq_normalize_sign(&rn);           Tcl_SetObjResult(interp, rv);
1431        if (GMP_INTS_mpz_is_neg(&(rn.num)))  
1432           {           GMP_INTS_mpz_clear(&arb_arg1);
1433           rv = Tcl_NewStringObj("arbint cfratnum: \"", -1);           GMP_INTS_mpz_clear(&arb_arg2);
1434           Tcl_AppendToObj(rv, input_arg, -1);           GMP_INTS_mpz_clear(&arb_result);
1435    
1436           Tcl_AppendToObj(rv, "\" is negative.", -1);           return(TCL_OK);
1437           Tcl_SetObjResult(interp, rv);           }
1438    
1439           TclpFree(string_result);        //Try to convert both strings into arbitrary integers.
1440           GMP_RATS_mpq_clear(&rn);        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, add_arg1);
1441          GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, add_arg2);
1442           return(TCL_ERROR);  
1443           }        //If there was a parse failure, we have to return an error
1444          //message.  It is possible that both arguments failed the parse,
1445        //OK, we have a rational number.  Form the continued fraction        //but only return one in the error message.
1446        //decomposition of it.  The function called is set up so that        if (failure1 || failure2)
1447        //one must deallocate, even in an error condition.           {
1448        GMP_RALG_cfdecomp_init(&decomp,           rv = Tcl_NewStringObj("arbint intadd: \"", -1);
1449                               &failure,           if (failure1)
1450                               &(rn.num),              Tcl_AppendToObj(rv, add_arg1, -1);
1451                               &(rn.den));           else
1452                Tcl_AppendToObj(rv, add_arg2, -1);
1453        //If we failed in the decomposition (don't know why that would  
1454        //happen) use the general error flag "NAN".           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
1455        if (failure)           Tcl_SetObjResult(interp, rv);
1456           {  
1457           rv = Tcl_NewStringObj("NAN", -1);           GMP_INTS_mpz_clear(&arb_arg1);
1458             GMP_INTS_mpz_clear(&arb_arg2);
1459           Tcl_SetObjResult(interp, rv);           GMP_INTS_mpz_clear(&arb_result);
1460    
1461           TclpFree(string_result);           return(TCL_ERROR);
1462           GMP_RATS_mpq_clear(&rn);           }
1463           GMP_RALG_cfdecomp_destroy(&decomp);  
1464          //Calculate the sum.
1465           return(TCL_ERROR);        GMP_INTS_mpz_add(&arb_result, &arb_arg1, &arb_arg2);
1466           }  
1467          //Figure out the number of characters required for
1468        //OK, that really is the last error we could have.        //the output string.
1469        //Iterate, adding the partial quotients and convergents        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);
1470        //to the string which we'll return.  We need to watch out  
1471        //for running over our 10K buffer.        //Allocate space for the conversion result.
1472        rv = Tcl_NewStringObj("", -1);        string_result = TclpAlloc(sizeof(char) * chars_reqd);
1473        for (i=0; i<decomp.n; i++)        assert(string_result != NULL);
1474           {  
1475           //Partial quotient.        //Make the conversion to a character string.
1476           chars_reqd = GMP_INTS_mpz_size_in_base_10(&(decomp.a[i]));        GMP_INTS_mpz_to_string(string_result, &arb_result);
1477           if (chars_reqd > (unsigned)n_string_result)  
1478              {        //Assign the string result to a Tcl object.
1479              n_string_result = chars_reqd;        rv = Tcl_NewStringObj(string_result, -1);
1480              string_result = TclpRealloc(string_result,  
1481                                          sizeof(char) * n_string_result);        //Deallocate the string.
1482              }        TclpFree(string_result);
1483           GMP_INTS_mpz_to_string(string_result, &(decomp.a[i]));  
1484           Tcl_AppendToObj(rv, string_result, -1);        //Deallocate space for the arbitrary-length integers.
1485           Tcl_AppendToObj(rv, " ", -1);        GMP_INTS_mpz_clear(&arb_arg1);
1486          GMP_INTS_mpz_clear(&arb_arg2);
1487           //Numerator of convergent.        GMP_INTS_mpz_clear(&arb_result);
1488           chars_reqd = GMP_INTS_mpz_size_in_base_10(&(decomp.p[i]));  
1489           if (chars_reqd > (unsigned)n_string_result)        //Assign the result to be the return value.
1490              {        Tcl_SetObjResult(interp, rv);
1491              n_string_result = chars_reqd;  
1492              string_result = TclpRealloc(string_result,        //Return
1493                                          sizeof(char) * n_string_result);        return(TCL_OK);
1494              }        }
1495           GMP_INTS_mpz_to_string(string_result, &(decomp.p[i]));     }
1496           Tcl_AppendToObj(rv, string_result, -1);  
1497           Tcl_AppendToObj(rv, " ", -1);  
1498    //08/01/01:  Visual inspection and some unit testing, OK.
1499           //Denominator of convergent.  //Handles the "intcmp" subextension.
1500           chars_reqd = GMP_INTS_mpz_size_in_base_10(&(decomp.q[i]));  static
1501           if (chars_reqd > (unsigned)n_string_result)  int ARBLENINTS_intcmp_handler(ClientData dummy,
1502              {                                Tcl_Interp *interp,
1503              n_string_result = chars_reqd;                                int objc,
1504              string_result = TclpRealloc(string_result,                                Tcl_Obj *objv[])
1505                                          sizeof(char) * n_string_result);     {
1506              }     Tcl_Obj *rv;
1507           GMP_INTS_mpz_to_string(string_result, &(decomp.q[i]));  
1508           Tcl_AppendToObj(rv, string_result, -1);     //We must have two and exactly two additional arguments
1509           if (i != (decomp.n - 1)) //No space after last number.     //to this function, which are the integers to be compared.
1510              Tcl_AppendToObj(rv, " ", -1);     if (objc != 4)
1511           }        {
1512          Tcl_WrongNumArgs(interp,
1513        //Assign the result to be the return value.                         2,
1514        Tcl_SetObjResult(interp, rv);                         objv,
1515                           "sint sint");
1516        //Free up all dynamic memory.        return(TCL_ERROR);
1517        TclpFree(string_result);        }
1518        GMP_RATS_mpq_clear(&rn);     else
1519        GMP_RALG_cfdecomp_destroy(&decomp);        {
1520          GMP_INTS_mpz_struct arb_arg1, arb_arg2;
1521        //Return        char *cmp_arg1, *cmp_arg2;
1522        return(TCL_OK);        int failure1, failure2;
1523        }        int i, j, compare_result;
1524     }  
1525          //Allocate space for the arbitrary-length integer result.
1526          GMP_INTS_mpz_init(&arb_arg1);
1527  //Handles the "commanate" subextension.        GMP_INTS_mpz_init(&arb_arg2);
1528  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this  
1529  //from memory an intuition as far as how to set return results and so forth.        //Grab pointers to the string representation of
1530  static        //the input arguments.  The storage does not belong to us.
1531  int ARBLENINTS_commanate_handler(ClientData dummy,        cmp_arg1 = Tcl_GetString(objv[2]);
1532                                Tcl_Interp *interp,        assert(cmp_arg1 != NULL);
1533                                int objc,        cmp_arg2 = Tcl_GetString(objv[3]);
1534                                Tcl_Obj *objv[])        assert(cmp_arg2 != NULL);
1535     {  
1536     Tcl_Obj *rv;        //Try to interpret either of the  strings as one of the NAN tags.
1537          //We cannot compare NAN tags.  If either is a NAN tag, we must signal an
1538     //We must have one and exactly one additional argument        //error.
1539     //to this function, which is the string we want to        i = GMP_INTS_identify_nan_string(cmp_arg1);
1540     //commanate.        j = GMP_INTS_identify_nan_string(cmp_arg2);
1541     if (objc != 3)  
1542        {        if ((i >= 0) || (j >= 0))
1543        Tcl_WrongNumArgs(interp,           {
1544                         2,           rv = Tcl_NewStringObj("arbint intcmp: cannot compare NAN symbolic tags.", -1);
1545                         objv,           Tcl_SetObjResult(interp, rv);
1546                         "sint");  
1547        return(TCL_ERROR);           GMP_INTS_mpz_clear(&arb_arg1);
1548        }           GMP_INTS_mpz_clear(&arb_arg2);
1549     else  
1550        {           return(TCL_ERROR);
1551        char *string_arg;           }
1552    
1553        //Grab a pointer to the string representation of        //Try to convert both strings into arbitrary integers.
1554        //the input argument.  The storage does not belong to us.        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, cmp_arg1);
1555        string_arg = Tcl_GetString(objv[2]);        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, cmp_arg2);
1556        assert(string_arg != NULL);  
1557          //If there was a parse failure, we have to return an error
1558        //Try to parse the string as one of the error tags.        //message.  It is possible that both arguments failed the parse,
1559        //If it is one of those, it isn't an error, but don't        //but only return one in the error message.
1560        //want to touch the string.        if (failure1 || failure2)
1561        if (GMP_INTS_identify_nan_string(string_arg) >= 0)           {
1562           {           rv = Tcl_NewStringObj("arbint intcmp: \"", -1);
1563           rv = Tcl_NewStringObj(string_arg, -1);           if (failure1)
1564           Tcl_SetObjResult(interp, rv);              Tcl_AppendToObj(rv, cmp_arg1, -1);
1565           return(TCL_OK);           else
1566           }              Tcl_AppendToObj(rv, cmp_arg2, -1);
1567        //Try to parse it as a signed integer with commas already.  
1568        //If it already has commas, there is no need to add any.           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
1569        else if (BSTRFUNC_is_sint_w_commas(string_arg))           Tcl_SetObjResult(interp, rv);
1570           {  
1571           //This is already an acceptable commanated signed integer.  Send it           GMP_INTS_mpz_clear(&arb_arg1);
1572           //back as the return value.           GMP_INTS_mpz_clear(&arb_arg2);
1573           rv = Tcl_NewStringObj(string_arg, -1);  
1574           Tcl_SetObjResult(interp, rv);           return(TCL_ERROR);
1575           return(TCL_OK);           }
1576           }  
1577        //Try to parse the argument as a signed integer without commas.        //Calculate the compare result.
1578        //If it is one of those, commanate it and return it.        compare_result = GMP_INTS_mpz_cmp(&arb_arg1, &arb_arg2);
1579        else if (BSTRFUNC_is_sint_wo_commas(string_arg))  
1580           {        //Assign the return value based on the result.
1581           size_t len;        if (compare_result < 0)
1582           char *buffer;           rv = Tcl_NewStringObj("-1", -1);
1583          else if (compare_result == 0)
1584           len = strlen(string_arg);           rv = Tcl_NewStringObj("0", -1);
1585           buffer = TclpAlloc(((sizeof(char) * 4 * len) / 3) + 10);        else
1586           strcpy(buffer, string_arg);           rv = Tcl_NewStringObj("1", -1);
1587           BSTRFUNC_commanate(buffer);  
1588           rv = Tcl_NewStringObj(buffer, -1);        //Deallocate space for the arbitrary-length integers.
1589           TclpFree(buffer);        GMP_INTS_mpz_clear(&arb_arg1);
1590           Tcl_SetObjResult(interp, rv);        GMP_INTS_mpz_clear(&arb_arg2);
1591           return(TCL_OK);  
1592           }        //Assign the result to be the return value.
1593        else        Tcl_SetObjResult(interp, rv);
1594           {  
1595           //Error case.  Must give error message.        //Return
1596           rv = Tcl_NewStringObj("arbint commanate: \"", -1);        return(TCL_OK);
1597           Tcl_AppendToObj(rv, string_arg, -1);        }
1598           Tcl_AppendToObj(rv, "\" is not a recognized integer.", -1);     }
1599           Tcl_SetObjResult(interp, rv);  
1600           return(TCL_ERROR);  
1601           }  //Handles the "intdiv" subextension.
1602        }  //07/31/01:  Visually inspected, OK.
1603     }  static
1604    int ARBLENINTS_intdiv_handler(ClientData dummy,
1605                                  Tcl_Interp *interp,
1606  //Handles the "const" subextension.                                int objc,
1607  //08/17/01: Visual inspection OK.                                Tcl_Obj *objv[])
1608  static     {
1609  int ARBLENINTS_const_handler(ClientData dummy,     Tcl_Obj *rv;
1610                               Tcl_Interp *interp,  
1611                               int objc,     //We must have two and exactly two additional arguments
1612                               Tcl_Obj *objv[])     //to this function, which are the integers whose
1613     {     //integer quotient is to be calculated.
1614     //Table of constants used.     if (objc != 4)
1615     static struct        {
1616        {        Tcl_WrongNumArgs(interp,
1617        char *tag;                         2,
1618           //The symbolic tag used to identify the number.                         objv,
1619        char *desc;                         "sint sint");
1620           //The full description of the number.  It must consist        return(TCL_ERROR);
1621           //of a string with lines no longer than about 70 chars,        }
1622           //separated by newlines, and indented by 6 spaces.     else
1623        char *minmant;        {
1624           //The minimum mantissa or minimum representation.        GMP_INTS_mpz_struct arb_dividend, arb_divisor, arb_quotient, arb_remainder;
1625           //May not be empty or NULL.        char *dividend_arg1, *divisor_arg2;
1626        char *mantrem;        int failure1, failure2;
1627           //The remaining mantissa or remaining portion of        unsigned chars_reqd;
1628           //number.  May be empty, but may not be NULL.        char *string_result;
1629        char *exp;        int i, j;
1630           //The exponent portion, if any, or NULL otherwise.  
1631        int deflen;        //Allocate space for the arbitrary-length integer arguments and results.
1632           //The default number of digits for the constant        GMP_INTS_mpz_init(&arb_dividend);
1633           //if none is specified.        GMP_INTS_mpz_init(&arb_divisor);
1634        int digit_count_offset;        GMP_INTS_mpz_init(&arb_quotient);
1635           //The offset to go from string length of mantissa        GMP_INTS_mpz_init(&arb_remainder);
1636           //portions to number of digits.  Cheap way to adjust  
1637           //for - sign and decimal point.        //Grab pointers to the string representation of
1638        } tbl[] =        //the input arguments.  The storage does not belong to us.
1639        {        dividend_arg1 = Tcl_GetString(objv[2]);
1640        //e--the transcendental number e.        assert(dividend_arg1 != NULL);
1641           {        divisor_arg2 = Tcl_GetString(objv[3]);
1642           //tag        assert(divisor_arg2 != NULL);
1643           "e",  
1644           //desc        //Try to interpret either of the  strings as one of the NAN tags.
1645           "      Historically significant transcendental constant.  Digits obtained\n"        //If it is one, return the appropriate result for
1646           "      from http://fermi.udw.ac.za/physics/e.html on 08/17/01.",        //a binary operation.
1647           //minmant        i = GMP_INTS_identify_nan_string(dividend_arg1);
1648           "2.7",        j = GMP_INTS_identify_nan_string(divisor_arg2);
1649           //mantrem  
1650           "182818284590452353602874713526624977572470936999595749669676277240766303535"        if ((i >= 0) || (j >= 0))
1651           "475945713821785251664274274663919320030599218174135966290435729003342952605956"           {
1652           "307381323286279434907632338298807531952510190115738341879307021540891499348841"           const char *p;
1653           "675092447614606680822648001684774118537423454424371075390777449920695517027618"  
1654           "386062613313845830007520449338265602976067371132007093287091274437470472306969"           //Find the max of i and j.  This isn't a scientific way to tag the
1655           "772093101416928368190255151086574637721112523897844250569536967707854499699679"           //result, but will be OK.  Some information is lost no matter what
1656           "468644549059879316368892300987931277361782154249992295763514822082698951936680"           //we do.
1657           "331825288693984964651058209392398294887933203625094431173012381970684161403970"           if (i > j)
1658           "198376793206832823764648042953118023287825098194558153017567173613320698112509"              ;
1659           "961818815930416903515988885193458072738667385894228792284998920868058257492796"           else
1660           "104841984443634632449684875602336248270419786232090021609902353043699418491463"              i = j;
1661           "140934317381436405462531520961836908887070167683964243781405927145635490613031"  
1662           "07208510383750510115747704171898610687396965521267154688957035035",           //i now contains the max.
1663           //exp           switch (i)
1664           NULL,              {
1665           //deflen              case 0:  p = GMP_INTS_supply_nan_string(2);
1666           30,                       break;
1667           //digit_count_offset              case 1:  p = GMP_INTS_supply_nan_string(3);
1668           1                       break;
1669           },              case 2:  p = GMP_INTS_supply_nan_string(2);
1670        //g_metric                       break;
1671           {              case 3:  p = GMP_INTS_supply_nan_string(3);
1672           //tag                       break;
1673           "g_si",              default:
1674           //desc                       assert(0);
1675           "      Gravitational acceleration in SI units, meters per second**2.\n"                       break;
1676           "      Obtained from NIST Special Publication 811 on 08/17/01.",              }
1677           //minmant  
1678           "9.80665",           rv = Tcl_NewStringObj(p, -1);
1679           //mantrem           Tcl_SetObjResult(interp, rv);
1680           "",  
1681           //exp           GMP_INTS_mpz_clear(&arb_dividend);
1682           NULL,           GMP_INTS_mpz_clear(&arb_divisor);
1683           //deflen           GMP_INTS_mpz_clear(&arb_quotient);
1684           30,           GMP_INTS_mpz_clear(&arb_remainder);
1685           //digit_count_offset  
1686           1           return(TCL_OK);
1687           },           }
1688        //in2m  
1689           {        //Try to convert both strings into arbitrary integers.
1690           //tag        GMP_INTS_mpz_set_general_int(&arb_dividend, &failure1, dividend_arg1);
1691           "in2m",        GMP_INTS_mpz_set_general_int(&arb_divisor,  &failure2, divisor_arg2);
1692           //desc  
1693           "      Multiplicative conversion factor from inches to meters.\n"        //If there was a parse failure, we have to return an error
1694           "      Obtained from NIST Special Publication 811 on 08/17/01.",        //message.  It is possible that both arguments failed the parse,
1695           //minmant        //but only return one in the error message.
1696           "2.54",        if (failure1 || failure2)
1697           //mantrem           {
1698           "",           rv = Tcl_NewStringObj("arbint intdiv: \"", -1);
1699           //exp           if (failure1)
1700           "e-2",              Tcl_AppendToObj(rv, dividend_arg1, -1);
1701           //deflen           else
1702           30,              Tcl_AppendToObj(rv, divisor_arg2, -1);
1703           //digit_count_offset  
1704           1           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
1705           },           Tcl_SetObjResult(interp, rv);
1706        //mi2km  
1707           {           GMP_INTS_mpz_clear(&arb_dividend);
1708           //tag           GMP_INTS_mpz_clear(&arb_divisor);
1709           "mi2km",           GMP_INTS_mpz_clear(&arb_quotient);
1710           //desc           GMP_INTS_mpz_clear(&arb_remainder);
1711           "      Multiplicative conversion factor from miles to kilometers.\n"  
1712           "      Obtained from NIST Special Publication 811 on 08/17/01.",           return(TCL_ERROR);
1713           //minmant           }
1714           "1.609344",  
1715           //mantrem        //Calculate the quotient.
1716           "",        GMP_INTS_mpz_tdiv_qr(&arb_quotient, &arb_remainder, &arb_dividend, &arb_divisor);
1717           //exp  
1718           NULL,        //Figure out the number of characters required for
1719           //deflen        //the output string.
1720           30,        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_quotient);
1721           //digit_count_offset  
1722           1        //Allocate space for the conversion result.
1723           },        string_result = TclpAlloc(sizeof(char) * chars_reqd);
1724        //pi--the transcendental number PI.        assert(string_result != NULL);
1725           {  
1726           //tag        //Make the conversion to a character string.
1727           "pi",        GMP_INTS_mpz_to_string(string_result, &arb_quotient);
1728           //desc  
1729           "      Transcendental constant supplying ratio of a circle's circumference\n"        //Assign the string result to a Tcl object.
1730           "      to its diameter.  Digits obtained from http://www.joyofpi.com/\n"        rv = Tcl_NewStringObj(string_result, -1);
1731           "      pi.htm on 08/17/01.",  
1732           //minmant        //Deallocate the string.
1733           "3.14",        TclpFree(string_result);
1734           //mantrem  
1735           "15926535897932384626433832795028841971"        //Deallocate space for the arbitrary-length integers.
1736           "6939937510582097494459230781640628620899"        GMP_INTS_mpz_clear(&arb_dividend);
1737           "8628034825342117067982148086513282306647"        GMP_INTS_mpz_clear(&arb_divisor);
1738           "0938446095505822317253594081284811174502"        GMP_INTS_mpz_clear(&arb_quotient);
1739           "8410270193852110555964462294895493038196"        GMP_INTS_mpz_clear(&arb_remainder);
1740           "4428810975665933446128475648233786783165"  
1741           "2712019091456485669234603486104543266482"        //Assign the result to be the return value.
1742           "1339360726024914127372458700660631558817"        Tcl_SetObjResult(interp, rv);
1743           "4881520920962829254091715364367892590360"  
1744           "0113305305488204665213841469519415116094"        //Return
1745           "3305727036575959195309218611738193261179"        return(TCL_OK);
1746           "3105118548074462379962749567351885752724"        }
1747           "8912279381830119491298336733624406566430"     }
1748           "8602139494639522473719070217986094370277"  
1749           "0539217176293176752384674818467669405132"  
1750           "0005681271452635608277857713427577896091"  //08/01/01:  Visually inspected.
1751           "7363717872146844090122495343014654958537"  //Handles the "intexp" subextension.
1752           "1050792279689258923542019956112129021960"  static
1753           "8640344181598136297747713099605187072113"  int ARBLENINTS_intexp_handler(ClientData dummy,
1754           "4999999837297804995105973173281609631859"                                Tcl_Interp *interp,
1755           "5024459455346908302642522308253344685035"                                int objc,
1756           "2619311881710100031378387528865875332083"                                Tcl_Obj *objv[])
1757           "8142061717766914730359825349042875546873"     {
1758           "1159562863882353787593751957781857780532"     Tcl_Obj *rv;
1759           "1712268066130019278766111959092164201989"  
1760           "3809525720106548586327886593615338182796"     //We must have two and exactly two additional arguments
1761           "8230301952035301852968995773622599413891"     //to this function, which are the integers used to
1762           "2497217752834791315155748572424541506959"     //calculate the exponential.
1763           "5082953311686172785588907509838175463746"     if (objc != 4)
1764           "4939319255060400927701671139009848824012",        {
1765           //exp        Tcl_WrongNumArgs(interp,
1766           NULL,                         2,
1767           //deflen                         objv,
1768           30,                         "sint uint32");
1769           //digit_count_offset        return(TCL_ERROR);
1770           1        }
1771           },     else
1772        //sqrt5--the square root of 5.        {
1773           {        GMP_INTS_mpz_struct arb_arg1, arb_result;
1774           //tag        unsigned arg2;
1775           "sqrt5",        char *str_arg1, *str_arg2;
1776           //desc        int failure1, failure2;
1777           "      The square root of 5.  Digits obtained from\n"        unsigned chars_reqd;
1778           "      http://home.earthlink.net/~maryski/sqrt51000000.txt on 08/17/01.",        char *string_result;
1779           //minmant        int i, j;
1780           "2.236",  
1781           //mantrem        //Allocate space for the arbitrary-length integers.
1782           "0679774997896964091736687312762354406183596115257242708972454105209256378048"        GMP_INTS_mpz_init(&arb_arg1);
1783           "99414414408378782274969508176150773783504253267724447073863586360121533452708866"        GMP_INTS_mpz_init(&arb_result);
1784           "77817319187916581127664532263985658053576135041753378500342339241406444208643253"  
1785           "90972525926272288762995174024406816117759089094984923713907297288984820886415426"        //Grab pointers to the string representation of
1786           "89894099131693577019748678884425089754132956183176921499977424801530434115035957"        //the input arguments.  The storage does not belong to us.
1787           "66833251249881517813940800056242085524354223555610630634282023409333198293395974"        str_arg1 = Tcl_GetString(objv[2]);
1788           "63522712013417496142026359047378855043896870611356600457571399565955669569175645"        assert(str_arg1 != NULL);
1789           "78221952500060539231234005009286764875529722056766253666074485853505262330678494"        str_arg2 = Tcl_GetString(objv[3]);
1790           "63342224231763727702663240768010444331582573350589309813622634319868647194698997"        assert(str_arg2 != NULL);
1791           "01808189524264459620345221411922329125981963258111041704958070481204034559949435"  
1792           "06855551855572512388641655010262436312571024449618789424682903404474716115455723"        //Try to interpret either of the  strings as one of the NAN tags.
1793           "20173767659046091852957560357798439805415538077906439363972302875606299948221385"        //If it is one, return the appropriate result for
1794           "21773485924535151210463455550407072278724215347787529112121211843317893351910380",        //a binary operation.
1795           //exp        i = GMP_INTS_identify_nan_string(str_arg1);
1796           NULL,        j = GMP_INTS_identify_nan_string(str_arg2);
1797           //deflen  
1798           30,        if ((i >= 0) || (j >= 0))
1799           //digit_count_offset           {
1800           1           const char *p;
1801           },  
1802        };           //Find the max of i and j.  This isn't a scientific way to tag the
1803                   //result, but will be OK.  Some information is lost no matter what
1804     Tcl_Obj *rv;           //we do.
1805        //Value that will be returned to caller.           if (i > j)
1806     int i;              ;
1807        //Iteration variable.           else
1808     int tbl_idx;              i = j;
1809        //Index into lookup table, of -1 if not found.  
1810     int ndigits;           //i now contains the max.
1811        //The number of digits to supply.           switch (i)
1812     int result_code;              {
1813        //Return value from Tcl library function.              case 0:  p = GMP_INTS_supply_nan_string(2);
1814                         break;
1815     //We must have either one or two additional arguments.              case 1:  p = GMP_INTS_supply_nan_string(3);
1816     if ((objc != 3) && (objc != 4))                       break;
1817        {              case 2:  p = GMP_INTS_supply_nan_string(2);
1818        Tcl_WrongNumArgs(interp,                       break;
1819                         2,              case 3:  p = GMP_INTS_supply_nan_string(3);
1820                         objv,                       break;
1821                         "constant_tag ?ndigits?");              default:
1822        return(TCL_ERROR);                       assert(0);
1823        }                       break;
1824     else              }
1825        {  
1826        char *string_arg;           rv = Tcl_NewStringObj(p, -1);
1827             Tcl_SetObjResult(interp, rv);
1828        //Grab a pointer to the string representation of  
1829        //the input argument.  The storage does not belong to us.           GMP_INTS_mpz_clear(&arb_arg1);
1830        string_arg = Tcl_GetString(objv[2]);           GMP_INTS_mpz_clear(&arb_result);
1831        assert(string_arg != NULL);  
1832             return(TCL_OK);
1833        //Try to look up the string argument in the table.           }
1834        tbl_idx = -1;  
1835        for (i=0; i<sizeof(tbl)/sizeof(tbl[0]); i++)        //Try to convert the first string into arbitrary integers.
1836           {        //The first string can be anything, including zero or a negative
1837           if (!strcmp(string_arg, tbl[i].tag))        //arugument.
1838              {        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, str_arg1);
1839              tbl_idx = i;  
1840              break;        //If the conversion of the first string did not go alright,
1841              }        //print error message and abort.
1842           }        if (failure1)
1843             {
1844        //If the tag was not found in the table, print a hostile           rv = Tcl_NewStringObj("arbint intexp: \"", -1);
1845        //message and abort.           Tcl_AppendToObj(rv, str_arg1, -1);
1846        if (tbl_idx == -1)           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
1847           {           Tcl_SetObjResult(interp, rv);
1848           char buf[100];  
1849             GMP_INTS_mpz_clear(&arb_arg1);
1850           //Error case.  Must give error message.               GMP_INTS_mpz_clear(&arb_result);
1851           //Must also list the constants available.  
1852           rv = Tcl_NewStringObj("arbint const: \"", -1);           return(TCL_ERROR);
1853           Tcl_AppendToObj(rv, string_arg, -1);           }
1854           Tcl_AppendToObj(rv, "\" is not a recognized constant.\n", -1);  
1855    
1856           Tcl_AppendToObj(rv, "Available constants are:\n", -1);        //Try to convert the second string into an unsigned 32-bit
1857          //integer.
1858           for (i=0; i<sizeof(tbl)/sizeof(tbl[0]); i++)        GMP_INTS_mpz_parse_into_uint32(&arg2, &failure2, str_arg2);
1859              {  
1860              Tcl_AppendToObj(rv, "   ", -1);        //If the conversion of the second string did not go alright,
1861              Tcl_AppendToObj(rv, tbl[i].tag, -1);        //print error message and abort.
1862              sprintf(buf, " (%d digits available)\n",        if (failure2)
1863                      strlen(tbl[i].minmant) + strlen(tbl[i].mantrem) - tbl[i].digit_count_offset);           {
1864              Tcl_AppendToObj(rv, buf, -1);           rv = Tcl_NewStringObj("arbint intexp: \"", -1);
1865              Tcl_AppendToObj(rv, tbl[i].desc, -1);           Tcl_AppendToObj(rv, str_arg2, -1);
1866              if (i != (sizeof(tbl)/sizeof(tbl[0]) - 1))           Tcl_AppendToObj(rv, "\" is not a recognized unsigned 32-bit integer.", -1);
1867                 Tcl_AppendToObj(rv, "\n", -1);           Tcl_SetObjResult(interp, rv);
1868              }  
1869             GMP_INTS_mpz_clear(&arb_arg1);
1870           Tcl_SetObjResult(interp, rv);           GMP_INTS_mpz_clear(&arb_result);
1871           return(TCL_ERROR);  
1872           }           return(TCL_ERROR);
1873             }
1874        //Make assertions about the string pointers.  
1875        assert(tbl[tbl_idx].tag     != NULL);        //Calculate the exponential.
1876        assert(tbl[tbl_idx].desc    != NULL);        GMP_INTS_mpz_pow_ui(&arb_result, &arb_arg1, arg2);
1877        assert(tbl[tbl_idx].minmant != NULL);  
1878        assert(tbl[tbl_idx].mantrem != NULL);        //Figure out the number of characters required for
1879          //the output string.
1880        //Assume the default number of digits by default.        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);
1881        ndigits = tbl[tbl_idx].deflen;  
1882          //Allocate space for the conversion result.
1883        //If there is an additional parameter, try to interpret        string_result = TclpAlloc(sizeof(char) * chars_reqd);
1884        //that as the number of digits.        assert(string_result != NULL);
1885        if (objc == 4)  
1886           {        //Make the conversion to a character string.
1887           //SetIntFromAny(interp, objPtr)        GMP_INTS_mpz_to_string(string_result, &arb_result);
1888           result_code = Tcl_GetIntFromObj(NULL, objv[3], &ndigits);  
1889          //Assign the string result to a Tcl object.
1890           if (result_code != TCL_OK)        rv = Tcl_NewStringObj(string_result, -1);
1891              {  
1892              //Could not obtain an integer.  Use hostile error        //Deallocate the string.
1893              //message and abort.        TclpFree(string_result);
1894              string_arg = Tcl_GetString(objv[3]);  
1895              assert(string_arg != NULL);        //Deallocate space for the arbitrary-length integers.
1896          GMP_INTS_mpz_clear(&arb_arg1);
1897              rv = Tcl_NewStringObj("arbint const: \"", -1);        GMP_INTS_mpz_clear(&arb_result);
1898              Tcl_AppendToObj(rv, string_arg, -1);  
1899              Tcl_AppendToObj(rv, "\" is not a recognized integer.", -1);        //Assign the result to be the return value.
1900              Tcl_SetObjResult(interp, rv);        Tcl_SetObjResult(interp, rv);
1901              return(TCL_ERROR);  
1902              }        //Return
1903           }        return(TCL_OK);
1904          }
1905        //Ndigits may be corrupt.  We have to be careful below to not     }
1906        //allow any funny stuff.  
1907        rv = Tcl_NewStringObj(tbl[tbl_idx].minmant, -1);  
1908        ndigits = ndigits - strlen(tbl[tbl_idx].minmant) + tbl[tbl_idx].digit_count_offset;  //Handles the "intfac" subextension.
1909        if (ndigits > 0)  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this
1910           {  //from memory an intuition as far as how to set return results and so forth.
1911           if (ndigits >= (int)strlen(tbl[tbl_idx].mantrem))  static
1912              {  int ARBLENINTS_intfac_handler(ClientData dummy,
1913              Tcl_AppendToObj(rv, tbl[tbl_idx].mantrem, -1);                                Tcl_Interp *interp,
1914              }                                int objc,
1915           else                                Tcl_Obj *objv[])
1916              {     {
1917              Tcl_AppendToObj(rv, tbl[tbl_idx].mantrem, ndigits);     Tcl_Obj *rv;
1918              }  
1919           }     //We must have one and exactly one additional argument
1920       //to this function, which is the integer whose
1921        //Append the exponent portion.     //factorial is to be evaluated.
1922        if (tbl[tbl_idx].exp)     if (objc != 3)
1923           Tcl_AppendToObj(rv, tbl[tbl_idx].exp, -1);        {
1924          Tcl_WrongNumArgs(interp,
1925        //Default successful return.                         2,
1926        Tcl_SetObjResult(interp, rv);                         objv,
1927        return(TCL_OK);                         "uint32");
1928        }        return(TCL_ERROR);
1929     }        }
1930       else
1931          {
1932  //Handles the "decommanate" subextension.        GMP_INTS_mpz_struct arb_result;
1933  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this        char *fac_arg;
1934  //from memory an intuition as far as how to set return results and so forth.        int failure;
1935  static        unsigned fac_ui_arg;
1936  int ARBLENINTS_decommanate_handler(ClientData dummy,        unsigned chars_reqd;
1937                                Tcl_Interp *interp,        char *string_result;
1938                                int objc,        int i;
1939                                Tcl_Obj *objv[])  
1940     {        //Allocate space for the arbitrary-length integer result.
1941     Tcl_Obj *rv;        GMP_INTS_mpz_init(&arb_result);
1942    
1943     //We must have one and exactly one additional argument        //Grab a pointer to the string representation of
1944     //to this function, which is the string we want to        //the input argument.  The storage does not belong to us.
1945     //decommanate.        fac_arg = Tcl_GetString(objv[2]);
1946     if (objc != 3)        assert(fac_arg != NULL);
1947        {  
1948        Tcl_WrongNumArgs(interp,        //Try to interpret the string as one of the NAN tags.
1949                         2,        //If it is one, return the appropriate result for
1950                         objv,        //a unary operation.
1951                         "sint");        if ((i = GMP_INTS_identify_nan_string(fac_arg)) >= 0)
1952        return(TCL_ERROR);           {
1953        }           const char *p;
1954     else  
1955        {           switch (i)
1956        char *string_arg;              {
1957                case 0:  p = GMP_INTS_supply_nan_string(2);
1958        //Grab a pointer to the string representation of                       break;
1959        //the input argument.  The storage does not belong to us.              case 1:  p = GMP_INTS_supply_nan_string(3);
1960        string_arg = Tcl_GetString(objv[2]);                       break;
1961        assert(string_arg != NULL);              case 2:  p = GMP_INTS_supply_nan_string(2);
1962                         break;
1963        //Try to parse the string as one of the error tags.              case 3:  p = GMP_INTS_supply_nan_string(3);
1964        //If it is one of those, it isn't an error, but don't                       break;
1965        //want to touch the string.              default:
1966        if (GMP_INTS_identify_nan_string(string_arg) >= 0)                       assert(0);
1967           {                       break;
1968           rv = Tcl_NewStringObj(string_arg, -1);              }
1969           Tcl_SetObjResult(interp, rv);  
1970           return(TCL_OK);           rv = Tcl_NewStringObj(p, -1);
1971           }           Tcl_SetObjResult(interp, rv);
1972        //Try to parse it as a signed integer without commas.           GMP_INTS_mpz_clear(&arb_result);
1973        //If it has no commas, there is no need to decommanate it.           return(TCL_OK);
1974        else if (BSTRFUNC_is_sint_wo_commas(string_arg))           }
1975           {  
1976           //This is already an acceptable commanated signed integer.  Send it        //Try to convert the string to a UINT32 using all
1977           //back as the return value.        //known methods.
1978           rv = Tcl_NewStringObj(string_arg, -1);        GMP_INTS_mpz_parse_into_uint32(&fac_ui_arg, &failure, fac_arg);
1979           Tcl_SetObjResult(interp, rv);  
1980           return(TCL_OK);        //If there was a parse failure, we have to return an error
1981           }        //message.
1982        //Try to parse the argument as a signed integer with commas.        if (failure)
1983        //If it is one of those, decommanate it and return it.           {
1984        else if (BSTRFUNC_is_sint_w_commas(string_arg))           rv = Tcl_NewStringObj("arbint intfac: \"", -1);
1985           {           Tcl_AppendToObj(rv, fac_arg, -1);
1986           size_t len;           Tcl_AppendToObj(rv, "\" is not a recognized 32-bit unsigned integer.", -1);
1987           char *buffer;           Tcl_SetObjResult(interp, rv);
1988             GMP_INTS_mpz_clear(&arb_result);
1989           len = strlen(string_arg);           return(TCL_ERROR);
1990           buffer = TclpAlloc(sizeof(char) * len + 1);           }
1991           strcpy(buffer, string_arg);  
1992           BSTRFUNC_decommanate(buffer);        //Calculate the factorial.
1993           rv = Tcl_NewStringObj(buffer, -1);        GMP_INTS_mpz_fac_ui(&arb_result, fac_ui_arg);
1994           TclpFree(buffer);  
1995           Tcl_SetObjResult(interp, rv);        //Figure out the number of characters required for
1996           return(TCL_OK);        //the output string.
1997           }        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);
1998        else  
1999           {        //Allocate space for the conversion result.
2000           //Error case.  Must give error message.        string_result = TclpAlloc(sizeof(char) * chars_reqd);
2001           rv = Tcl_NewStringObj("arbint decommanate: \"", -1);        assert(string_result != NULL);
2002           Tcl_AppendToObj(rv, string_arg, -1);  
2003           Tcl_AppendToObj(rv, "\" is not a recognized integer.", -1);        //Make the conversion to a character string.
2004           Tcl_SetObjResult(interp, rv);        GMP_INTS_mpz_to_string(string_result, &arb_result);
2005           return(TCL_ERROR);  
2006           }        //Assign the string result to a Tcl object.
2007        }        rv = Tcl_NewStringObj(string_result, -1);
2008     }  
2009          //Deallocate the string.
2010          TclpFree(string_result);
2011  //Handles the "intadd" subextension.  
2012  //08/06/01:  Visual inspection OK.        //Deallocate space for the arbitrary-length integer.
2013  static        GMP_INTS_mpz_clear(&arb_result);
2014  int ARBLENINTS_intadd_handler(ClientData dummy,  
2015                                Tcl_Interp *interp,        //Assign the result to be the return value.
2016                                int objc,        Tcl_SetObjResult(interp, rv);
2017                                Tcl_Obj *objv[])  
2018     {        //Return
2019     Tcl_Obj *rv;        return(TCL_OK);
2020          }
2021     //We must have two and exactly two additional arguments     }
2022     //to this function, which are the integers whose  
2023     //sum is to be calculated.  
2024     if (objc != 4)  //Handles the "intgcd" subextension.
2025        {  //08/06/01:  Visual inspection OK.
2026        Tcl_WrongNumArgs(interp,  static
2027                         2,  int ARBLENINTS_intgcd_handler(ClientData dummy,
2028                         objv,                                Tcl_Interp *interp,
2029                         "sint sint");                                int objc,
2030        return(TCL_ERROR);                                Tcl_Obj *objv[])
2031        }     {
2032     else     Tcl_Obj *rv;
2033        {  
2034        GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;     //We must have two and exactly two additional arguments
2035        char *add_arg1, *add_arg2;     //to this function, which are the integers whose
2036        int failure1, failure2;     //gcd is to be calculated.
2037        unsigned chars_reqd;     if (objc != 4)
2038        char *string_result;        {
2039        int i, j;        Tcl_WrongNumArgs(interp,
2040                           2,
2041        //Allocate space for the arbitrary-length integer result.                         objv,
2042        GMP_INTS_mpz_init(&arb_arg1);                         "sint sint");
2043        GMP_INTS_mpz_init(&arb_arg2);        return(TCL_ERROR);
2044        GMP_INTS_mpz_init(&arb_result);        }
2045       else
2046        //Grab pointers to the string representation of        {
2047        //the input arguments.  The storage does not belong to us.        GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;
2048        add_arg1 = Tcl_GetString(objv[2]);        char *gcd_arg1, *gcd_arg2;
2049        assert(add_arg1 != NULL);        int failure1, failure2;
2050        add_arg2 = Tcl_GetString(objv[3]);        unsigned chars_reqd;
2051        assert(add_arg2 != NULL);        char *string_result;
2052          int i, j;
2053        //Try to interpret either of the  strings as one of the NAN tags.  
2054        //If it is one, return the appropriate result for        //Allocate space for the arbitrary-length integer result.
2055        //a binary operation.        GMP_INTS_mpz_init(&arb_arg1);
2056        i = GMP_INTS_identify_nan_string(add_arg1);        GMP_INTS_mpz_init(&arb_arg2);
2057        j = GMP_INTS_identify_nan_string(add_arg2);        GMP_INTS_mpz_init(&arb_result);
2058    
2059        if ((i >= 0) || (j >= 0))        //Grab pointers to the string representation of
2060           {        //the input arguments.  The storage does not belong to us.
2061           const char *p;        gcd_arg1 = Tcl_GetString(objv[2]);
2062          assert(gcd_arg1 != NULL);
2063           //Find the max of i and j.  This isn't a scientific way to tag the        gcd_arg2 = Tcl_GetString(objv[3]);
2064           //result, but will be OK.  Some information is lost no matter what        assert(gcd_arg2 != NULL);
2065           //we do.  
2066           if (i > j)        //Try to interpret either of the  strings as one of the NAN tags.
2067              ;        //If it is one, return the appropriate result for
2068           else        //a binary operation.
2069              i = j;        i = GMP_INTS_identify_nan_string(gcd_arg1);
2070          j = GMP_INTS_identify_nan_string(gcd_arg2);
2071           //i now contains the max.  
2072           switch (i)        if ((i >= 0) || (j >= 0))
2073              {           {
2074              case 0:  p = GMP_INTS_supply_nan_string(2);           const char *p;
2075                       break;  
2076              case 1:  p = GMP_INTS_supply_nan_string(3);           //Find the max of i and j.  This isn't a scientific way to tag the
2077                       break;           //result, but will be OK.  Some information is lost no matter what
2078              case 2:  p = GMP_INTS_supply_nan_string(2);           //we do.
2079                       break;           if (i > j)
2080              case 3:  p = GMP_INTS_supply_nan_string(3);              ;
2081                       break;           else
2082              default:              i = j;
2083                       assert(0);  
2084                       break;           //i now contains the max.
2085              }           switch (i)
2086                {
2087           rv = Tcl_NewStringObj(p, -1);              case 0:  p = GMP_INTS_supply_nan_string(2);
2088           Tcl_SetObjResult(interp, rv);                       break;
2089                case 1:  p = GMP_INTS_supply_nan_string(3);
2090           GMP_INTS_mpz_clear(&arb_arg1);                       break;
2091           GMP_INTS_mpz_clear(&arb_arg2);              case 2:  p = GMP_INTS_supply_nan_string(2);
2092           GMP_INTS_mpz_clear(&arb_result);                       break;
2093                case 3:  p = GMP_INTS_supply_nan_string(3);
2094           return(TCL_OK);                       break;
2095           }              default:
2096                         assert(0);
2097        //Try to convert both strings into arbitrary integers.                       break;
2098        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, add_arg1);              }
2099        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, add_arg2);  
2100             rv = Tcl_NewStringObj(p, -1);
2101        //If there was a parse failure, we have to return an error           Tcl_SetObjResult(interp, rv);
2102        //message.  It is possible that both arguments failed the parse,  
2103        //but only return one in the error message.           GMP_INTS_mpz_clear(&arb_arg1);
2104        if (failure1 || failure2)           GMP_INTS_mpz_clear(&arb_arg2);
2105           {           GMP_INTS_mpz_clear(&arb_result);
2106           rv = Tcl_NewStringObj("arbint intadd: \"", -1);  
2107           if (failure1)           return(TCL_OK);
2108              Tcl_AppendToObj(rv, add_arg1, -1);           }
2109           else  
2110              Tcl_AppendToObj(rv, add_arg2, -1);        //Try to convert both strings into arbitrary integers.
2111          GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, gcd_arg1);
2112           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, gcd_arg2);
2113           Tcl_SetObjResult(interp, rv);  
2114          //If there was a parse failure, we have to return an error
2115           GMP_INTS_mpz_clear(&arb_arg1);        //message.  It is possible that both arguments failed the parse,
2116           GMP_INTS_mpz_clear(&arb_arg2);        //but only return one in the error message.
2117           GMP_INTS_mpz_clear(&arb_result);        if (failure1 || failure2)
2118             {
2119           return(TCL_ERROR);           rv = Tcl_NewStringObj("arbint intgcd: \"", -1);
2120           }           if (failure1)
2121                Tcl_AppendToObj(rv, gcd_arg1, -1);
2122        //Calculate the sum.           else
2123        GMP_INTS_mpz_add(&arb_result, &arb_arg1, &arb_arg2);              Tcl_AppendToObj(rv, gcd_arg2, -1);
2124    
2125        //Figure out the number of characters required for           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
2126        //the output string.           Tcl_SetObjResult(interp, rv);
2127        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);  
2128             GMP_INTS_mpz_clear(&arb_arg1);
2129        //Allocate space for the conversion result.           GMP_INTS_mpz_clear(&arb_arg2);
2130        string_result = TclpAlloc(sizeof(char) * chars_reqd);           GMP_INTS_mpz_clear(&arb_result);
2131        assert(string_result != NULL);  
2132             return(TCL_ERROR);
2133        //Make the conversion to a character string.           }
2134        GMP_INTS_mpz_to_string(string_result, &arb_result);  
2135          //Calculate the gcd.
2136        //Assign the string result to a Tcl object.        GMP_INTS_mpz_gcd(&arb_result, &arb_arg1, &arb_arg2);
2137        rv = Tcl_NewStringObj(string_result, -1);  
2138          //Figure out the number of characters required for
2139        //Deallocate the string.        //the output string.
2140        TclpFree(string_result);        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);
2141    
2142        //Deallocate space for the arbitrary-length integers.        //Allocate space for the conversion result.
2143        GMP_INTS_mpz_clear(&arb_arg1);        string_result = TclpAlloc(sizeof(char) * chars_reqd);
2144        GMP_INTS_mpz_clear(&arb_arg2);        assert(string_result != NULL);
2145        GMP_INTS_mpz_clear(&arb_result);  
2146          //Make the conversion to a character string.
2147        //Assign the result to be the return value.        GMP_INTS_mpz_to_string(string_result, &arb_result);
2148        Tcl_SetObjResult(interp, rv);  
2149          //Assign the string result to a Tcl object.
2150        //Return        rv = Tcl_NewStringObj(string_result, -1);
2151        return(TCL_OK);  
2152        }        //Deallocate the string.
2153     }        TclpFree(string_result);
2154    
2155          //Deallocate space for the arbitrary-length integers.
2156  //08/01/01:  Visual inspection and some unit testing, OK.        GMP_INTS_mpz_clear(&arb_arg1);
2157  //Handles the "intcmp" subextension.        GMP_INTS_mpz_clear(&arb_arg2);
2158  static        GMP_INTS_mpz_clear(&arb_result);
2159  int ARBLENINTS_intcmp_handler(ClientData dummy,  
2160                                Tcl_Interp *interp,        //Assign the result to be the return value.
2161                                int objc,        Tcl_SetObjResult(interp, rv);
2162                                Tcl_Obj *objv[])  
2163     {        //Return
2164     Tcl_Obj *rv;        return(TCL_OK);
2165          }
2166     //We must have two and exactly two additional arguments     }
2167     //to this function, which are the integers to be compared.  
2168     if (objc != 4)  
2169        {  //Handles the "intlcm" subextension.
2170        Tcl_WrongNumArgs(interp,  //08/10/01:  Visual inspection OK.
2171                         2,  static
2172                         objv,  int ARBLENINTS_intlcm_handler(ClientData dummy,
2173                         "sint sint");                                Tcl_Interp *interp,
2174        return(TCL_ERROR);                                int objc,
2175        }                                Tcl_Obj *objv[])
2176     else     {
2177        {     Tcl_Obj *rv;
2178        GMP_INTS_mpz_struct arb_arg1, arb_arg2;  
2179        char *cmp_arg1, *cmp_arg2;     //We must have two and exactly two additional arguments
2180        int failure1, failure2;     //to this function, which are the integers whose
2181        int i, j, compare_result;     //lcm is to be calculated.
2182       if (objc != 4)
2183        //Allocate space for the arbitrary-length integer result.        {
2184        GMP_INTS_mpz_init(&arb_arg1);        Tcl_WrongNumArgs(interp,
2185        GMP_INTS_mpz_init(&arb_arg2);                         2,
2186                           objv,
2187        //Grab pointers to the string representation of                         "sint sint");
2188        //the input arguments.  The storage does not belong to us.        return(TCL_ERROR);
2189        cmp_arg1 = Tcl_GetString(objv[2]);        }
2190        assert(cmp_arg1 != NULL);     else
2191        cmp_arg2 = Tcl_GetString(objv[3]);        {
2192        assert(cmp_arg2 != NULL);        GMP_INTS_mpz_struct arb_arg1, arb_arg2, gcd, remainder, arb_result;
2193          char *lcm_arg1, *lcm_arg2;
2194        //Try to interpret either of the  strings as one of the NAN tags.        int failure1, failure2;
2195        //We cannot compare NAN tags.  If either is a NAN tag, we must signal an        unsigned chars_reqd;
2196        //error.        char *string_result;
2197        i = GMP_INTS_identify_nan_string(cmp_arg1);        int i, j;
2198        j = GMP_INTS_identify_nan_string(cmp_arg2);  
2199          //Allocate space for the arbitrary-length integers.
2200        if ((i >= 0) || (j >= 0))        GMP_INTS_mpz_init(&arb_arg1);
2201           {        GMP_INTS_mpz_init(&arb_arg2);
2202           rv = Tcl_NewStringObj("arbint intcmp: cannot compare NAN symbolic tags.", -1);        GMP_INTS_mpz_init(&gcd);
2203           Tcl_SetObjResult(interp, rv);        GMP_INTS_mpz_init(&remainder);
2204          GMP_INTS_mpz_init(&arb_result);
2205           GMP_INTS_mpz_clear(&arb_arg1);  
2206           GMP_INTS_mpz_clear(&arb_arg2);        //Grab pointers to the string representation of
2207          //the input arguments.  The storage does not belong to us.
2208           return(TCL_ERROR);        lcm_arg1 = Tcl_GetString(objv[2]);
2209           }        assert(lcm_arg1 != NULL);
2210          lcm_arg2 = Tcl_GetString(objv[3]);
2211        //Try to convert both strings into arbitrary integers.        assert(lcm_arg2 != NULL);
2212        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, cmp_arg1);  
2213        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, cmp_arg2);        //Try to interpret either of the  strings as one of the NAN tags.
2214          //If it is one, return the appropriate result for
2215        //If there was a parse failure, we have to return an error        //a binary operation.
2216        //message.  It is possible that both arguments failed the parse,        i = GMP_INTS_identify_nan_string(lcm_arg1);
2217        //but only return one in the error message.        j = GMP_INTS_identify_nan_string(lcm_arg2);
2218        if (failure1 || failure2)  
2219           {        if ((i >= 0) || (j >= 0))
2220           rv = Tcl_NewStringObj("arbint intcmp: \"", -1);           {
2221           if (failure1)           const char *p;
2222              Tcl_AppendToObj(rv, cmp_arg1, -1);  
2223           else           //Find the max of i and j.  This isn't a scientific way to tag the
2224              Tcl_AppendToObj(rv, cmp_arg2, -1);           //result, but will be OK.  Some information is lost no matter what
2225             //we do.
2226           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);           if (i > j)
2227           Tcl_SetObjResult(interp, rv);              ;
2228             else
2229           GMP_INTS_mpz_clear(&arb_arg1);              i = j;
2230           GMP_INTS_mpz_clear(&arb_arg2);  
2231             //i now contains the max.
2232           return(TCL_ERROR);           switch (i)
2233           }              {
2234                case 0:  p = GMP_INTS_supply_nan_string(2);
2235        //Calculate the compare result.                       break;
2236        compare_result = GMP_INTS_mpz_cmp(&arb_arg1, &arb_arg2);              case 1:  p = GMP_INTS_supply_nan_string(3);
2237                         break;
2238        //Assign the return value based on the result.              case 2:  p = GMP_INTS_supply_nan_string(2);
2239        if (compare_result < 0)                       break;
2240           rv = Tcl_NewStringObj("-1", -1);              case 3:  p = GMP_INTS_supply_nan_string(3);
2241        else if (compare_result == 0)                       break;
2242           rv = Tcl_NewStringObj("0", -1);              default:
2243        else                       assert(0);
2244           rv = Tcl_NewStringObj("1", -1);                       break;
2245                }
2246        //Deallocate space for the arbitrary-length integers.  
2247        GMP_INTS_mpz_clear(&arb_arg1);           rv = Tcl_NewStringObj(p, -1);
2248        GMP_INTS_mpz_clear(&arb_arg2);           Tcl_SetObjResult(interp, rv);
2249    
2250        //Assign the result to be the return value.           GMP_INTS_mpz_clear(&arb_arg1);
2251        Tcl_SetObjResult(interp, rv);           GMP_INTS_mpz_clear(&arb_arg2);
2252             GMP_INTS_mpz_clear(&gcd);
2253        //Return           GMP_INTS_mpz_clear(&remainder);
2254        return(TCL_OK);           GMP_INTS_mpz_clear(&arb_result);
2255        }  
2256     }           return(TCL_OK);
2257             }
2258    
2259  //Handles the "intdiv" subextension.        //Try to convert both strings into arbitrary integers.
2260  //07/31/01:  Visually inspected, OK.        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, lcm_arg1);
2261  static        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, lcm_arg2);
2262  int ARBLENINTS_intdiv_handler(ClientData dummy,  
2263                                Tcl_Interp *interp,        //If there was a parse failure, we have to return an error
2264                                int objc,        //message.  It is possible that both arguments failed the parse,
2265                                Tcl_Obj *objv[])        //but only return one in the error message.
2266     {        if (failure1 || failure2)
2267     Tcl_Obj *rv;           {
2268             rv = Tcl_NewStringObj("arbint intlcm: \"", -1);
2269     //We must have two and exactly two additional arguments           if (failure1)
2270     //to this function, which are the integers whose              Tcl_AppendToObj(rv, lcm_arg1, -1);
2271     //integer quotient is to be calculated.           else
2272     if (objc != 4)              Tcl_AppendToObj(rv, lcm_arg2, -1);
2273        {  
2274        Tcl_WrongNumArgs(interp,           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
2275                         2,           Tcl_SetObjResult(interp, rv);
2276                         objv,  
2277                         "sint sint");           GMP_INTS_mpz_clear(&arb_arg1);
2278        return(TCL_ERROR);           GMP_INTS_mpz_clear(&arb_arg2);
2279        }           GMP_INTS_mpz_clear(&gcd);
2280     else           GMP_INTS_mpz_clear(&remainder);
2281        {           GMP_INTS_mpz_clear(&arb_result);
2282        GMP_INTS_mpz_struct arb_dividend, arb_divisor, arb_quotient, arb_remainder;  
2283        char *dividend_arg1, *divisor_arg2;           return(TCL_ERROR);
2284        int failure1, failure2;           }
2285        unsigned chars_reqd;  
2286        char *string_result;        //Adjust errant arguments.
2287        int i, j;        if (GMP_INTS_mpz_is_neg(&arb_arg1))
2288             GMP_INTS_mpz_negate(&arb_arg1);
2289        //Allocate space for the arbitrary-length integer arguments and results.        else if (GMP_INTS_mpz_is_zero(&arb_arg1))
2290        GMP_INTS_mpz_init(&arb_dividend);           GMP_INTS_mpz_set_ui(&arb_arg1, 1);
2291        GMP_INTS_mpz_init(&arb_divisor);        if (GMP_INTS_mpz_is_neg(&arb_arg2))
2292        GMP_INTS_mpz_init(&arb_quotient);           GMP_INTS_mpz_negate(&arb_arg2);
2293        GMP_INTS_mpz_init(&arb_remainder);        else if (GMP_INTS_mpz_is_zero(&arb_arg2))
2294             GMP_INTS_mpz_set_ui(&arb_arg2, 1);
2295        //Grab pointers to the string representation of        
2296        //the input arguments.  The storage does not belong to us.        //Calculate the gcd.
2297        dividend_arg1 = Tcl_GetString(objv[2]);        GMP_INTS_mpz_gcd(&gcd, &arb_arg1, &arb_arg2);
2298        assert(dividend_arg1 != NULL);  
2299        divisor_arg2 = Tcl_GetString(objv[3]);        //Calculate the lcm.
2300        assert(divisor_arg2 != NULL);        GMP_INTS_mpz_mul(&arb_arg1, &arb_arg1, &arb_arg2);
2301          GMP_INTS_mpz_tdiv_qr(&arb_result, &remainder,
2302        //Try to interpret either of the  strings as one of the NAN tags.                             &arb_arg1, &gcd);
2303        //If it is one, return the appropriate result for  
2304        //a binary operation.        //Figure out the number of characters required for
2305        i = GMP_INTS_identify_nan_string(dividend_arg1);        //the output string.
2306        j = GMP_INTS_identify_nan_string(divisor_arg2);        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);
2307    
2308        if ((i >= 0) || (j >= 0))        //Allocate space for the conversion result.
2309           {        string_result = TclpAlloc(sizeof(char) * chars_reqd);
2310           const char *p;        assert(string_result != NULL);
2311    
2312           //Find the max of i and j.  This isn't a scientific way to tag the        //Make the conversion to a character string.
2313           //result, but will be OK.  Some information is lost no matter what        GMP_INTS_mpz_to_string(string_result, &arb_result);
2314           //we do.  
2315           if (i > j)        //Assign the string result to a Tcl object.
2316              ;        rv = Tcl_NewStringObj(string_result, -1);
2317           else  
2318              i = j;        //Deallocate the string.
2319          TclpFree(string_result);
2320           //i now contains the max.  
2321           switch (i)        //Deallocate space for the arbitrary-length integers.
2322              {        GMP_INTS_mpz_clear(&arb_arg1);
2323              case 0:  p = GMP_INTS_supply_nan_string(2);        GMP_INTS_mpz_clear(&arb_arg2);
2324                       break;        GMP_INTS_mpz_clear(&gcd);
2325              case 1:  p = GMP_INTS_supply_nan_string(3);        GMP_INTS_mpz_clear(&remainder);
2326                       break;        GMP_INTS_mpz_clear(&arb_result);
2327              case 2:  p = GMP_INTS_supply_nan_string(2);  
2328                       break;        //Assign the result to be the return value.
2329              case 3:  p = GMP_INTS_supply_nan_string(3);        Tcl_SetObjResult(interp, rv);
2330                       break;  
2331              default:        //Return
2332                       assert(0);        return(TCL_OK);
2333                       break;        }
2334              }     }
2335    
2336           rv = Tcl_NewStringObj(p, -1);  
2337           Tcl_SetObjResult(interp, rv);  //Handles the "intmod" subextension.
2338    //08/06/01:  Visual inspection OK.
2339           GMP_INTS_mpz_clear(&arb_dividend);  static
2340           GMP_INTS_mpz_clear(&arb_divisor);  int ARBLENINTS_intmod_handler(ClientData dummy,
2341           GMP_INTS_mpz_clear(&arb_quotient);                                Tcl_Interp *interp,
2342           GMP_INTS_mpz_clear(&arb_remainder);                                int objc,
2343                                  Tcl_Obj *objv[])
2344           return(TCL_OK);     {
2345           }     Tcl_Obj *rv;
2346    
2347        //Try to convert both strings into arbitrary integers.     //We must have two and exactly two additional arguments
2348        GMP_INTS_mpz_set_general_int(&arb_dividend, &failure1, dividend_arg1);     //to this function, which are the integers whose
2349        GMP_INTS_mpz_set_general_int(&arb_divisor,  &failure2, divisor_arg2);     //integer quotient is to be calculated.
2350       if (objc != 4)
2351        //If there was a parse failure, we have to return an error        {
2352        //message.  It is possible that both arguments failed the parse,        Tcl_WrongNumArgs(interp,
2353        //but only return one in the error message.                         2,
2354        if (failure1 || failure2)                         objv,
2355           {                         "sint sint");
2356           rv = Tcl_NewStringObj("arbint intdiv: \"", -1);        return(TCL_ERROR);
2357           if (failure1)        }
2358              Tcl_AppendToObj(rv, dividend_arg1, -1);     else
2359           else        {
2360              Tcl_AppendToObj(rv, divisor_arg2, -1);        GMP_INTS_mpz_struct arb_dividend, arb_divisor, arb_quotient, arb_remainder;
2361          char *dividend_arg1, *divisor_arg2;
2362           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);        int failure1, failure2;
2363           Tcl_SetObjResult(interp, rv);        unsigned chars_reqd;
2364          char *string_result;
2365           GMP_INTS_mpz_clear(&arb_dividend);        int i, j;
2366           GMP_INTS_mpz_clear(&arb_divisor);  
2367           GMP_INTS_mpz_clear(&arb_quotient);        //Allocate space for the arbitrary-length integer arguments and results.
2368           GMP_INTS_mpz_clear(&arb_remainder);        GMP_INTS_mpz_init(&arb_dividend);
2369          GMP_INTS_mpz_init(&arb_divisor);
2370           return(TCL_ERROR);        GMP_INTS_mpz_init(&arb_quotient);
2371           }        GMP_INTS_mpz_init(&arb_remainder);
2372    
2373        //Calculate the quotient.        //Grab pointers to the string representation of
2374        GMP_INTS_mpz_tdiv_qr(&arb_quotient, &arb_remainder, &arb_dividend, &arb_divisor);        //the input arguments.  The storage does not belong to us.
2375          dividend_arg1 = Tcl_GetString(objv[2]);
2376        //Figure out the number of characters required for        assert(dividend_arg1 != NULL);
2377        //the output string.        divisor_arg2 = Tcl_GetString(objv[3]);
2378        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_quotient);        assert(divisor_arg2 != NULL);
2379    
2380        //Allocate space for the conversion result.        //Try to interpret either of the  strings as one of the NAN tags.
2381        string_result = TclpAlloc(sizeof(char) * chars_reqd);        //If it is one, return the appropriate result for
2382        assert(string_result != NULL);        //a binary operation.
2383          i = GMP_INTS_identify_nan_string(dividend_arg1);
2384        //Make the conversion to a character string.        j = GMP_INTS_identify_nan_string(divisor_arg2);
2385        GMP_INTS_mpz_to_string(string_result, &arb_quotient);  
2386          if ((i >= 0) || (j >= 0))
2387        //Assign the string result to a Tcl object.           {
2388        rv = Tcl_NewStringObj(string_result, -1);           const char *p;
2389    
2390        //Deallocate the string.           //Find the max of i and j.  This isn't a scientific way to tag the
2391        TclpFree(string_result);           //result, but will be OK.  Some information is lost no matter what
2392             //we do.
2393        //Deallocate space for the arbitrary-length integers.           if (i > j)
2394        GMP_INTS_mpz_clear(&arb_dividend);              ;
2395        GMP_INTS_mpz_clear(&arb_divisor);           else
2396        GMP_INTS_mpz_clear(&arb_quotient);              i = j;
2397        GMP_INTS_mpz_clear(&arb_remainder);  
2398             //i now contains the max.
2399        //Assign the result to be the return value.           switch (i)
2400        Tcl_SetObjResult(interp, rv);              {
2401                case 0:  p = GMP_INTS_supply_nan_string(2);
2402        //Return                       break;
2403        return(TCL_OK);              case 1:  p = GMP_INTS_supply_nan_string(3);
2404        }                       break;
2405     }              case 2:  p = GMP_INTS_supply_nan_string(2);
2406                         break;
2407                case 3:  p = GMP_INTS_supply_nan_string(3);
2408  //08/01/01:  Visually inspected.                       break;
2409  //Handles the "intexp" subextension.              default:
2410  static                       assert(0);
2411  int ARBLENINTS_intexp_handler(ClientData dummy,                       break;
2412                                Tcl_Interp *interp,              }
2413                                int objc,  
2414                                Tcl_Obj *objv[])           rv = Tcl_NewStringObj(p, -1);
2415     {           Tcl_SetObjResult(interp, rv);
2416     Tcl_Obj *rv;  
2417             GMP_INTS_mpz_clear(&arb_dividend);
2418     //We must have two and exactly two additional arguments           GMP_INTS_mpz_clear(&arb_divisor);
2419     //to this function, which are the integers used to           GMP_INTS_mpz_clear(&arb_quotient);
2420     //calculate the exponential.           GMP_INTS_mpz_clear(&arb_remainder);
2421     if (objc != 4)  
2422        {           return(TCL_OK);
2423        Tcl_WrongNumArgs(interp,           }
2424                         2,  
2425                         objv,        //Try to convert both strings into arbitrary integers.
2426                         "sint uint32");        GMP_INTS_mpz_set_general_int(&arb_dividend, &failure1, dividend_arg1);
2427        return(TCL_ERROR);        GMP_INTS_mpz_set_general_int(&arb_divisor,  &failure2, divisor_arg2);
2428        }  
2429     else        //If there was a parse failure, we have to return an error
2430        {        //message.  It is possible that both arguments failed the parse,
2431        GMP_INTS_mpz_struct arb_arg1, arb_result;        //but only return one in the error message.
2432        unsigned arg2;        if (failure1 || failure2)
2433        char *str_arg1, *str_arg2;           {
2434        int failure1, failure2;           rv = Tcl_NewStringObj("arbint intmod: \"", -1);
2435        unsigned chars_reqd;           if (failure1)
2436        char *string_result;              Tcl_AppendToObj(rv, dividend_arg1, -1);
2437        int i, j;           else
2438                Tcl_AppendToObj(rv, divisor_arg2, -1);
2439        //Allocate space for the arbitrary-length integers.  
2440        GMP_INTS_mpz_init(&arb_arg1);           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
2441        GMP_INTS_mpz_init(&arb_result);           Tcl_SetObjResult(interp, rv);
2442    
2443        //Grab pointers to the string representation of           GMP_INTS_mpz_clear(&arb_dividend);
2444        //the input arguments.  The storage does not belong to us.           GMP_INTS_mpz_clear(&arb_divisor);
2445        str_arg1 = Tcl_GetString(objv[2]);           GMP_INTS_mpz_clear(&arb_quotient);
2446        assert(str_arg1 != NULL);           GMP_INTS_mpz_clear(&arb_remainder);
2447        str_arg2 = Tcl_GetString(objv[3]);  
2448        assert(str_arg2 != NULL);           return(TCL_ERROR);
2449             }
2450        //Try to interpret either of the  strings as one of the NAN tags.  
2451        //If it is one, return the appropriate result for        //Calculate the quotient and remainder.
2452        //a binary operation.        GMP_INTS_mpz_tdiv_qr(&arb_quotient, &arb_remainder, &arb_dividend, &arb_divisor);
2453        i = GMP_INTS_identify_nan_string(str_arg1);  
2454        j = GMP_INTS_identify_nan_string(str_arg2);        //Figure out the number of characters required for
2455          //the output string.
2456        if ((i >= 0) || (j >= 0))        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_remainder);
2457           {  
2458           const char *p;        //Allocate space for the conversion result.
2459          string_result = TclpAlloc(sizeof(char) * chars_reqd);
2460           //Find the max of i and j.  This isn't a scientific way to tag the        assert(string_result != NULL);
2461           //result, but will be OK.  Some information is lost no matter what  
2462           //we do.        //Make the conversion to a character string.
2463           if (i > j)        GMP_INTS_mpz_to_string(string_result, &arb_remainder);
2464              ;  
2465           else        //Assign the string result to a Tcl object.
2466              i = j;        rv = Tcl_NewStringObj(string_result, -1);
2467    
2468           //i now contains the max.        //Deallocate the string.
2469           switch (i)        TclpFree(string_result);
2470              {  
2471              case 0:  p = GMP_INTS_supply_nan_string(2);        //Deallocate space for the arbitrary-length integers.
2472                       break;        GMP_INTS_mpz_clear(&arb_dividend);
2473              case 1:  p = GMP_INTS_supply_nan_string(3);        GMP_INTS_mpz_clear(&arb_divisor);
2474                       break;        GMP_INTS_mpz_clear(&arb_quotient);
2475              case 2:  p = GMP_INTS_supply_nan_string(2);        GMP_INTS_mpz_clear(&arb_remainder);
2476                       break;  
2477              case 3:  p = GMP_INTS_supply_nan_string(3);        //Assign the result to be the return value.
2478                       break;        Tcl_SetObjResult(interp, rv);
2479              default:  
2480                       assert(0);        //Return
2481                       break;        return(TCL_OK);
2482              }        }
2483       }
2484           rv = Tcl_NewStringObj(p, -1);  
2485           Tcl_SetObjResult(interp, rv);  
2486    //Handles the "intmul" subextension.
2487           GMP_INTS_mpz_clear(&arb_arg1);  //08/06/01:  Visual inspection OK.
2488           GMP_INTS_mpz_clear(&arb_result);  static
2489    int ARBLENINTS_intmul_handler(ClientData dummy,
2490           return(TCL_OK);                                Tcl_Interp *interp,
2491           }                                int objc,
2492                                  Tcl_Obj *objv[])
2493        //Try to convert the first string into arbitrary integers.     {
2494        //The first string can be anything, including zero or a negative     Tcl_Obj *rv;
2495        //arugument.  
2496        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, str_arg1);     //We must have two and exactly two additional arguments
2497       //to this function, which are the integers whose
2498        //If the conversion of the first string did not go alright,     //product is to be calculated.
2499        //print error message and abort.     if (objc != 4)
2500        if (failure1)        {
2501           {        Tcl_WrongNumArgs(interp,
2502           rv = Tcl_NewStringObj("arbint intexp: \"", -1);                         2,
2503           Tcl_AppendToObj(rv, str_arg1, -1);                         objv,
2504           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);                         "sint sint");
2505           Tcl_SetObjResult(interp, rv);        return(TCL_ERROR);
2506          }
2507           GMP_INTS_mpz_clear(&arb_arg1);     else
2508           GMP_INTS_mpz_clear(&arb_result);        {
2509          GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;
2510           return(TCL_ERROR);        char *mul_arg1, *mul_arg2;
2511           }        int failure1, failure2;
2512          unsigned chars_reqd;
2513          char *string_result;
2514        //Try to convert the second string into an unsigned 32-bit        int i, j;
2515        //integer.  
2516        GMP_INTS_mpz_parse_into_uint32(&arg2, &failure2, str_arg2);        //Allocate space for the arbitrary-length integer result.
2517          GMP_INTS_mpz_init(&arb_arg1);
2518        //If the conversion of the second string did not go alright,        GMP_INTS_mpz_init(&arb_arg2);
2519        //print error message and abort.        GMP_INTS_mpz_init(&arb_result);
2520        if (failure2)  
2521           {        //Grab pointers to the string representation of
2522           rv = Tcl_NewStringObj("arbint intexp: \"", -1);        //the input arguments.  The storage does not belong to us.
2523           Tcl_AppendToObj(rv, str_arg2, -1);        mul_arg1 = Tcl_GetString(objv[2]);
2524           Tcl_AppendToObj(rv, "\" is not a recognized unsigned 32-bit integer.", -1);        assert(mul_arg1 != NULL);
2525           Tcl_SetObjResult(interp, rv);        mul_arg2 = Tcl_GetString(objv[3]);
2526          assert(mul_arg2 != NULL);
2527           GMP_INTS_mpz_clear(&arb_arg1);  
2528           GMP_INTS_mpz_clear(&arb_result);        //Try to interpret either of the  strings as one of the NAN tags.
2529          //If it is one, return the appropriate result for
2530           return(TCL_ERROR);        //a binary operation.
2531           }        i = GMP_INTS_identify_nan_string(mul_arg1);
2532          j = GMP_INTS_identify_nan_string(mul_arg2);
2533        //Calculate the exponential.  
2534        GMP_INTS_mpz_pow_ui(&arb_result, &arb_arg1, arg2);        if ((i >= 0) || (j >= 0))
2535             {
2536        //Figure out the number of characters required for           const char *p;
2537        //the output string.  
2538        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);           //Find the max of i and j.  This isn't a scientific way to tag the
2539             //result, but will be OK.  Some information is lost no matter what
2540        //Allocate space for the conversion result.           //we do.
2541        string_result = TclpAlloc(sizeof(char) * chars_reqd);           if (i > j)
2542        assert(string_result != NULL);              ;
2543             else
2544        //Make the conversion to a character string.              i = j;
2545        GMP_INTS_mpz_to_string(string_result, &arb_result);  
2546             //i now contains the max.
2547        //Assign the string result to a Tcl object.           switch (i)
2548        rv = Tcl_NewStringObj(string_result, -1);              {
2549                case 0:  p = GMP_INTS_supply_nan_string(2);
2550        //Deallocate the string.                       break;
2551        TclpFree(string_result);              case 1:  p = GMP_INTS_supply_nan_string(3);
2552                         break;
2553        //Deallocate space for the arbitrary-length integers.              case 2:  p = GMP_INTS_supply_nan_string(2);
2554        GMP_INTS_mpz_clear(&arb_arg1);                       break;
2555        GMP_INTS_mpz_clear(&arb_result);              case 3:  p = GMP_INTS_supply_nan_string(3);
2556                         break;
2557        //Assign the result to be the return value.              default:
2558        Tcl_SetObjResult(interp, rv);                       assert(0);
2559                         break;
2560        //Return              }
2561        return(TCL_OK);  
2562        }           rv = Tcl_NewStringObj(p, -1);
2563     }           Tcl_SetObjResult(interp, rv);
2564    
2565             GMP_INTS_mpz_clear(&arb_arg1);
2566  //Handles the "intfac" subextension.           GMP_INTS_mpz_clear(&arb_arg2);
2567  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this           GMP_INTS_mpz_clear(&arb_result);
2568  //from memory an intuition as far as how to set return results and so forth.  
2569  static           return(TCL_OK);
2570  int ARBLENINTS_intfac_handler(ClientData dummy,           }
2571                                Tcl_Interp *interp,  
2572                                int objc,        //Try to convert both strings into arbitrary integers.
2573                                Tcl_Obj *objv[])        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, mul_arg1);
2574     {        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, mul_arg2);
2575     Tcl_Obj *rv;  
2576          //If there was a parse failure, we have to return an error
2577     //We must have one and exactly one additional argument        //message.  It is possible that both arguments failed the parse,
2578     //to this function, which is the integer whose        //but only return one in the error message.
2579     //factorial is to be evaluated.        if (failure1 || failure2)
2580     if (objc != 3)           {
2581        {           rv = Tcl_NewStringObj("arbint intmul: \"", -1);
2582        Tcl_WrongNumArgs(interp,           if (failure1)
2583                         2,              Tcl_AppendToObj(rv, mul_arg1, -1);
2584                         objv,           else
2585                         "uint32");              Tcl_AppendToObj(rv, mul_arg2, -1);
2586        return(TCL_ERROR);  
2587        }           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
2588     else           Tcl_SetObjResult(interp, rv);
2589        {  
2590        GMP_INTS_mpz_struct arb_result;           GMP_INTS_mpz_clear(&arb_arg1);
2591        char *fac_arg;           GMP_INTS_mpz_clear(&arb_arg2);
2592        int failure;           GMP_INTS_mpz_clear(&arb_result);
2593        unsigned fac_ui_arg;  
2594        unsigned chars_reqd;           return(TCL_ERROR);
2595        char *string_result;           }
2596        int i;  
2597          //Calculate the product.
2598        //Allocate space for the arbitrary-length integer result.        GMP_INTS_mpz_mul(&arb_result, &arb_arg1, &arb_arg2);
2599        GMP_INTS_mpz_init(&arb_result);  
2600          //Figure out the number of characters required for
2601        //Grab a pointer to the string representation of        //the output string.
2602        //the input argument.  The storage does not belong to us.        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);
2603        fac_arg = Tcl_GetString(objv[2]);  
2604        assert(fac_arg != NULL);        //Allocate space for the conversion result.
2605          string_result = TclpAlloc(sizeof(char) * chars_reqd);
2606        //Try to interpret the string as one of the NAN tags.        assert(string_result != NULL);
2607        //If it is one, return the appropriate result for  
2608        //a unary operation.        //Make the conversion to a character string.
2609        if ((i = GMP_INTS_identify_nan_string(fac_arg)) >= 0)        GMP_INTS_mpz_to_string(string_result, &arb_result);
2610           {  
2611           const char *p;        //Assign the string result to a Tcl object.
2612          rv = Tcl_NewStringObj(string_result, -1);
2613           switch (i)  
2614              {        //Deallocate the string.
2615              case 0:  p = GMP_INTS_supply_nan_string(2);        TclpFree(string_result);
2616                       break;  
2617              case 1:  p = GMP_INTS_supply_nan_string(3);        //Deallocate space for the arbitrary-length integers.
2618                       break;        GMP_INTS_mpz_clear(&arb_arg1);
2619              case 2:  p = GMP_INTS_supply_nan_string(2);        GMP_INTS_mpz_clear(&arb_arg2);
2620                       break;        GMP_INTS_mpz_clear(&arb_result);
2621              case 3:  p = GMP_INTS_supply_nan_string(3);  
2622                       break;        //Assign the result to be the return value.
2623              default:        Tcl_SetObjResult(interp, rv);
2624                       assert(0);  
2625                       break;        //Return
2626              }        return(TCL_OK);
2627          }
2628           rv = Tcl_NewStringObj(p, -1);     }
2629           Tcl_SetObjResult(interp, rv);  
2630           GMP_INTS_mpz_clear(&arb_result);  
2631           return(TCL_OK);  //Handles the "intsub" subextension.
2632           }  //08/06/01:  Visual inspection OK.
2633    static
2634        //Try to convert the string to a UINT32 using all  int ARBLENINTS_intsub_handler(ClientData dummy,
2635        //known methods.                                Tcl_Interp *interp,
2636        GMP_INTS_mpz_parse_into_uint32(&fac_ui_arg, &failure, fac_arg);                                int objc,
2637                                  Tcl_Obj *objv[])
2638        //If there was a parse failure, we have to return an error     {
2639        //message.     Tcl_Obj *rv;
2640        if (failure)  
2641           {     //We must have two and exactly two additional arguments
2642           rv = Tcl_NewStringObj("arbint intfac: \"", -1);     //to this function, which are the integers whose
2643           Tcl_AppendToObj(rv, fac_arg, -1);     //difference is to be calculated.
2644           Tcl_AppendToObj(rv, "\" is not a recognized 32-bit unsigned integer.", -1);     if (objc != 4)
2645           Tcl_SetObjResult(interp, rv);        {
2646           GMP_INTS_mpz_clear(&arb_result);        Tcl_WrongNumArgs(interp,
2647           return(TCL_ERROR);                         2,
2648           }                         objv,
2649                           "sint sint");
2650        //Calculate the factorial.        return(TCL_ERROR);
2651        GMP_INTS_mpz_fac_ui(&arb_result, fac_ui_arg);        }
2652       else
2653        //Figure out the number of characters required for        {
2654        //the output string.        GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;
2655        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);        char *sub_arg1, *sub_arg2;
2656          int failure1, failure2;
2657        //Allocate space for the conversion result.        unsigned chars_reqd;
2658        string_result = TclpAlloc(sizeof(char) * chars_reqd);        char *string_result;
2659        assert(string_result != NULL);        int i, j;
2660    
2661        //Make the conversion to a character string.        //Allocate space for the arbitrary-length integer result.
2662        GMP_INTS_mpz_to_string(string_result, &arb_result);        GMP_INTS_mpz_init(&arb_arg1);
2663          GMP_INTS_mpz_init(&arb_arg2);
2664        //Assign the string result to a Tcl object.        GMP_INTS_mpz_init(&arb_result);
2665        rv = Tcl_NewStringObj(string_result, -1);  
2666          //Grab pointers to the string representation of
2667        //Deallocate the string.        //the input arguments.  The storage does not belong to us.
2668        TclpFree(string_result);        sub_arg1 = Tcl_GetString(objv[2]);
2669          assert(sub_arg1 != NULL);
2670        //Deallocate space for the arbitrary-length integer.        sub_arg2 = Tcl_GetString(objv[3]);
2671        GMP_INTS_mpz_clear(&arb_result);        assert(sub_arg2 != NULL);
2672    
2673        //Assign the result to be the return value.        //Try to interpret either of the  strings as one of the NAN tags.
2674        Tcl_SetObjResult(interp, rv);        //If it is one, return the appropriate result for
2675          //a binary operation.
2676        //Return        i = GMP_INTS_identify_nan_string(sub_arg1);
2677        return(TCL_OK);        j = GMP_INTS_identify_nan_string(sub_arg2);
2678        }  
2679     }        if ((i >= 0) || (j >= 0))
2680             {
2681             const char *p;
2682  //Handles the "intgcd" subextension.  
2683  //08/06/01:  Visual inspection OK.           //Find the max of i and j.  This isn't a scientific way to tag the
2684  static           //result, but will be OK.  Some information is lost no matter what
2685  int ARBLENINTS_intgcd_handler(ClientData dummy,           //we do.
2686                                Tcl_Interp *interp,           if (i > j)
2687                                int objc,              ;
2688                                Tcl_Obj *objv[])           else
2689     {              i = j;
2690     Tcl_Obj *rv;  
2691             //i now contains the max.
2692     //We must have two and exactly two additional arguments           switch (i)
2693     //to this function, which are the integers whose              {
2694     //gcd is to be calculated.              case 0:  p = GMP_INTS_supply_nan_string(2);
2695     if (objc != 4)                       break;
2696        {              case 1:  p = GMP_INTS_supply_nan_string(3);
2697        Tcl_WrongNumArgs(interp,                       break;
2698                         2,              case 2:  p = GMP_INTS_supply_nan_string(2);
2699                         objv,                       break;
2700                         "sint sint");              case 3:  p = GMP_INTS_supply_nan_string(3);
2701        return(TCL_ERROR);                       break;
2702        }              default:
2703     else                       assert(0);
2704        {                       break;
2705        GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;              }
2706        char *gcd_arg1, *gcd_arg2;  
2707        int failure1, failure2;           rv = Tcl_NewStringObj(p, -1);
2708        unsigned chars_reqd;           Tcl_SetObjResult(interp, rv);
2709        char *string_result;  
2710        int i, j;           GMP_INTS_mpz_clear(&arb_arg1);
2711             GMP_INTS_mpz_clear(&arb_arg2);
2712        //Allocate space for the arbitrary-length integer result.           GMP_INTS_mpz_clear(&arb_result);
2713        GMP_INTS_mpz_init(&arb_arg1);  
2714        GMP_INTS_mpz_init(&arb_arg2);           return(TCL_OK);
2715        GMP_INTS_mpz_init(&arb_result);           }
2716    
2717        //Grab pointers to the string representation of        //Try to convert both strings into arbitrary integers.
2718        //the input arguments.  The storage does not belong to us.        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, sub_arg1);
2719        gcd_arg1 = Tcl_GetString(objv[2]);        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, sub_arg2);
2720        assert(gcd_arg1 != NULL);  
2721        gcd_arg2 = Tcl_GetString(objv[3]);        //If there was a parse failure, we have to return an error
2722        assert(gcd_arg2 != NULL);        //message.  It is possible that both arguments failed the parse,
2723          //but only return one in the error message.
2724        //Try to interpret either of the  strings as one of the NAN tags.        if (failure1 || failure2)
2725        //If it is one, return the appropriate result for           {
2726        //a binary operation.           rv = Tcl_NewStringObj("arbint intsub: \"", -1);
2727        i = GMP_INTS_identify_nan_string(gcd_arg1);           if (failure1)
2728        j = GMP_INTS_identify_nan_string(gcd_arg2);              Tcl_AppendToObj(rv, sub_arg1, -1);
2729             else
2730        if ((i >= 0) || (j >= 0))              Tcl_AppendToObj(rv, sub_arg2, -1);
2731           {  
2732           const char *p;           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);
2733             Tcl_SetObjResult(interp, rv);
2734           //Find the max of i and j.  This isn't a scientific way to tag the  
2735           //result, but will be OK.  Some information is lost no matter what           GMP_INTS_mpz_clear(&arb_arg1);
2736           //we do.           GMP_INTS_mpz_clear(&arb_arg2);
2737           if (i > j)           GMP_INTS_mpz_clear(&arb_result);
2738              ;  
2739           else           return(TCL_ERROR);
2740              i = j;           }
2741    
2742           //i now contains the max.        //Calculate the difference.
2743           switch (i)        GMP_INTS_mpz_sub(&arb_result, &arb_arg1, &arb_arg2);
2744              {  
2745              case 0:  p = GMP_INTS_supply_nan_string(2);        //Figure out the number of characters required for
2746                       break;        //the output string.
2747              case 1:  p = GMP_INTS_supply_nan_string(3);        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);
2748                       break;  
2749              case 2:  p = GMP_INTS_supply_nan_string(2);        //Allocate space for the conversion result.
2750                       break;        string_result = TclpAlloc(sizeof(char) * chars_reqd);
2751              case 3:  p = GMP_INTS_supply_nan_string(3);        assert(string_result != NULL);
2752                       break;  
2753              default:        //Make the conversion to a character string.
2754                       assert(0);        GMP_INTS_mpz_to_string(string_result, &arb_result);
2755                       break;  
2756              }        //Assign the string result to a Tcl object.
2757          rv = Tcl_NewStringObj(string_result, -1);
2758           rv = Tcl_NewStringObj(p, -1);  
2759           Tcl_SetObjResult(interp, rv);        //Deallocate the string.
2760          TclpFree(string_result);
2761           GMP_INTS_mpz_clear(&arb_arg1);  
2762           GMP_INTS_mpz_clear(&arb_arg2);        //Deallocate space for the arbitrary-length integers.
2763           GMP_INTS_mpz_clear(&arb_result);        GMP_INTS_mpz_clear(&arb_arg1);
2764          GMP_INTS_mpz_clear(&arb_arg2);
2765           return(TCL_OK);        GMP_INTS_mpz_clear(&arb_result);
2766           }  
2767          //Assign the result to be the return value.
2768        //Try to convert both strings into arbitrary integers.        Tcl_SetObjResult(interp, rv);
2769        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, gcd_arg1);  
2770        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, gcd_arg2);        //Return
2771          return(TCL_OK);
2772        //If there was a parse failure, we have to return an error        }
2773        //message.  It is possible that both arguments failed the parse,     }
2774        //but only return one in the error message.  
2775        if (failure1 || failure2)  
2776           {  //Handles the "iseflag" subextension.
2777           rv = Tcl_NewStringObj("arbint intgcd: \"", -1);  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this
2778           if (failure1)  //from memory an intuition as far as how to set return results and so forth.
2779              Tcl_AppendToObj(rv, gcd_arg1, -1);  static
2780           else  int ARBLENINTS_iseflag_handler(ClientData dummy,
2781              Tcl_AppendToObj(rv, gcd_arg2, -1);                                 Tcl_Interp *interp,
2782                                   int objc,
2783           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);                                 Tcl_Obj *objv[])
2784           Tcl_SetObjResult(interp, rv);     {
2785       Tcl_Obj *rv;
2786           GMP_INTS_mpz_clear(&arb_arg1);  
2787           GMP_INTS_mpz_clear(&arb_arg2);     //We must have one and exactly one additional argument
2788           GMP_INTS_mpz_clear(&arb_result);     //to this function, which is the string we want to
2789       //classify.
2790           return(TCL_ERROR);     if (objc != 3)
2791           }        {
2792          Tcl_WrongNumArgs(interp,
2793        //Calculate the gcd.                         2,
2794        GMP_INTS_mpz_gcd(&arb_result, &arb_arg1, &arb_arg2);                         objv,
2795                           "stringarg");
2796        //Figure out the number of characters required for        return(TCL_ERROR);
2797        //the output string.        }
2798        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);     else
2799          {
2800        //Allocate space for the conversion result.        char *string_arg;
2801        string_result = TclpAlloc(sizeof(char) * chars_reqd);  
2802        assert(string_result != NULL);        //Grab a pointer to the string representation of
2803          //the input argument.  The storage does not belong to us.
2804        //Make the conversion to a character string.        string_arg = Tcl_GetString(objv[2]);
2805        GMP_INTS_mpz_to_string(string_result, &arb_result);        assert(string_arg != NULL);
2806    
2807        //Assign the string result to a Tcl object.        //Try to parse it out.  We will definitely get one of
2808        rv = Tcl_NewStringObj(string_result, -1);        //the return values.
2809          if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_POS_STRING))
2810        //Deallocate the string.           {
2811        TclpFree(string_result);           rv = Tcl_NewStringObj("1", -1);
2812             }
2813        //Deallocate space for the arbitrary-length integers.        else if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_NEG_STRING))
2814        GMP_INTS_mpz_clear(&arb_arg1);           {
2815        GMP_INTS_mpz_clear(&arb_arg2);           rv = Tcl_NewStringObj("2", -1);
2816        GMP_INTS_mpz_clear(&arb_result);           }
2817          else if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_TAINT_POS_STRING))
2818        //Assign the result to be the return value.           {
2819        Tcl_SetObjResult(interp, rv);           rv = Tcl_NewStringObj("3", -1);
2820             }
2821        //Return        else if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_TAINT_NEG_STRING))
2822        return(TCL_OK);           {
2823        }           rv = Tcl_NewStringObj("4", -1);
2824     }           }
2825          else
2826             {
2827  //Handles the "intlcm" subextension.           rv = Tcl_NewStringObj("0", -1);
2828  //08/10/01:  Visual inspection OK.           }
2829  static  
2830  int ARBLENINTS_intlcm_handler(ClientData dummy,        //Assign the result to be the return value.
2831                                Tcl_Interp *interp,        Tcl_SetObjResult(interp, rv);
2832                                int objc,  
2833                                Tcl_Obj *objv[])        //Return
2834     {        return(TCL_OK);
2835     Tcl_Obj *rv;        }
2836       }
2837     //We must have two and exactly two additional arguments  
2838     //to this function, which are the integers whose  
2839     //lcm is to be calculated.  //08/08/01:  Visual inspection OK.
2840     if (objc != 4)  static
2841        {  int ARBLENINTS_rnadd_handler(ClientData dummy,
2842        Tcl_WrongNumArgs(interp,                               Tcl_Interp *interp,
2843                         2,                               int objc,
2844                         objv,                               Tcl_Obj *objv[])
2845                         "sint sint");     {
2846        return(TCL_ERROR);     Tcl_Obj *rv;
2847        }  
2848     else     //We must have exactly two additional arguments
2849        {     //to this function, which are the rational numbers
2850        GMP_INTS_mpz_struct arb_arg1, arb_arg2, gcd, remainder, arb_result;     //to add.
2851        char *lcm_arg1, *lcm_arg2;     if (objc != 4)
2852        int failure1, failure2;        {
2853        unsigned chars_reqd;        Tcl_WrongNumArgs(interp,
2854        char *string_result;                         2,
2855        int i, j;                         objv,
2856                           "srn srn");
2857        //Allocate space for the arbitrary-length integers.        return(TCL_ERROR);
2858        GMP_INTS_mpz_init(&arb_arg1);        }
2859        GMP_INTS_mpz_init(&arb_arg2);     else
2860        GMP_INTS_mpz_init(&gcd);        {
2861        GMP_INTS_mpz_init(&remainder);        char *input_arg;
2862        GMP_INTS_mpz_init(&arb_result);        int failure;
2863          char *string_result;
2864        //Grab pointers to the string representation of        GMP_RATS_mpq_struct arg1, arg2, result;
2865        //the input arguments.  The storage does not belong to us.  
2866        lcm_arg1 = Tcl_GetString(objv[2]);        //Allocate space for the rational numbers.
2867        assert(lcm_arg1 != NULL);        GMP_RATS_mpq_init(&arg1);
2868        lcm_arg2 = Tcl_GetString(objv[3]);        GMP_RATS_mpq_init(&arg2);
2869        assert(lcm_arg2 != NULL);        GMP_RATS_mpq_init(&result);
2870    
2871        //Try to interpret either of the  strings as one of the NAN tags.        //Grab a pointer to the string representation of
2872        //If it is one, return the appropriate result for        //the first input argument.  The storage does not belong to us.
2873        //a binary operation.        input_arg = Tcl_GetString(objv[2]);
2874        i = GMP_INTS_identify_nan_string(lcm_arg1);        assert(input_arg != NULL);
2875        j = GMP_INTS_identify_nan_string(lcm_arg2);  
2876          //Try to parse our first input string as a rational number.
2877        if ((i >= 0) || (j >= 0))        //If we are not successful in this, must abort.
2878           {        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
2879           const char *p;                                            &failure,
2880                                              &arg1);
2881           //Find the max of i and j.  This isn't a scientific way to tag the  
2882           //result, but will be OK.  Some information is lost no matter what        if (failure)
2883           //we do.           {
2884           if (i > j)           rv = Tcl_NewStringObj("arbint rnadd: \"", -1);
2885              ;           Tcl_AppendToObj(rv, input_arg, -1);
2886           else  
2887              i = j;           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
2888             Tcl_SetObjResult(interp, rv);
2889           //i now contains the max.  
2890           switch (i)           GMP_RATS_mpq_clear(&arg1);
2891              {           GMP_RATS_mpq_clear(&arg2);
2892              case 0:  p = GMP_INTS_supply_nan_string(2);           GMP_RATS_mpq_clear(&result);
2893                       break;  
2894              case 1:  p = GMP_INTS_supply_nan_string(3);           return(TCL_ERROR);
2895                       break;           }
2896              case 2:  p = GMP_INTS_supply_nan_string(2);  
2897                       break;        //Grab a pointer to the string representation of
2898              case 3:  p = GMP_INTS_supply_nan_string(3);        //the second input argument.  The storage does not belong to us.
2899                       break;        input_arg = Tcl_GetString(objv[3]);
2900              default:        assert(input_arg != NULL);
2901                       assert(0);  
2902                       break;        //Try to parse our second input string as a rational number.
2903              }        //If we are not successful in this, must abort.
2904          GMP_RATS_mpq_set_all_format_rat_num(input_arg,
2905           rv = Tcl_NewStringObj(p, -1);                                            &failure,
2906           Tcl_SetObjResult(interp, rv);                                            &arg2);
2907    
2908           GMP_INTS_mpz_clear(&arb_arg1);        if (failure)
2909           GMP_INTS_mpz_clear(&arb_arg2);           {
2910           GMP_INTS_mpz_clear(&gcd);           rv = Tcl_NewStringObj("arbint rnadd: \"", -1);
2911           GMP_INTS_mpz_clear(&remainder);           Tcl_AppendToObj(rv, input_arg, -1);
2912           GMP_INTS_mpz_clear(&arb_result);  
2913             Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
2914           return(TCL_OK);           Tcl_SetObjResult(interp, rv);
2915           }  
2916             GMP_RATS_mpq_clear(&arg1);
2917        //Try to convert both strings into arbitrary integers.           GMP_RATS_mpq_clear(&arg2);
2918        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, lcm_arg1);           GMP_RATS_mpq_clear(&result);
2919        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, lcm_arg2);  
2920             return(TCL_ERROR);
2921        //If there was a parse failure, we have to return an error           }
2922        //message.  It is possible that both arguments failed the parse,  
2923        //but only return one in the error message.        //Perform the actual addition of the rational numbers.  All
2924        if (failure1 || failure2)        //error cases are covered.  If either of the inputs has a
2925           {        //denominator of zero, this will propagate to the result.
2926           rv = Tcl_NewStringObj("arbint intlcm: \"", -1);        GMP_RATS_mpq_add(&result, &arg1, &arg2);
2927           if (failure1)  
2928              Tcl_AppendToObj(rv, lcm_arg1, -1);        //If the result has been NAN'd, return the string "NAN".
2929           else        if (GMP_RATS_mpq_is_nan(&result))
2930              Tcl_AppendToObj(rv, lcm_arg2, -1);           {
2931             rv = Tcl_NewStringObj("NAN", -1);
2932           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);  
2933           Tcl_SetObjResult(interp, rv);           Tcl_SetObjResult(interp, rv);
2934    
2935           GMP_INTS_mpz_clear(&arb_arg1);           GMP_RATS_mpq_clear(&arg1);
2936           GMP_INTS_mpz_clear(&arb_arg2);           GMP_RATS_mpq_clear(&arg2);
2937           GMP_INTS_mpz_clear(&gcd);           GMP_RATS_mpq_clear(&result);
2938           GMP_INTS_mpz_clear(&remainder);  
2939           GMP_INTS_mpz_clear(&arb_result);           return(TCL_OK);
2940             }
2941           return(TCL_ERROR);  
2942           }        //Allocate space for the string result which we'll form for
2943          //both numerator and denominator.  We need the maximum, because we'll only
2944        //Adjust errant arguments.        //do one number at a time.
2945        if (GMP_INTS_mpz_is_neg(&arb_arg1))        string_result = TclpAlloc(sizeof(char)
2946           GMP_INTS_mpz_negate(&arb_arg1);                                  *
2947        else if (GMP_INTS_mpz_is_zero(&arb_arg1))                                  INTFUNC_max
2948           GMP_INTS_mpz_set_ui(&arb_arg1, 1);                                     (
2949        if (GMP_INTS_mpz_is_neg(&arb_arg2))                                     GMP_INTS_mpz_size_in_base_10(&(result.num)),
2950           GMP_INTS_mpz_negate(&arb_arg2);                                     GMP_INTS_mpz_size_in_base_10(&(result.den))
2951        else if (GMP_INTS_mpz_is_zero(&arb_arg2))                                     )
2952           GMP_INTS_mpz_set_ui(&arb_arg2, 1);                                  );
2953                assert(string_result != NULL);
2954        //Calculate the gcd.  
2955        GMP_INTS_mpz_gcd(&gcd, &arb_arg1, &arb_arg2);        //Convert the numerator to a string and set that to be the
2956          //return value.
2957        //Calculate the lcm.        GMP_INTS_mpz_to_string(string_result, &(result.num));
2958        GMP_INTS_mpz_mul(&arb_arg1, &arb_arg1, &arb_arg2);        rv = Tcl_NewStringObj(string_result, -1);
2959        GMP_INTS_mpz_tdiv_qr(&arb_result, &remainder,  
2960                             &arb_arg1, &gcd);        //Append the separating slash.
2961          Tcl_AppendToObj(rv, "/", -1);
2962        //Figure out the number of characters required for  
2963        //the output string.        //Convert the denominator to a string and append that to the
2964        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);        //return value.
2965          GMP_INTS_mpz_to_string(string_result, &(result.den));
2966        //Allocate space for the conversion result.        Tcl_AppendToObj(rv, string_result, -1);
2967        string_result = TclpAlloc(sizeof(char) * chars_reqd);  
2968        assert(string_result != NULL);        //Assign the result to be the return value.
2969          Tcl_SetObjResult(interp, rv);
2970        //Make the conversion to a character string.  
2971        GMP_INTS_mpz_to_string(string_result, &arb_result);        //Free up all dynamic memory.
2972          TclpFree(string_result);
2973        //Assign the string result to a Tcl object.        GMP_RATS_mpq_clear(&arg1);
2974        rv = Tcl_NewStringObj(string_result, -1);        GMP_RATS_mpq_clear(&arg2);
2975          GMP_RATS_mpq_clear(&result);
2976        //Deallocate the string.  
2977        TclpFree(string_result);        //Return
2978          return(TCL_OK);
2979        //Deallocate space for the arbitrary-length integers.        }
2980        GMP_INTS_mpz_clear(&arb_arg1);     }
2981        GMP_INTS_mpz_clear(&arb_arg2);  
2982        GMP_INTS_mpz_clear(&gcd);  
2983        GMP_INTS_mpz_clear(&remainder);  //08/16/01: Visual inspection OK.  
2984        GMP_INTS_mpz_clear(&arb_result);  static
2985    int ARBLENINTS_rncmp_handler(ClientData dummy,
2986        //Assign the result to be the return value.                               Tcl_Interp *interp,
2987        Tcl_SetObjResult(interp, rv);                               int objc,
2988                                 Tcl_Obj *objv[])
2989        //Return     {
2990        return(TCL_OK);     Tcl_Obj *rv;
2991        }  
2992     }     //We must have exactly two additional arguments
2993       //to this function, which are the rational numbers
2994       //to compare.
2995  //Handles the "intmod" subextension.     if (objc != 4)
2996  //08/06/01:  Visual inspection OK.        {
2997  static        Tcl_WrongNumArgs(interp,
2998  int ARBLENINTS_intmod_handler(ClientData dummy,                         2,
2999                                Tcl_Interp *interp,                         objv,
3000                                int objc,                         "srn srn");
3001                                Tcl_Obj *objv[])        return(TCL_ERROR);
3002     {        }
3003     Tcl_Obj *rv;     else
3004          {
3005     //We must have two and exactly two additional arguments        char *input_arg;
3006     //to this function, which are the integers whose        int failure, compare_result;
3007     //integer quotient is to be calculated.        GMP_RATS_mpq_struct arg1, arg2;
3008     if (objc != 4)  
3009        {        //Allocate space for the rational numbers.
3010        Tcl_WrongNumArgs(interp,        GMP_RATS_mpq_init(&arg1);
3011                         2,        GMP_RATS_mpq_init(&arg2);
3012                         objv,  
3013                         "sint sint");        //Grab a pointer to the string representation of
3014        return(TCL_ERROR);        //the first input argument.  The storage does not belong to us.
3015        }        input_arg = Tcl_GetString(objv[2]);
3016     else        assert(input_arg != NULL);
3017        {  
3018        GMP_INTS_mpz_struct arb_dividend, arb_divisor, arb_quotient, arb_remainder;        //Try to parse our first input string as a rational number.
3019        char *dividend_arg1, *divisor_arg2;        //If we are not successful in this, must abort.
3020        int failure1, failure2;        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3021        unsigned chars_reqd;                                            &failure,
3022        char *string_result;                                            &arg1);
3023        int i, j;  
3024          if (failure)
3025        //Allocate space for the arbitrary-length integer arguments and results.           {
3026        GMP_INTS_mpz_init(&arb_dividend);           rv = Tcl_NewStringObj("arbint rncmp: \"", -1);
3027        GMP_INTS_mpz_init(&arb_divisor);           Tcl_AppendToObj(rv, input_arg, -1);
3028        GMP_INTS_mpz_init(&arb_quotient);  
3029        GMP_INTS_mpz_init(&arb_remainder);           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3030             Tcl_SetObjResult(interp, rv);
3031        //Grab pointers to the string representation of  
3032        //the input arguments.  The storage does not belong to us.           GMP_RATS_mpq_clear(&arg1);
3033        dividend_arg1 = Tcl_GetString(objv[2]);           GMP_RATS_mpq_clear(&arg2);
3034        assert(dividend_arg1 != NULL);  
3035        divisor_arg2 = Tcl_GetString(objv[3]);           return(TCL_ERROR);
3036        assert(divisor_arg2 != NULL);           }
3037    
3038        //Try to interpret either of the  strings as one of the NAN tags.        //Grab a pointer to the string representation of
3039        //If it is one, return the appropriate result for        //the second input argument.  The storage does not belong to us.
3040        //a binary operation.        input_arg = Tcl_GetString(objv[3]);
3041        i = GMP_INTS_identify_nan_string(dividend_arg1);        assert(input_arg != NULL);
3042        j = GMP_INTS_identify_nan_string(divisor_arg2);  
3043          //Try to parse our second input string as a rational number.
3044        if ((i >= 0) || (j >= 0))        //If we are not successful in this, must abort.
3045           {        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3046           const char *p;                                            &failure,
3047                                              &arg2);
3048           //Find the max of i and j.  This isn't a scientific way to tag the  
3049           //result, but will be OK.  Some information is lost no matter what        if (failure)
3050           //we do.           {
3051           if (i > j)           rv = Tcl_NewStringObj("arbint rncmp: \"", -1);
3052              ;           Tcl_AppendToObj(rv, input_arg, -1);
3053           else  
3054              i = j;           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3055             Tcl_SetObjResult(interp, rv);
3056           //i now contains the max.  
3057           switch (i)           GMP_RATS_mpq_clear(&arg1);
3058              {           GMP_RATS_mpq_clear(&arg2);
3059              case 0:  p = GMP_INTS_supply_nan_string(2);  
3060                       break;           return(TCL_ERROR);
3061              case 1:  p = GMP_INTS_supply_nan_string(3);           }
3062                       break;  
3063              case 2:  p = GMP_INTS_supply_nan_string(2);        //Perform the actual comparison of the rational numbers.  All
3064                       break;        //error cases are covered.  If either of the inputs has a
3065              case 3:  p = GMP_INTS_supply_nan_string(3);        //denominator of zero, this will propagate to the result.
3066                       break;        compare_result = GMP_RATS_mpq_cmp(&arg1, &arg2, &failure);
3067              default:  
3068                       assert(0);        //If the failure flag was thrown, we have to throw an error.
3069                       break;        //The reason is that if we can't successfully compare the two
3070              }        //rational numbers, then we have to kill the script--logical
3071          //correctness is not possible.
3072           rv = Tcl_NewStringObj(p, -1);        if (failure)
3073           Tcl_SetObjResult(interp, rv);           {
3074             rv = Tcl_NewStringObj("arbint rncmp: can't compare supplied rational numbers.", -1);
3075           GMP_INTS_mpz_clear(&arb_dividend);  
3076           GMP_INTS_mpz_clear(&arb_divisor);           Tcl_SetObjResult(interp, rv);
3077           GMP_INTS_mpz_clear(&arb_quotient);  
3078           GMP_INTS_mpz_clear(&arb_remainder);           GMP_RATS_mpq_clear(&arg1);
3079             GMP_RATS_mpq_clear(&arg2);
3080           return(TCL_OK);  
3081           }           return(TCL_ERROR);
3082             }
3083        //Try to convert both strings into arbitrary integers.  
3084        GMP_INTS_mpz_set_general_int(&arb_dividend, &failure1, dividend_arg1);        //Convert the comparison result to a string.
3085        GMP_INTS_mpz_set_general_int(&arb_divisor,  &failure2, divisor_arg2);        if (compare_result < 0)
3086             rv = Tcl_NewStringObj("-1", -1);
3087        //If there was a parse failure, we have to return an error        else if (compare_result == 0)
3088        //message.  It is possible that both arguments failed the parse,           rv = Tcl_NewStringObj("0", -1);
3089        //but only return one in the error message.        else
3090        if (failure1 || failure2)           rv = Tcl_NewStringObj("1", -1);
3091           {  
3092           rv = Tcl_NewStringObj("arbint intmod: \"", -1);        //Assign the result to be the return value.
3093           if (failure1)        Tcl_SetObjResult(interp, rv);
3094              Tcl_AppendToObj(rv, dividend_arg1, -1);  
3095           else        //Free up all dynamic memory.
3096              Tcl_AppendToObj(rv, divisor_arg2, -1);        GMP_RATS_mpq_clear(&arg1);
3097          GMP_RATS_mpq_clear(&arg2);
3098           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);  
3099           Tcl_SetObjResult(interp, rv);        //Return
3100          return(TCL_OK);
3101           GMP_INTS_mpz_clear(&arb_dividend);        }
3102           GMP_INTS_mpz_clear(&arb_divisor);     }
3103           GMP_INTS_mpz_clear(&arb_quotient);  
3104           GMP_INTS_mpz_clear(&arb_remainder);  
3105    //08/09/01:  Visual inspection OK.
3106           return(TCL_ERROR);  static
3107           }  int ARBLENINTS_rndiv_handler(ClientData dummy,
3108                                 Tcl_Interp *interp,
3109        //Calculate the quotient and remainder.                               int objc,
3110        GMP_INTS_mpz_tdiv_qr(&arb_quotient, &arb_remainder, &arb_dividend, &arb_divisor);                               Tcl_Obj *objv[])
3111       {
3112        //Figure out the number of characters required for     Tcl_Obj *rv;
3113        //the output string.  
3114        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_remainder);     //We must have exactly two additional arguments
3115       //to this function, which are the rational numbers
3116        //Allocate space for the conversion result.     //to divide.
3117        string_result = TclpAlloc(sizeof(char) * chars_reqd);     if (objc != 4)
3118        assert(string_result != NULL);        {
3119          Tcl_WrongNumArgs(interp,
3120        //Make the conversion to a character string.                         2,
3121        GMP_INTS_mpz_to_string(string_result, &arb_remainder);                         objv,
3122                           "srn srn");
3123        //Assign the string result to a Tcl object.        return(TCL_ERROR);
3124        rv = Tcl_NewStringObj(string_result, -1);        }
3125       else
3126        //Deallocate the string.        {
3127        TclpFree(string_result);        char *input_arg;
3128          int failure;
3129        //Deallocate space for the arbitrary-length integers.        char *string_result;
3130        GMP_INTS_mpz_clear(&arb_dividend);        GMP_RATS_mpq_struct arg1, arg2, result;
3131        GMP_INTS_mpz_clear(&arb_divisor);  
3132        GMP_INTS_mpz_clear(&arb_quotient);        //Allocate space for the rational numbers.
3133        GMP_INTS_mpz_clear(&arb_remainder);        GMP_RATS_mpq_init(&arg1);
3134          GMP_RATS_mpq_init(&arg2);
3135        //Assign the result to be the return value.        GMP_RATS_mpq_init(&result);
3136        Tcl_SetObjResult(interp, rv);  
3137          //Grab a pointer to the string representation of
3138        //Return        //the first input argument.  The storage does not belong to us.
3139        return(TCL_OK);        input_arg = Tcl_GetString(objv[2]);
3140        }        assert(input_arg != NULL);
3141     }  
3142          //Try to parse our first input string as a rational number.
3143          //If we are not successful in this, must abort.
3144  //Handles the "intmul" subextension.        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3145  //08/06/01:  Visual inspection OK.                                            &failure,
3146  static                                            &arg1);
3147  int ARBLENINTS_intmul_handler(ClientData dummy,  
3148                                Tcl_Interp *interp,        if (failure)
3149                                int objc,           {
3150                                Tcl_Obj *objv[])           rv = Tcl_NewStringObj("arbint rndiv: \"", -1);
3151     {           Tcl_AppendToObj(rv, input_arg, -1);
3152     Tcl_Obj *rv;  
3153             Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3154     //We must have two and exactly two additional arguments           Tcl_SetObjResult(interp, rv);
3155     //to this function, which are the integers whose  
3156     //product is to be calculated.           GMP_RATS_mpq_clear(&arg1);
3157     if (objc != 4)           GMP_RATS_mpq_clear(&arg2);
3158        {           GMP_RATS_mpq_clear(&result);
3159        Tcl_WrongNumArgs(interp,  
3160                         2,           return(TCL_ERROR);
3161                         objv,           }
3162                         "sint sint");  
3163        return(TCL_ERROR);        //Grab a pointer to the string representation of
3164        }        //the second input argument.  The storage does not belong to us.
3165     else        input_arg = Tcl_GetString(objv[3]);
3166        {        assert(input_arg != NULL);
3167        GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;  
3168        char *mul_arg1, *mul_arg2;        //Try to parse our second input string as a rational number.
3169        int failure1, failure2;        //If we are not successful in this, must abort.
3170        unsigned chars_reqd;        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3171        char *string_result;                                            &failure,
3172        int i, j;                                            &arg2);
3173    
3174        //Allocate space for the arbitrary-length integer result.        if (failure)
3175        GMP_INTS_mpz_init(&arb_arg1);           {
3176        GMP_INTS_mpz_init(&arb_arg2);           rv = Tcl_NewStringObj("arbint rndiv: \"", -1);
3177        GMP_INTS_mpz_init(&arb_result);           Tcl_AppendToObj(rv, input_arg, -1);
3178    
3179        //Grab pointers to the string representation of           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3180        //the input arguments.  The storage does not belong to us.           Tcl_SetObjResult(interp, rv);
3181        mul_arg1 = Tcl_GetString(objv[2]);  
3182        assert(mul_arg1 != NULL);           GMP_RATS_mpq_clear(&arg1);
3183        mul_arg2 = Tcl_GetString(objv[3]);           GMP_RATS_mpq_clear(&arg2);
3184        assert(mul_arg2 != NULL);           GMP_RATS_mpq_clear(&result);
3185    
3186        //Try to interpret either of the  strings as one of the NAN tags.           return(TCL_ERROR);
3187        //If it is one, return the appropriate result for           }
3188        //a binary operation.  
3189        i = GMP_INTS_identify_nan_string(mul_arg1);        //Perform the actual division of the rational numbers.  All
3190        j = GMP_INTS_identify_nan_string(mul_arg2);        //error cases are covered.  If either of the inputs has a
3191          //denominator of zero, this will propagate to the result.
3192        if ((i >= 0) || (j >= 0))        GMP_RATS_mpq_div(&result, &arg1, &arg2);
3193           {  
3194           const char *p;        //If the result has been NAN'd, return the string "NAN".
3195          if (GMP_RATS_mpq_is_nan(&result))
3196           //Find the max of i and j.  This isn't a scientific way to tag the           {
3197           //result, but will be OK.  Some information is lost no matter what           rv = Tcl_NewStringObj("NAN", -1);
3198           //we do.  
3199           if (i > j)           Tcl_SetObjResult(interp, rv);
3200              ;  
3201           else           GMP_RATS_mpq_clear(&arg1);
3202              i = j;           GMP_RATS_mpq_clear(&arg2);
3203             GMP_RATS_mpq_clear(&result);
3204           //i now contains the max.  
3205           switch (i)           return(TCL_OK);
3206              {           }
3207              case 0:  p = GMP_INTS_supply_nan_string(2);  
3208                       break;        //Allocate space for the string result which we'll form for
3209              case 1:  p = GMP_INTS_supply_nan_string(3);        //both numerator and denominator.  We need the maximum, because we'll only
3210                       break;        //do one number at a time.
3211              case 2:  p = GMP_INTS_supply_nan_string(2);        string_result = TclpAlloc(sizeof(char)
3212                       break;                                  *
3213              case 3:  p = GMP_INTS_supply_nan_string(3);                                  INTFUNC_max
3214                       break;                                     (
3215              default:                                     GMP_INTS_mpz_size_in_base_10(&(result.num)),
3216                       assert(0);                                     GMP_INTS_mpz_size_in_base_10(&(result.den))
3217                       break;                                     )
3218              }                                  );
3219          assert(string_result != NULL);
3220           rv = Tcl_NewStringObj(p, -1);  
3221           Tcl_SetObjResult(interp, rv);        //Convert the numerator to a string and set that to be the
3222          //return value.
3223           GMP_INTS_mpz_clear(&arb_arg1);        GMP_INTS_mpz_to_string(string_result, &(result.num));
3224           GMP_INTS_mpz_clear(&arb_arg2);        rv = Tcl_NewStringObj(string_result, -1);
3225           GMP_INTS_mpz_clear(&arb_result);  
3226          //Append the separating slash.
3227           return(TCL_OK);        Tcl_AppendToObj(rv, "/", -1);
3228           }  
3229          //Convert the denominator to a string and append that to the
3230        //Try to convert both strings into arbitrary integers.        //return value.
3231        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, mul_arg1);        GMP_INTS_mpz_to_string(string_result, &(result.den));
3232        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, mul_arg2);        Tcl_AppendToObj(rv, string_result, -1);
3233    
3234        //If there was a parse failure, we have to return an error        //Assign the result to be the return value.
3235        //message.  It is possible that both arguments failed the parse,        Tcl_SetObjResult(interp, rv);
3236        //but only return one in the error message.  
3237        if (failure1 || failure2)        //Free up all dynamic memory.
3238           {        TclpFree(string_result);
3239           rv = Tcl_NewStringObj("arbint intmul: \"", -1);        GMP_RATS_mpq_clear(&arg1);
3240           if (failure1)        GMP_RATS_mpq_clear(&arg2);
3241              Tcl_AppendToObj(rv, mul_arg1, -1);        GMP_RATS_mpq_clear(&result);
3242           else  
3243              Tcl_AppendToObj(rv, mul_arg2, -1);        //Return
3244          return(TCL_OK);
3245           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);        }
3246           Tcl_SetObjResult(interp, rv);     }
3247    
3248           GMP_INTS_mpz_clear(&arb_arg1);  
3249           GMP_INTS_mpz_clear(&arb_arg2);  //08/09/01:  Visual inspection OK.
3250           GMP_INTS_mpz_clear(&arb_result);  static
3251    int ARBLENINTS_rnmul_handler(ClientData dummy,
3252           return(TCL_ERROR);                               Tcl_Interp *interp,
3253           }                               int objc,
3254                                 Tcl_Obj *objv[])
3255        //Calculate the product.     {
3256        GMP_INTS_mpz_mul(&arb_result, &arb_arg1, &arb_arg2);     Tcl_Obj *rv;
3257    
3258        //Figure out the number of characters required for     //We must have exactly two additional arguments
3259        //the output string.     //to this function, which are the rational numbers
3260        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);     //to add.
3261       if (objc != 4)
3262        //Allocate space for the conversion result.        {
3263        string_result = TclpAlloc(sizeof(char) * chars_reqd);        Tcl_WrongNumArgs(interp,
3264        assert(string_result != NULL);                         2,
3265                           objv,
3266        //Make the conversion to a character string.                         "srn srn");
3267        GMP_INTS_mpz_to_string(string_result, &arb_result);        return(TCL_ERROR);
3268          }
3269        //Assign the string result to a Tcl object.     else
3270        rv = Tcl_NewStringObj(string_result, -1);        {
3271          char *input_arg;
3272        //Deallocate the string.        int failure;
3273        TclpFree(string_result);        char *string_result;
3274          GMP_RATS_mpq_struct arg1, arg2, result;
3275        //Deallocate space for the arbitrary-length integers.  
3276        GMP_INTS_mpz_clear(&arb_arg1);        //Allocate space for the rational numbers.
3277        GMP_INTS_mpz_clear(&arb_arg2);        GMP_RATS_mpq_init(&arg1);
3278        GMP_INTS_mpz_clear(&arb_result);        GMP_RATS_mpq_init(&arg2);
3279          GMP_RATS_mpq_init(&result);
3280        //Assign the result to be the return value.  
3281        Tcl_SetObjResult(interp, rv);        //Grab a pointer to the string representation of
3282          //the first input argument.  The storage does not belong to us.
3283        //Return        input_arg = Tcl_GetString(objv[2]);
3284        return(TCL_OK);        assert(input_arg != NULL);
3285        }  
3286     }        //Try to parse our first input string as a rational number.
3287          //If we are not successful in this, must abort.
3288          GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3289  //Handles the "intsub" subextension.                                            &failure,
3290  //08/06/01:  Visual inspection OK.                                            &arg1);
3291  static  
3292  int ARBLENINTS_intsub_handler(ClientData dummy,        if (failure)
3293                                Tcl_Interp *interp,           {
3294                                int objc,           rv = Tcl_NewStringObj("arbint rnmul: \"", -1);
3295                                Tcl_Obj *objv[])           Tcl_AppendToObj(rv, input_arg, -1);
3296     {  
3297     Tcl_Obj *rv;           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3298             Tcl_SetObjResult(interp, rv);
3299     //We must have two and exactly two additional arguments  
3300     //to this function, which are the integers whose           GMP_RATS_mpq_clear(&arg1);
3301     //difference is to be calculated.           GMP_RATS_mpq_clear(&arg2);
3302     if (objc != 4)           GMP_RATS_mpq_clear(&result);
3303        {  
3304        Tcl_WrongNumArgs(interp,           return(TCL_ERROR);
3305                         2,           }
3306                         objv,  
3307                         "sint sint");        //Grab a pointer to the string representation of
3308        return(TCL_ERROR);        //the second input argument.  The storage does not belong to us.
3309        }        input_arg = Tcl_GetString(objv[3]);
3310     else        assert(input_arg != NULL);
3311        {  
3312        GMP_INTS_mpz_struct arb_arg1, arb_arg2, arb_result;        //Try to parse our second input string as a rational number.
3313        char *sub_arg1, *sub_arg2;        //If we are not successful in this, must abort.
3314        int failure1, failure2;        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3315        unsigned chars_reqd;                                            &failure,
3316        char *string_result;                                            &arg2);
3317        int i, j;  
3318          if (failure)
3319        //Allocate space for the arbitrary-length integer result.           {
3320        GMP_INTS_mpz_init(&arb_arg1);           rv = Tcl_NewStringObj("arbint rnmul: \"", -1);
3321        GMP_INTS_mpz_init(&arb_arg2);           Tcl_AppendToObj(rv, input_arg, -1);
3322        GMP_INTS_mpz_init(&arb_result);  
3323             Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3324        //Grab pointers to the string representation of           Tcl_SetObjResult(interp, rv);
3325        //the input arguments.  The storage does not belong to us.  
3326        sub_arg1 = Tcl_GetString(objv[2]);           GMP_RATS_mpq_clear(&arg1);
3327        assert(sub_arg1 != NULL);           GMP_RATS_mpq_clear(&arg2);
3328        sub_arg2 = Tcl_GetString(objv[3]);           GMP_RATS_mpq_clear(&result);
3329        assert(sub_arg2 != NULL);  
3330             return(TCL_ERROR);
3331        //Try to interpret either of the  strings as one of the NAN tags.           }
3332        //If it is one, return the appropriate result for  
3333        //a binary operation.        //Perform the actual multiplication of the rational numbers.  All
3334        i = GMP_INTS_identify_nan_string(sub_arg1);        //error cases are covered.  If either of the inputs has a
3335        j = GMP_INTS_identify_nan_string(sub_arg2);        //denominator of zero, this will propagate to the result.
3336          GMP_RATS_mpq_mul(&result, &arg1, &arg2);
3337        if ((i >= 0) || (j >= 0))  
3338           {        //If the result has been NAN'd, return the string "NAN".
3339           const char *p;        if (GMP_RATS_mpq_is_nan(&result))
3340             {
3341           //Find the max of i and j.  This isn't a scientific way to tag the           rv = Tcl_NewStringObj("NAN", -1);
3342           //result, but will be OK.  Some information is lost no matter what  
3343           //we do.           Tcl_SetObjResult(interp, rv);
3344           if (i > j)  
3345              ;           GMP_RATS_mpq_clear(&arg1);
3346           else           GMP_RATS_mpq_clear(&arg2);
3347              i = j;           GMP_RATS_mpq_clear(&result);
3348    
3349           //i now contains the max.           return(TCL_OK);
3350           switch (i)           }
3351              {  
3352              case 0:  p = GMP_INTS_supply_nan_string(2);        //Allocate space for the string result which we'll form for
3353                       break;        //both numerator and denominator.  We need the maximum, because we'll only
3354              case 1:  p = GMP_INTS_supply_nan_string(3);        //do one number at a time.
3355                       break;        string_result = TclpAlloc(sizeof(char)
3356              case 2:  p = GMP_INTS_supply_nan_string(2);                                  *
3357                       break;                                  INTFUNC_max
3358              case 3:  p = GMP_INTS_supply_nan_string(3);                                     (
3359                       break;                                     GMP_INTS_mpz_size_in_base_10(&(result.num)),
3360              default:                                     GMP_INTS_mpz_size_in_base_10(&(result.den))
3361                       assert(0);                                     )
3362                       break;                                  );
3363              }        assert(string_result != NULL);
3364    
3365           rv = Tcl_NewStringObj(p, -1);        //Convert the numerator to a string and set that to be the
3366           Tcl_SetObjResult(interp, rv);        //return value.
3367          GMP_INTS_mpz_to_string(string_result, &(result.num));
3368           GMP_INTS_mpz_clear(&arb_arg1);        rv = Tcl_NewStringObj(string_result, -1);
3369           GMP_INTS_mpz_clear(&arb_arg2);  
3370           GMP_INTS_mpz_clear(&arb_result);        //Append the separating slash.
3371          Tcl_AppendToObj(rv, "/", -1);
3372           return(TCL_OK);  
3373           }        //Convert the denominator to a string and append that to the
3374          //return value.
3375        //Try to convert both strings into arbitrary integers.        GMP_INTS_mpz_to_string(string_result, &(result.den));
3376        GMP_INTS_mpz_set_general_int(&arb_arg1, &failure1, sub_arg1);        Tcl_AppendToObj(rv, string_result, -1);
3377        GMP_INTS_mpz_set_general_int(&arb_arg2, &failure2, sub_arg2);  
3378          //Assign the result to be the return value.
3379        //If there was a parse failure, we have to return an error        Tcl_SetObjResult(interp, rv);
3380        //message.  It is possible that both arguments failed the parse,  
3381        //but only return one in the error message.        //Free up all dynamic memory.
3382        if (failure1 || failure2)        TclpFree(string_result);
3383           {        GMP_RATS_mpq_clear(&arg1);
3384           rv = Tcl_NewStringObj("arbint intsub: \"", -1);        GMP_RATS_mpq_clear(&arg2);
3385           if (failure1)        GMP_RATS_mpq_clear(&result);
3386              Tcl_AppendToObj(rv, sub_arg1, -1);  
3387           else        //Return
3388              Tcl_AppendToObj(rv, sub_arg2, -1);        return(TCL_OK);
3389          }
3390           Tcl_AppendToObj(rv, "\" is not a recognized signed integer.", -1);     }
3391           Tcl_SetObjResult(interp, rv);  
3392    
3393           GMP_INTS_mpz_clear(&arb_arg1);  //08/09/01:  Visual inspection OK.
3394           GMP_INTS_mpz_clear(&arb_arg2);  static
3395           GMP_INTS_mpz_clear(&arb_result);  int ARBLENINTS_rnred_handler(ClientData dummy,
3396                                 Tcl_Interp *interp,
3397           return(TCL_ERROR);                               int objc,
3398           }                               Tcl_Obj *objv[])
3399       {
3400        //Calculate the difference.     Tcl_Obj *rv;
3401        GMP_INTS_mpz_sub(&arb_result, &arb_arg1, &arb_arg2);  
3402       //We must have exactly one additional argument
3403        //Figure out the number of characters required for     //to this function, which is the rational number
3404        //the output string.     //to provide the fully reduced form of.
3405        chars_reqd = GMP_INTS_mpz_size_in_base_10(&arb_result);     if (objc != 3)
3406          {
3407        //Allocate space for the conversion result.        Tcl_WrongNumArgs(interp,
3408        string_result = TclpAlloc(sizeof(char) * chars_reqd);                         2,
3409        assert(string_result != NULL);                         objv,
3410                           "srn");
3411        //Make the conversion to a character string.        return(TCL_ERROR);
3412        GMP_INTS_mpz_to_string(string_result, &arb_result);        }
3413       else
3414        //Assign the string result to a Tcl object.        {
3415        rv = Tcl_NewStringObj(string_result, -1);        char *input_arg;
3416          int failure;
3417        //Deallocate the string.        char *string_result;
3418        TclpFree(string_result);        GMP_RATS_mpq_struct rn;
3419    
3420        //Deallocate space for the arbitrary-length integers.        //We will need a rational number to hold the return value
3421        GMP_INTS_mpz_clear(&arb_arg1);        //from the parsing function.  Allocate that now.
3422        GMP_INTS_mpz_clear(&arb_arg2);        GMP_RATS_mpq_init(&rn);
3423        GMP_INTS_mpz_clear(&arb_result);  
3424          //Grab a pointer to the string representation of
3425        //Assign the result to be the return value.        //the input argument.  The storage does not belong to us.
3426        Tcl_SetObjResult(interp, rv);        input_arg = Tcl_GetString(objv[2]);
3427          assert(input_arg != NULL);
3428        //Return  
3429        return(TCL_OK);        //Try to parse our input string as a rational number.
3430        }        //If we are not successful in this, must abort.
3431     }        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3432                                              &failure,
3433                                              &rn);
3434  //Handles the "iseflag" subextension.  
3435  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this        if (failure)
3436  //from memory an intuition as far as how to set return results and so forth.           {
3437  static           rv = Tcl_NewStringObj("arbint rnred: \"", -1);
3438  int ARBLENINTS_iseflag_handler(ClientData dummy,           Tcl_AppendToObj(rv, input_arg, -1);
3439                                 Tcl_Interp *interp,  
3440                                 int objc,           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3441                                 Tcl_Obj *objv[])           Tcl_SetObjResult(interp, rv);
3442     {  
3443     Tcl_Obj *rv;           GMP_RATS_mpq_clear(&rn);
3444    
3445     //We must have one and exactly one additional argument           return(TCL_ERROR);
3446     //to this function, which is the string we want to           }
3447     //classify.  
3448     if (objc != 3)        //Normalize the rational number.  This takes care of the
3449        {        //sign and also of the coprimality of numerator and
3450        Tcl_WrongNumArgs(interp,        //denominator.
3451                         2,        GMP_RATS_mpq_normalize(&rn);
3452                         objv,  
3453                         "stringarg");        //Allocate space for the string result which we'll form for
3454        return(TCL_ERROR);        //both numbers.  We need the maximum, because we'll only
3455        }        //do one number at a time.
3456     else        string_result = TclpAlloc(sizeof(char)
3457        {                                  *
3458        char *string_arg;                                  INTFUNC_max
3459                                       (
3460        //Grab a pointer to the string representation of                                     GMP_INTS_mpz_size_in_base_10(&(rn.num)),
3461        //the input argument.  The storage does not belong to us.                                     GMP_INTS_mpz_size_in_base_10(&(rn.den))
3462        string_arg = Tcl_GetString(objv[2]);                                     )
3463        assert(string_arg != NULL);                                  );
3464          assert(string_result != NULL);
3465        //Try to parse it out.  We will definitely get one of  
3466        //the return values.        //Convert the numerator to a string and set that to be the
3467        if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_POS_STRING))        //return value.
3468           {        GMP_INTS_mpz_to_string(string_result, &(rn.num));
3469           rv = Tcl_NewStringObj("1", -1);        rv = Tcl_NewStringObj(string_result, -1);
3470           }  
3471        else if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_NEG_STRING))        //Append the separating slash.
3472           {        Tcl_AppendToObj(rv, "/", -1);
3473           rv = Tcl_NewStringObj("2", -1);  
3474           }        //Convert the denominator to a string and append that to the
3475        else if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_TAINT_POS_STRING))        //return value.
3476           {        GMP_INTS_mpz_to_string(string_result, &(rn.den));
3477           rv = Tcl_NewStringObj("3", -1);        Tcl_AppendToObj(rv, string_result, -1);
3478           }  
3479        else if (!strcmp(string_arg, GMP_INTS_EF_INTOVF_TAINT_NEG_STRING))        //Assign the result to be the return value.
3480           {        Tcl_SetObjResult(interp, rv);
3481           rv = Tcl_NewStringObj("4", -1);  
3482           }        //Free up all dynamic memory.
3483        else        TclpFree(string_result);
3484           {        GMP_RATS_mpq_clear(&rn);
3485           rv = Tcl_NewStringObj("0", -1);  
3486           }        //Return
3487          return(TCL_OK);
3488        //Assign the result to be the return value.        }
3489        Tcl_SetObjResult(interp, rv);     }
3490    
3491        //Return  
3492        return(TCL_OK);  //08/08/01:  Visual inspection OK.
3493        }  static
3494     }  int ARBLENINTS_rnsub_handler(ClientData dummy,
3495                                 Tcl_Interp *interp,
3496                                 int objc,
3497  //08/08/01:  Visual inspection OK.                               Tcl_Obj *objv[])
3498  static     {
3499  int ARBLENINTS_rnadd_handler(ClientData dummy,     Tcl_Obj *rv;
3500                               Tcl_Interp *interp,  
3501                               int objc,     //We must have exactly two additional arguments
3502                               Tcl_Obj *objv[])     //to this function, which are the rational numbers
3503     {     //to subtract.
3504     Tcl_Obj *rv;     if (objc != 4)
3505          {
3506     //We must have exactly two additional arguments        Tcl_WrongNumArgs(interp,
3507     //to this function, which are the rational numbers                         2,
3508     //to add.                         objv,
3509     if (objc != 4)                         "srn srn");
3510        {        return(TCL_ERROR);
3511        Tcl_WrongNumArgs(interp,        }
3512                         2,     else
3513                         objv,        {
3514                         "srn srn");        char *input_arg;
3515        return(TCL_ERROR);        int failure;
3516        }        char *string_result;
3517     else        GMP_RATS_mpq_struct arg1, arg2, result;
3518        {  
3519        char *input_arg;        //Allocate space for the rational numbers.
3520        int failure;        GMP_RATS_mpq_init(&arg1);
3521        char *string_result;        GMP_RATS_mpq_init(&arg2);
3522        GMP_RATS_mpq_struct arg1, arg2, result;        GMP_RATS_mpq_init(&result);
3523    
3524        //Allocate space for the rational numbers.        //Grab a pointer to the string representation of
3525        GMP_RATS_mpq_init(&arg1);        //the first input argument.  The storage does not belong to us.
3526        GMP_RATS_mpq_init(&arg2);        input_arg = Tcl_GetString(objv[2]);
3527        GMP_RATS_mpq_init(&result);        assert(input_arg != NULL);
3528    
3529        //Grab a pointer to the string representation of        //Try to parse our first input string as a rational number.
3530        //the first input argument.  The storage does not belong to us.        //If we are not successful in this, must abort.
3531        input_arg = Tcl_GetString(objv[2]);        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3532        assert(input_arg != NULL);                                            &failure,
3533                                              &arg1);
3534        //Try to parse our first input string as a rational number.  
3535        //If we are not successful in this, must abort.        if (failure)
3536        GMP_RATS_mpq_set_all_format_rat_num(input_arg,           {
3537                                            &failure,           rv = Tcl_NewStringObj("arbint rnsub: \"", -1);
3538                                            &arg1);           Tcl_AppendToObj(rv, input_arg, -1);
3539    
3540        if (failure)           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3541           {           Tcl_SetObjResult(interp, rv);
3542           rv = Tcl_NewStringObj("arbint rnadd: \"", -1);  
3543           Tcl_AppendToObj(rv, input_arg, -1);           GMP_RATS_mpq_clear(&arg1);
3544             GMP_RATS_mpq_clear(&arg2);
3545           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);           GMP_RATS_mpq_clear(&result);
3546           Tcl_SetObjResult(interp, rv);  
3547             return(TCL_ERROR);
3548           GMP_RATS_mpq_clear(&arg1);           }
3549           GMP_RATS_mpq_clear(&arg2);  
3550           GMP_RATS_mpq_clear(&result);        //Grab a pointer to the string representation of
3551          //the second input argument.  The storage does not belong to us.
3552           return(TCL_ERROR);        input_arg = Tcl_GetString(objv[3]);
3553           }        assert(input_arg != NULL);
3554    
3555        //Grab a pointer to the string representation of        //Try to parse our second input string as a rational number.
3556        //the second input argument.  The storage does not belong to us.        //If we are not successful in this, must abort.
3557        input_arg = Tcl_GetString(objv[3]);        GMP_RATS_mpq_set_all_format_rat_num(input_arg,
3558        assert(input_arg != NULL);                                            &failure,
3559                                              &arg2);
3560        //Try to parse our second input string as a rational number.  
3561        //If we are not successful in this, must abort.        if (failure)
3562        GMP_RATS_mpq_set_all_format_rat_num(input_arg,           {
3563                                            &failure,           rv = Tcl_NewStringObj("arbint rnsub: \"", -1);
3564                                            &arg2);           Tcl_AppendToObj(rv, input_arg, -1);
3565    
3566        if (failure)           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);
3567           {           Tcl_SetObjResult(interp, rv);
3568           rv = Tcl_NewStringObj("arbint rnadd: \"", -1);  
3569           Tcl_AppendToObj(rv, input_arg, -1);           GMP_RATS_mpq_clear(&arg1);
3570             GMP_RATS_mpq_clear(&arg2);
3571           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);           GMP_RATS_mpq_clear(&result);
3572           Tcl_SetObjResult(interp, rv);  
3573             return(TCL_ERROR);
3574           GMP_RATS_mpq_clear(&arg1);           }
3575           GMP_RATS_mpq_clear(&arg2);  
3576           GMP_RATS_mpq_clear(&result);        //Perform the actual subtraction of the rational numbers.  All
3577          //error cases are covered.  If either of the inputs has a
3578           return(TCL_ERROR);        //denominator of zero, this will propagate to the result.
3579           }        GMP_RATS_mpq_sub(&result, &arg1, &arg2);
3580    
3581        //Perform the actual addition of the rational numbers.  All        //If the result has been NAN'd, return the string "NAN".
3582        //error cases are covered.  If either of the inputs has a        if (GMP_RATS_mpq_is_nan(&result))
3583        //denominator of zero, this will propagate to the result.           {
3584        GMP_RATS_mpq_add(&result, &arg1, &arg2);           rv = Tcl_NewStringObj("NAN", -1);
3585    
3586        //If the result has been NAN'd, return the string "NAN".           Tcl_SetObjResult(interp, rv);
3587        if (GMP_RATS_mpq_is_nan(&result))  
3588           {           GMP_RATS_mpq_clear(&arg1);
3589           rv = Tcl_NewStringObj("NAN", -1);           GMP_RATS_mpq_clear(&arg2);
3590             GMP_RATS_mpq_clear(&result);
3591           Tcl_SetObjResult(interp, rv);  
3592             return(TCL_OK);
3593           GMP_RATS_mpq_clear(&arg1);           }
3594           GMP_RATS_mpq_clear(&arg2);  
3595           GMP_RATS_mpq_clear(&result);        //Allocate space for the string result which we'll form for
3596          //both numerator and denominator.  We need the maximum, because we'll only
3597           return(TCL_OK);        //do one number at a time.
3598           }        string_result = TclpAlloc(sizeof(char)
3599                                    *
3600        //Allocate space for the string result which we'll form for                                  INTFUNC_max
3601        //both numerator and denominator.  We need the maximum, because we'll only                                     (
3602        //do one number at a time.                                     GMP_INTS_mpz_size_in_base_10(&(result.num)),
3603        string_result = TclpAlloc(sizeof(char)                                     GMP_INTS_mpz_size_in_base_10(&(result.den))
3604                                  *                                     )
3605                                  INTFUNC_max                                  );
3606                                     (        assert(string_result != NULL);
3607                                     GMP_INTS_mpz_size_in_base_10(&(result.num)),  
3608                                     GMP_INTS_mpz_size_in_base_10(&(result.den))        //Convert the numerator to a string and set that to be the
3609                                     )        //return value.
3610                                  );        GMP_INTS_mpz_to_string(string_result, &(result.num));
3611        assert(string_result != NULL);        rv = Tcl_NewStringObj(string_result, -1);
3612    
3613        //Convert the numerator to a string and set that to be the        //Append the separating slash.
3614        //return value.        Tcl_AppendToObj(rv, "/", -1);
3615        GMP_INTS_mpz_to_string(string_result, &(result.num));  
3616        rv = Tcl_NewStringObj(string_result, -1);        //Convert the denominator to a string and append that to the
3617          //return value.
3618        //Append the separating slash.        GMP_INTS_mpz_to_string(string_result, &(result.den));
3619        Tcl_AppendToObj(rv, "/", -1);        Tcl_AppendToObj(rv, string_result, -1);
3620    
3621        //Convert the denominator to a string and append that to the        //Assign the result to be the return value.
3622        //return value.        Tcl_SetObjResult(interp, rv);
3623        GMP_INTS_mpz_to_string(string_result, &(result.den));  
3624        Tcl_AppendToObj(rv, string_result, -1);        //Free up all dynamic memory.
3625          TclpFree(string_result);
3626        //Assign the result to be the return value.        GMP_RATS_mpq_clear(&arg1);
3627        Tcl_SetObjResult(interp, rv);        GMP_RATS_mpq_clear(&arg2);
3628          GMP_RATS_mpq_clear(&result);
3629        //Free up all dynamic memory.  
3630        TclpFree(string_result);        //Return
3631        GMP_RATS_mpq_clear(&arg1);        return(TCL_OK);
3632        GMP_RATS_mpq_clear(&arg2);        }
3633        GMP_RATS_mpq_clear(&result);     }
3634    
3635        //Return  
3636        return(TCL_OK);  //This is the search data table of possible subcommands
3637        }  //for the "arbint" extension.  These must be kept
3638     }  //in alphabetical order, because a binary search is done
3639    //on this table in order to find an entry.  If this table
3640    //falls out of alphabetical order, the binary search may
3641  //08/16/01: Visual inspection OK.    //fail when in fact the entry exists.
3642  static  //
3643  int ARBLENINTS_rncmp_handler(ClientData dummy,  //In a lot of cases below, this table is set up to accept
3644                               Tcl_Interp *interp,  //short forms.  This is purely undocumented, and I won't put
3645                               int objc,  //it in any documentation.  In a lot of cases, these table
3646                               Tcl_Obj *objv[])  //entries cover common mistakes where people forget the "int".
3647     {  //
3648     Tcl_Obj *rv;  static struct EXTNINIT_subextn_bsearch_record_struct
3649       ARBLENINTS_subextn_tbl[] =
3650     //We must have exactly two additional arguments        {
3651     //to this function, which are the rational numbers           { "brap",             ARBLENINTS_cfbrapab_handler      },
3652     //to compare.           { "cfbrapab",         ARBLENINTS_cfbrapab_handler      },
3653     if (objc != 4)           { "cfratnum",         ARBLENINTS_cfratnum_handler      },
3654        {           { "cmp",              ARBLENINTS_intcmp_handler        },
3655        Tcl_WrongNumArgs(interp,           { "commanate",        ARBLENINTS_commanate_handler     },
3656                         2,           { "compare",          ARBLENINTS_intcmp_handler        },
3657                         objv,           { "const",            ARBLENINTS_const_handler         },
3658                         "srn srn");           { "decommanate",      ARBLENINTS_decommanate_handler   },
3659        return(TCL_ERROR);           { "div",              ARBLENINTS_intdiv_handler        },
3660        }           { "divide",           ARBLENINTS_intdiv_handler        },
3661     else           { "exp",              ARBLENINTS_intexp_handler        },
3662        {           { "fac",              ARBLENINTS_intfac_handler        },
3663        char *input_arg;           { "factorial",        ARBLENINTS_intfac_handler        },
3664        int failure, compare_result;           { "gcd",              ARBLENINTS_intgcd_handler        },
3665        GMP_RATS_mpq_struct arg1, arg2;           { "intadd",           ARBLENINTS_intadd_handler        },
3666             { "intcmp",           ARBLENINTS_intcmp_handler        },
3667        //Allocate space for the rational numbers.           { "intdiv",           ARBLENINTS_intdiv_handler        },
3668        GMP_RATS_mpq_init(&arg1);           { "intexp",           ARBLENINTS_intexp_handler        },
3669        GMP_RATS_mpq_init(&arg2);           { "intfac",           ARBLENINTS_intfac_handler        },
3670             { "intgcd",           ARBLENINTS_intgcd_handler        },
3671        //Grab a pointer to the string representation of           { "intlcm",           ARBLENINTS_intlcm_handler        },
3672        //the first input argument.  The storage does not belong to us.           { "intmod",           ARBLENINTS_intmod_handler        },
3673        input_arg = Tcl_GetString(objv[2]);           { "intmul",           ARBLENINTS_intmul_handler        },
3674        assert(input_arg != NULL);           { "intsub",           ARBLENINTS_intsub_handler        },
3675             { "iseflag",          ARBLENINTS_iseflag_handler       },
3676        //Try to parse our first input string as a rational number.           { "lcm",              ARBLENINTS_intlcm_handler        },
3677        //If we are not successful in this, must abort.           { "mod",              ARBLENINTS_intmod_handler        },
3678        GMP_RATS_mpq_set_all_format_rat_num(input_arg,           { "mul",              ARBLENINTS_intmul_handler        },
3679                                            &failure,           { "multiply",         ARBLENINTS_intmul_handler        },
3680                                            &arg1);           { "rnadd",            ARBLENINTS_rnadd_handler         },
3681             { "rncmp",            ARBLENINTS_rncmp_handler         },
3682        if (failure)           { "rndiv",            ARBLENINTS_rndiv_handler         },
3683           {           { "rnmul",            ARBLENINTS_rnmul_handler         },
3684           rv = Tcl_NewStringObj("arbint rncmp: \"", -1);           { "rnred",            ARBLENINTS_rnred_handler         },
3685           Tcl_AppendToObj(rv, input_arg, -1);           { "rnsub",            ARBLENINTS_rnsub_handler         },
3686             { "times",            ARBLENINTS_intmul_handler        },
3687           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);        };
3688           Tcl_SetObjResult(interp, rv);  
3689    
3690           GMP_RATS_mpq_clear(&arg1);  //Procedure called when the "arbint" command is encountered in a Tcl script.
3691           GMP_RATS_mpq_clear(&arg2);  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this
3692    //from memory an intuition as far as how to set return results and so forth.
3693           return(TCL_ERROR);  int ARBLENINTS_arbint_extn_command(ClientData dummy,
3694           }                                     Tcl_Interp *interp,
3695                                       int objc,
3696        //Grab a pointer to the string representation of                                     Tcl_Obj *objv[])
3697        //the second input argument.  The storage does not belong to us.     {
3698        input_arg = Tcl_GetString(objv[3]);     char *subcommand;
3699        assert(input_arg != NULL);        //Pointer to subcommand string.
3700       int tbl_entry;
3701        //Try to parse our second input string as a rational number.        //Index into the subcommand lookup table, or -1
3702        //If we are not successful in this, must abort.        //if no match.
3703        GMP_RATS_mpq_set_all_format_rat_num(input_arg,     Tcl_Obj *rv;
3704                                            &failure,        //The return result (a string) if there is an error.
3705                                            &arg2);        //In the normal execution case, one of the functions
3706          //above supplies the return object.
3707        if (failure)    
3708           {     if (objc < 2)
3709           rv = Tcl_NewStringObj("arbint rncmp: \"", -1);        {
3710           Tcl_AppendToObj(rv, input_arg, -1);        //It isn't possible to have an object count of less than
3711          //2, because you must have at least the command name
3712           Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);        //plus a subcommand.  The best way to handle this is
3713           Tcl_SetObjResult(interp, rv);        //to indicate wrong number of arguments.
3714          Tcl_WrongNumArgs(interp,
3715           GMP_RATS_mpq_clear(&arg1);                         1,
3716           GMP_RATS_mpq_clear(&arg2);                         objv,
3717                           "option ?args?");
3718           return(TCL_ERROR);        return(TCL_ERROR);
3719           }        }
3720       else
3721        //Perform the actual comparison of the rational numbers.  All        {
3722        //error cases are covered.  If either of the inputs has a        //A potentially appropriate number of arguments has been
3723        //denominator of zero, this will propagate to the result.        //specified.  Try to look up the subcommand.
3724        compare_result = GMP_RATS_mpq_cmp(&arg1, &arg2, &failure);  
3725          subcommand = Tcl_GetString(objv[1]);
3726        //If the failure flag was thrown, we have to throw an error.           //Grab the string representation of the subcommand.
3727        //The reason is that if we can't successfully compare the two           //This is constant, belongs to Tcl, and cannot be
3728        //rational numbers, then we have to kill the script--logical           //modified.
3729        //correctness is not possible.  
3730        if (failure)        tbl_entry = EXTNINIT_subextension_bsearch(
3731           {                       ARBLENINTS_subextn_tbl,
3732           rv = Tcl_NewStringObj("arbint rncmp: can't compare supplied rational numbers.", -1);                       sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]),
3733                         subcommand);
3734           Tcl_SetObjResult(interp, rv);        assert(tbl_entry < (int)(sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0])));
3735    
3736           GMP_RATS_mpq_clear(&arg1);        //If the integer returned is zero or positive, should
3737           GMP_RATS_mpq_clear(&arg2);        //run the subfunction.  If negative, this is an error and
3738          //should generate meaningful message.  A meaningful message
3739           return(TCL_ERROR);        //would definitely consist of all valid subcommands.
3740           }        if (tbl_entry < 0)
3741             {
3742        //Convert the comparison result to a string.           //This is an error path.
3743        if (compare_result < 0)           rv = Tcl_NewStringObj("arbint: bad option \"", -1);
3744           rv = Tcl_NewStringObj("-1", -1);           subcommand = Tcl_GetString(objv[1]);
3745        else if (compare_result == 0)           Tcl_AppendToObj(rv, subcommand, -1);
3746           rv = Tcl_NewStringObj("0", -1);           Tcl_AppendToObj(rv, "\": valid options are ", -1);
3747        else  
3748           rv = Tcl_NewStringObj("1", -1);           for (tbl_entry=0;
3749                  tbl_entry < sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]);
3750        //Assign the result to be the return value.                tbl_entry++)
3751        Tcl_SetObjResult(interp, rv);              {
3752                if ((sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]) != 1)
3753        //Free up all dynamic memory.                  && (tbl_entry == sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]) - 1))
3754        GMP_RATS_mpq_clear(&arg1);              Tcl_AppendToObj(rv, "and ", -1);
3755        GMP_RATS_mpq_clear(&arg2);              Tcl_AppendToObj(rv, ARBLENINTS_subextn_tbl[tbl_entry].name, -1);
3756                if (tbl_entry == sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]) - 1)
3757        //Return                 Tcl_AppendToObj(rv, ".", -1);
3758        return(TCL_OK);              else
3759        }                 Tcl_AppendToObj(rv, ", ", -1);
3760     }              }
3761    
3762             //Now, set the return value to be the object with our
3763  //08/09/01:  Visual inspection OK.           //meaningful string message.
3764  static           Tcl_SetObjResult(interp, rv);
3765  int ARBLENINTS_rndiv_handler(ClientData dummy,  
3766                               Tcl_Interp *interp,           return(TCL_ERROR);
3767                               int objc,           }
3768                               Tcl_Obj *objv[])        else
3769     {           {
3770     Tcl_Obj *rv;           //Call the function pointer.  Called function will
3771             //set the string return value.
3772     //We must have exactly two additional arguments           return((*ARBLENINTS_subextn_tbl[tbl_entry].fptr)
3773     //to this function, which are the rational numbers                  (dummy, interp, objc, objv));
3774     //to divide.           }
3775     if (objc != 4)        }
3776        {     }
3777        Tcl_WrongNumArgs(interp,  
3778                         2,  
3779                         objv,  //Performs initial registration to the hash table.
3780                         "srn srn");  //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this
3781        return(TCL_ERROR);  //from memory an intuition as far as how to set return results and so forth.
3782        }  void ARBLENINTS_arbint_extn_init(Tcl_Interp *interp)
3783     else     {
3784        {     //Register a command named "crc32".
3785        char *input_arg;     Tcl_CreateObjCommand(interp,
3786        int failure;                          "arbint",
3787        char *string_result;                          (Tcl_ObjCmdProc *)ARBLENINTS_arbint_extn_command,
3788        GMP_RATS_mpq_struct arg1, arg2, result;                          NULL,
3789                            NULL);
3790        //Allocate space for the rational numbers.     }
3791        GMP_RATS_mpq_init(&arg1);  
3792        GMP_RATS_mpq_init(&arg2);  
3793        GMP_RATS_mpq_init(&result);  
3794    //Returns version control string for file.
3795        //Grab a pointer to the string representation of  //
3796        //the first input argument.  The storage does not belong to us.  const char *ARBLENINTS_cvcinfo(void)
3797        input_arg = Tcl_GetString(objv[2]);  {  
3798        assert(input_arg != NULL);      return ("$Header$");
3799    }
3800        //Try to parse our first input string as a rational number.  
3801        //If we are not successful in this, must abort.  
3802        GMP_RATS_mpq_set_all_format_rat_num(input_arg,  //Returns version control string for associated .H file.
3803                                            &failure,  //
3804                                            &arg1);  const char *ARBLENINTS_hvcinfo(void)
3805    {  
3806        if (failure)      return (ARBLENINTS_H_VERSION);
3807           {  }
3808           rv = Tcl_NewStringObj("arbint rndiv: \"", -1);  
3809           Tcl_AppendToObj(rv, input_arg, -1);  //End of arblenints.c.
   
          Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);  
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_ERROR);  
          }  
   
       //Grab a pointer to the string representation of  
       //the second input argument.  The storage does not belong to us.  
       input_arg = Tcl_GetString(objv[3]);  
       assert(input_arg != NULL);  
   
       //Try to parse our second input string as a rational number.  
       //If we are not successful in this, must abort.  
       GMP_RATS_mpq_set_all_format_rat_num(input_arg,  
                                           &failure,  
                                           &arg2);  
   
       if (failure)  
          {  
          rv = Tcl_NewStringObj("arbint rndiv: \"", -1);  
          Tcl_AppendToObj(rv, input_arg, -1);  
   
          Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);  
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_ERROR);  
          }  
   
       //Perform the actual division of the rational numbers.  All  
       //error cases are covered.  If either of the inputs has a  
       //denominator of zero, this will propagate to the result.  
       GMP_RATS_mpq_div(&result, &arg1, &arg2);  
   
       //If the result has been NAN'd, return the string "NAN".  
       if (GMP_RATS_mpq_is_nan(&result))  
          {  
          rv = Tcl_NewStringObj("NAN", -1);  
   
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_OK);  
          }  
   
       //Allocate space for the string result which we'll form for  
       //both numerator and denominator.  We need the maximum, because we'll only  
       //do one number at a time.  
       string_result = TclpAlloc(sizeof(char)  
                                 *  
                                 INTFUNC_max  
                                    (  
                                    GMP_INTS_mpz_size_in_base_10(&(result.num)),  
                                    GMP_INTS_mpz_size_in_base_10(&(result.den))  
                                    )  
                                 );  
       assert(string_result != NULL);  
   
       //Convert the numerator to a string and set that to be the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(result.num));  
       rv = Tcl_NewStringObj(string_result, -1);  
   
       //Append the separating slash.  
       Tcl_AppendToObj(rv, "/", -1);  
   
       //Convert the denominator to a string and append that to the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(result.den));  
       Tcl_AppendToObj(rv, string_result, -1);  
   
       //Assign the result to be the return value.  
       Tcl_SetObjResult(interp, rv);  
   
       //Free up all dynamic memory.  
       TclpFree(string_result);  
       GMP_RATS_mpq_clear(&arg1);  
       GMP_RATS_mpq_clear(&arg2);  
       GMP_RATS_mpq_clear(&result);  
   
       //Return  
       return(TCL_OK);  
       }  
    }  
   
   
 //08/09/01:  Visual inspection OK.  
 static  
 int ARBLENINTS_rnmul_handler(ClientData dummy,  
                              Tcl_Interp *interp,  
                              int objc,  
                              Tcl_Obj *objv[])  
    {  
    Tcl_Obj *rv;  
   
    //We must have exactly two additional arguments  
    //to this function, which are the rational numbers  
    //to add.  
    if (objc != 4)  
       {  
       Tcl_WrongNumArgs(interp,  
                        2,  
                        objv,  
                        "srn srn");  
       return(TCL_ERROR);  
       }  
    else  
       {  
       char *input_arg;  
       int failure;  
       char *string_result;  
       GMP_RATS_mpq_struct arg1, arg2, result;  
   
       //Allocate space for the rational numbers.  
       GMP_RATS_mpq_init(&arg1);  
       GMP_RATS_mpq_init(&arg2);  
       GMP_RATS_mpq_init(&result);  
   
       //Grab a pointer to the string representation of  
       //the first input argument.  The storage does not belong to us.  
       input_arg = Tcl_GetString(objv[2]);  
       assert(input_arg != NULL);  
   
       //Try to parse our first input string as a rational number.  
       //If we are not successful in this, must abort.  
       GMP_RATS_mpq_set_all_format_rat_num(input_arg,  
                                           &failure,  
                                           &arg1);  
   
       if (failure)  
          {  
          rv = Tcl_NewStringObj("arbint rnmul: \"", -1);  
          Tcl_AppendToObj(rv, input_arg, -1);  
   
          Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);  
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_ERROR);  
          }  
   
       //Grab a pointer to the string representation of  
       //the second input argument.  The storage does not belong to us.  
       input_arg = Tcl_GetString(objv[3]);  
       assert(input_arg != NULL);  
   
       //Try to parse our second input string as a rational number.  
       //If we are not successful in this, must abort.  
       GMP_RATS_mpq_set_all_format_rat_num(input_arg,  
                                           &failure,  
                                           &arg2);  
   
       if (failure)  
          {  
          rv = Tcl_NewStringObj("arbint rnmul: \"", -1);  
          Tcl_AppendToObj(rv, input_arg, -1);  
   
          Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);  
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_ERROR);  
          }  
   
       //Perform the actual multiplication of the rational numbers.  All  
       //error cases are covered.  If either of the inputs has a  
       //denominator of zero, this will propagate to the result.  
       GMP_RATS_mpq_mul(&result, &arg1, &arg2);  
   
       //If the result has been NAN'd, return the string "NAN".  
       if (GMP_RATS_mpq_is_nan(&result))  
          {  
          rv = Tcl_NewStringObj("NAN", -1);  
   
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_OK);  
          }  
   
       //Allocate space for the string result which we'll form for  
       //both numerator and denominator.  We need the maximum, because we'll only  
       //do one number at a time.  
       string_result = TclpAlloc(sizeof(char)  
                                 *  
                                 INTFUNC_max  
                                    (  
                                    GMP_INTS_mpz_size_in_base_10(&(result.num)),  
                                    GMP_INTS_mpz_size_in_base_10(&(result.den))  
                                    )  
                                 );  
       assert(string_result != NULL);  
   
       //Convert the numerator to a string and set that to be the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(result.num));  
       rv = Tcl_NewStringObj(string_result, -1);  
   
       //Append the separating slash.  
       Tcl_AppendToObj(rv, "/", -1);  
   
       //Convert the denominator to a string and append that to the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(result.den));  
       Tcl_AppendToObj(rv, string_result, -1);  
   
       //Assign the result to be the return value.  
       Tcl_SetObjResult(interp, rv);  
   
       //Free up all dynamic memory.  
       TclpFree(string_result);  
       GMP_RATS_mpq_clear(&arg1);  
       GMP_RATS_mpq_clear(&arg2);  
       GMP_RATS_mpq_clear(&result);  
   
       //Return  
       return(TCL_OK);  
       }  
    }  
   
   
 //08/09/01:  Visual inspection OK.  
 static  
 int ARBLENINTS_rnred_handler(ClientData dummy,  
                              Tcl_Interp *interp,  
                              int objc,  
                              Tcl_Obj *objv[])  
    {  
    Tcl_Obj *rv;  
   
    //We must have exactly one additional argument  
    //to this function, which is the rational number  
    //to provide the fully reduced form of.  
    if (objc != 3)  
       {  
       Tcl_WrongNumArgs(interp,  
                        2,  
                        objv,  
                        "srn");  
       return(TCL_ERROR);  
       }  
    else  
       {  
       char *input_arg;  
       int failure;  
       char *string_result;  
       GMP_RATS_mpq_struct rn;  
   
       //We will need a rational number to hold the return value  
       //from the parsing function.  Allocate that now.  
       GMP_RATS_mpq_init(&rn);  
   
       //Grab a pointer to the string representation of  
       //the input argument.  The storage does not belong to us.  
       input_arg = Tcl_GetString(objv[2]);  
       assert(input_arg != NULL);  
   
       //Try to parse our input string as a rational number.  
       //If we are not successful in this, must abort.  
       GMP_RATS_mpq_set_all_format_rat_num(input_arg,  
                                           &failure,  
                                           &rn);  
   
       if (failure)  
          {  
          rv = Tcl_NewStringObj("arbint rnred: \"", -1);  
          Tcl_AppendToObj(rv, input_arg, -1);  
   
          Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);  
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&rn);  
   
          return(TCL_ERROR);  
          }  
   
       //Normalize the rational number.  This takes care of the  
       //sign and also of the coprimality of numerator and  
       //denominator.  
       GMP_RATS_mpq_normalize(&rn);  
   
       //Allocate space for the string result which we'll form for  
       //both numbers.  We need the maximum, because we'll only  
       //do one number at a time.  
       string_result = TclpAlloc(sizeof(char)  
                                 *  
                                 INTFUNC_max  
                                    (  
                                    GMP_INTS_mpz_size_in_base_10(&(rn.num)),  
                                    GMP_INTS_mpz_size_in_base_10(&(rn.den))  
                                    )  
                                 );  
       assert(string_result != NULL);  
   
       //Convert the numerator to a string and set that to be the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(rn.num));  
       rv = Tcl_NewStringObj(string_result, -1);  
   
       //Append the separating slash.  
       Tcl_AppendToObj(rv, "/", -1);  
   
       //Convert the denominator to a string and append that to the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(rn.den));  
       Tcl_AppendToObj(rv, string_result, -1);  
   
       //Assign the result to be the return value.  
       Tcl_SetObjResult(interp, rv);  
   
       //Free up all dynamic memory.  
       TclpFree(string_result);  
       GMP_RATS_mpq_clear(&rn);  
   
       //Return  
       return(TCL_OK);  
       }  
    }  
   
   
 //08/08/01:  Visual inspection OK.  
 static  
 int ARBLENINTS_rnsub_handler(ClientData dummy,  
                              Tcl_Interp *interp,  
                              int objc,  
                              Tcl_Obj *objv[])  
    {  
    Tcl_Obj *rv;  
   
    //We must have exactly two additional arguments  
    //to this function, which are the rational numbers  
    //to subtract.  
    if (objc != 4)  
       {  
       Tcl_WrongNumArgs(interp,  
                        2,  
                        objv,  
                        "srn srn");  
       return(TCL_ERROR);  
       }  
    else  
       {  
       char *input_arg;  
       int failure;  
       char *string_result;  
       GMP_RATS_mpq_struct arg1, arg2, result;  
   
       //Allocate space for the rational numbers.  
       GMP_RATS_mpq_init(&arg1);  
       GMP_RATS_mpq_init(&arg2);  
       GMP_RATS_mpq_init(&result);  
   
       //Grab a pointer to the string representation of  
       //the first input argument.  The storage does not belong to us.  
       input_arg = Tcl_GetString(objv[2]);  
       assert(input_arg != NULL);  
   
       //Try to parse our first input string as a rational number.  
       //If we are not successful in this, must abort.  
       GMP_RATS_mpq_set_all_format_rat_num(input_arg,  
                                           &failure,  
                                           &arg1);  
   
       if (failure)  
          {  
          rv = Tcl_NewStringObj("arbint rnsub: \"", -1);  
          Tcl_AppendToObj(rv, input_arg, -1);  
   
          Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);  
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_ERROR);  
          }  
   
       //Grab a pointer to the string representation of  
       //the second input argument.  The storage does not belong to us.  
       input_arg = Tcl_GetString(objv[3]);  
       assert(input_arg != NULL);  
   
       //Try to parse our second input string as a rational number.  
       //If we are not successful in this, must abort.  
       GMP_RATS_mpq_set_all_format_rat_num(input_arg,  
                                           &failure,  
                                           &arg2);  
   
       if (failure)  
          {  
          rv = Tcl_NewStringObj("arbint rnsub: \"", -1);  
          Tcl_AppendToObj(rv, input_arg, -1);  
   
          Tcl_AppendToObj(rv, "\" is not a recognized rational number.", -1);  
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_ERROR);  
          }  
   
       //Perform the actual subtraction of the rational numbers.  All  
       //error cases are covered.  If either of the inputs has a  
       //denominator of zero, this will propagate to the result.  
       GMP_RATS_mpq_sub(&result, &arg1, &arg2);  
   
       //If the result has been NAN'd, return the string "NAN".  
       if (GMP_RATS_mpq_is_nan(&result))  
          {  
          rv = Tcl_NewStringObj("NAN", -1);  
   
          Tcl_SetObjResult(interp, rv);  
   
          GMP_RATS_mpq_clear(&arg1);  
          GMP_RATS_mpq_clear(&arg2);  
          GMP_RATS_mpq_clear(&result);  
   
          return(TCL_OK);  
          }  
   
       //Allocate space for the string result which we'll form for  
       //both numerator and denominator.  We need the maximum, because we'll only  
       //do one number at a time.  
       string_result = TclpAlloc(sizeof(char)  
                                 *  
                                 INTFUNC_max  
                                    (  
                                    GMP_INTS_mpz_size_in_base_10(&(result.num)),  
                                    GMP_INTS_mpz_size_in_base_10(&(result.den))  
                                    )  
                                 );  
       assert(string_result != NULL);  
   
       //Convert the numerator to a string and set that to be the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(result.num));  
       rv = Tcl_NewStringObj(string_result, -1);  
   
       //Append the separating slash.  
       Tcl_AppendToObj(rv, "/", -1);  
   
       //Convert the denominator to a string and append that to the  
       //return value.  
       GMP_INTS_mpz_to_string(string_result, &(result.den));  
       Tcl_AppendToObj(rv, string_result, -1);  
   
       //Assign the result to be the return value.  
       Tcl_SetObjResult(interp, rv);  
   
       //Free up all dynamic memory.  
       TclpFree(string_result);  
       GMP_RATS_mpq_clear(&arg1);  
       GMP_RATS_mpq_clear(&arg2);  
       GMP_RATS_mpq_clear(&result);  
   
       //Return  
       return(TCL_OK);  
       }  
    }  
   
   
 //This is the search data table of possible subcommands  
 //for the "arbint" extension.  These must be kept  
 //in alphabetical order, because a binary search is done  
 //on this table in order to find an entry.  If this table  
 //falls out of alphabetical order, the binary search may  
 //fail when in fact the entry exists.  
 //  
 //In a lot of cases below, this table is set up to accept  
 //short forms.  This is purely undocumented, and I won't put  
 //it in any documentation.  In a lot of cases, these table  
 //entries cover common mistakes where people forget the "int".  
 //  
 static struct EXTNINIT_subextn_bsearch_record_struct  
    ARBLENINTS_subextn_tbl[] =  
       {  
          { "brap",             ARBLENINTS_cfbrapab_handler      },  
          { "cfbrapab",         ARBLENINTS_cfbrapab_handler      },  
          { "cfratnum",         ARBLENINTS_cfratnum_handler      },  
          { "cmp",              ARBLENINTS_intcmp_handler        },  
          { "commanate",        ARBLENINTS_commanate_handler     },  
          { "compare",          ARBLENINTS_intcmp_handler        },  
          { "const",            ARBLENINTS_const_handler         },  
          { "decommanate",      ARBLENINTS_decommanate_handler   },  
          { "div",              ARBLENINTS_intdiv_handler        },  
          { "divide",           ARBLENINTS_intdiv_handler        },  
          { "exp",              ARBLENINTS_intexp_handler        },  
          { "fac",              ARBLENINTS_intfac_handler        },  
          { "factorial",        ARBLENINTS_intfac_handler        },  
          { "gcd",              ARBLENINTS_intgcd_handler        },  
          { "intadd",           ARBLENINTS_intadd_handler        },  
          { "intcmp",           ARBLENINTS_intcmp_handler        },  
          { "intdiv",           ARBLENINTS_intdiv_handler        },  
          { "intexp",           ARBLENINTS_intexp_handler        },  
          { "intfac",           ARBLENINTS_intfac_handler        },  
          { "intgcd",           ARBLENINTS_intgcd_handler        },  
          { "intlcm",           ARBLENINTS_intlcm_handler        },  
          { "intmod",           ARBLENINTS_intmod_handler        },  
          { "intmul",           ARBLENINTS_intmul_handler        },  
          { "intsub",           ARBLENINTS_intsub_handler        },  
          { "iseflag",          ARBLENINTS_iseflag_handler       },  
          { "lcm",              ARBLENINTS_intlcm_handler        },  
          { "mod",              ARBLENINTS_intmod_handler        },  
          { "mul",              ARBLENINTS_intmul_handler        },  
          { "multiply",         ARBLENINTS_intmul_handler        },  
          { "rnadd",            ARBLENINTS_rnadd_handler         },  
          { "rncmp",            ARBLENINTS_rncmp_handler         },  
          { "rndiv",            ARBLENINTS_rndiv_handler         },  
          { "rnmul",            ARBLENINTS_rnmul_handler         },  
          { "rnred",            ARBLENINTS_rnred_handler         },  
          { "rnsub",            ARBLENINTS_rnsub_handler         },  
          { "times",            ARBLENINTS_intmul_handler        },  
       };  
   
   
 //Procedure called when the "arbint" command is encountered in a Tcl script.  
 //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this  
 //from memory an intuition as far as how to set return results and so forth.  
 int ARBLENINTS_arbint_extn_command(ClientData dummy,  
                                    Tcl_Interp *interp,  
                                    int objc,  
                                    Tcl_Obj *objv[])  
    {  
    char *subcommand;  
       //Pointer to subcommand string.  
    int tbl_entry;  
       //Index into the subcommand lookup table, or -1  
       //if no match.  
    Tcl_Obj *rv;  
       //The return result (a string) if there is an error.  
       //In the normal execution case, one of the functions  
       //above supplies the return object.  
     
    if (objc < 2)  
       {  
       //It isn't possible to have an object count of less than  
       //2, because you must have at least the command name  
       //plus a subcommand.  The best way to handle this is  
       //to indicate wrong number of arguments.  
       Tcl_WrongNumArgs(interp,  
                        1,  
                        objv,  
                        "option ?args?");  
       return(TCL_ERROR);  
       }  
    else  
       {  
       //A potentially appropriate number of arguments has been  
       //specified.  Try to look up the subcommand.  
   
       subcommand = Tcl_GetString(objv[1]);  
          //Grab the string representation of the subcommand.  
          //This is constant, belongs to Tcl, and cannot be  
          //modified.  
   
       tbl_entry = EXTNINIT_subextension_bsearch(  
                      ARBLENINTS_subextn_tbl,  
                      sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]),  
                      subcommand);  
       assert(tbl_entry < (int)(sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0])));  
   
       //If the integer returned is zero or positive, should  
       //run the subfunction.  If negative, this is an error and  
       //should generate meaningful message.  A meaningful message  
       //would definitely consist of all valid subcommands.  
       if (tbl_entry < 0)  
          {  
          //This is an error path.  
          rv = Tcl_NewStringObj("arbint: bad option \"", -1);  
          subcommand = Tcl_GetString(objv[1]);  
          Tcl_AppendToObj(rv, subcommand, -1);  
          Tcl_AppendToObj(rv, "\": valid options are ", -1);  
   
          for (tbl_entry=0;  
               tbl_entry < sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]);  
               tbl_entry++)  
             {  
             if ((sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]) != 1)  
                 && (tbl_entry == sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]) - 1))  
             Tcl_AppendToObj(rv, "and ", -1);  
             Tcl_AppendToObj(rv, ARBLENINTS_subextn_tbl[tbl_entry].name, -1);  
             if (tbl_entry == sizeof(ARBLENINTS_subextn_tbl)/sizeof(ARBLENINTS_subextn_tbl[0]) - 1)  
                Tcl_AppendToObj(rv, ".", -1);  
             else  
                Tcl_AppendToObj(rv, ", ", -1);  
             }  
   
          //Now, set the return value to be the object with our  
          //meaningful string message.  
          Tcl_SetObjResult(interp, rv);  
   
          return(TCL_ERROR);  
          }  
       else  
          {  
          //Call the function pointer.  Called function will  
          //set the string return value.  
          return((*ARBLENINTS_subextn_tbl[tbl_entry].fptr)  
                 (dummy, interp, objc, objv));  
          }  
       }  
    }  
   
   
 //Performs initial registration to the hash table.  
 //07/29/01:  Visual inspection OK.  Have not located my Tcl book, am doing this  
 //from memory an intuition as far as how to set return results and so forth.  
 void ARBLENINTS_arbint_extn_init(Tcl_Interp *interp)  
    {  
    //Register a command named "crc32".  
    Tcl_CreateObjCommand(interp,  
                         "arbint",  
                         (Tcl_ObjCmdProc *)ARBLENINTS_arbint_extn_command,  
                         NULL,  
                         NULL);  
    }  
   
   
   
 //Returns version control string for file.  
 //  
 const char *ARBLENINTS_cvcinfo(void)  
 {    
     return ("$Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tclxtens/arblenints.c,v 1.12 2001/08/18 09:47:00 dtashley Exp $");  
 }  
   
   
 //Returns version control string for associated .H file.  
 //  
 const char *ARBLENINTS_hvcinfo(void)  
 {    
     return (ARBLENINTS_H_VERSION);  
 }  
   
   
 //$Log: arblenints.c,v $  
 //Revision 1.12  2001/08/18 09:47:00  dtashley  
 //Preparing for test for release of v1.05.  
 //  
 //Revision 1.11  2001/08/16 19:49:40  dtashley  
 //Beginning to prepare for v1.05 release.  
 //  
 //Revision 1.10  2001/08/16 12:20:09  dtashley  
 //Version number changes.  
 //  
 //Revision 1.9  2001/08/12 10:20:58  dtashley  
 //Safety check-in.  Substantial progress.  
 //  
 //Revision 1.8  2001/08/10 00:53:59  dtashley  
 //Completion of basic rational number arithmetic utilities and extensions.  
 //  
 //Revision 1.7  2001/08/08 02:16:51  dtashley  
 //Completion of RNRED utility and ARBINT RNRED Tcl extension.  
 //  
 //Revision 1.6  2001/08/07 10:42:48  dtashley  
 //Completion of CFRATNUM extensions and DOS command-line utility.  
 //  
 //Revision 1.5  2001/08/01 03:35:29  dtashley  
 //Finished most primitive integer operations, both as Tcl extensions and  
 //as DOS command-line utilities, such as addition, subtraction,  
 //multiplication, division, and modulo.  
 //  
 //Revision 1.4  2001/07/30 02:51:18  dtashley  
 //INTGCD extension and command-line utility finished up.  
 //  
 //Revision 1.3  2001/07/29 07:17:04  dtashley  
 //Completion of ARBINT INTFAC extension.  
 //  
 //Revision 1.2  2001/07/28 06:03:57  dtashley  
 //Safety check-in.  Substantial edits.  
 //  
 //Revision 1.1  2001/07/27 07:00:56  dtashley  
 //Initial check-in.  
 //  
 //End of ARBLENINTS.C  

Legend:
Removed from v.25  
changed lines
  Added in v.220

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25