Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial import

not everything running yet :-)
  • Loading branch information...
commit 0b8b2719f41a2ac6fc14d6d6c0f4685799558b9c 0 parents
@poelzi authored
Showing with 8,771 additions and 0 deletions.
  1. +2 −0  .gitignore
  2. +1 −0  AUTHORS
  3. +50 −0 CMakeLists.txt
  4. +674 −0 COPYING
  5. +32 −0 README
  6. +3 −0  TODO
  7. +82 −0 rules/test.lua
  8. +3 −0  src/CMakeLists.txt
  9. +3 −0  src/bc/CMakeLists.txt
  10. +28 −0 src/bc/README
  11. +23 −0 src/bc/config.h
  12. +320 −0 src/bc/lbc.c
  13. +5 −0 src/bc/lbc.h
  14. +1,576 −0 src/bc/number.c
  15. +153 −0 src/bc/number.h
  16. +23 −0 src/core.lua
  17. +525 −0 src/lua_binding.c
  18. +4 −0 src/proc/CMakeLists.txt
  19. +49 −0 src/proc/alloc.c
  20. +14 −0 src/proc/alloc.h
  21. +329 −0 src/proc/devname.c
  22. +17 −0 src/proc/devname.h
  23. +216 −0 src/proc/escape.c
  24. +22 −0 src/proc/escape.h
  25. +631 −0 src/proc/ksym.c
  26. +112 −0 src/proc/procps.h
  27. +77 −0 src/proc/pwcache.c
  28. +17 −0 src/proc/pwcache.h
  29. +1,128 −0 src/proc/readproc.c
  30. +268 −0 src/proc/readproc.h
  31. +240 −0 src/proc/sig.c
  32. +30 −0 src/proc/sig.h
  33. +337 −0 src/proc/slab.c
  34. +39 −0 src/proc/slab.h
  35. +171 −0 src/proc/smaps.c
  36. +945 −0 src/proc/sysinfo.c
  37. +135 −0 src/proc/sysinfo.h
  38. +58 −0 src/proc/version.c
  39. +32 −0 src/proc/version.h
  40. +16 −0 src/proc/wchan.h
  41. +87 −0 src/proc/whattime.c
  42. +13 −0 src/proc/whattime.h
  43. +65 −0 src/ulatency.h
  44. +216 −0 src/ulatencyd.c
2  .gitignore
@@ -0,0 +1,2 @@
+*.[oa]
+*.*~
1  AUTHORS
@@ -0,0 +1 @@
+Daniel Poelzleithner <git@poelzi.org>
50 CMakeLists.txt
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 2.8)
+project(ulatency)
+
+INCLUDE(FindPkgConfig)
+
+pkg_check_modules(LIBCGROUP libcgroup REQUIRED)
+
+pkg_check_modules(GLIB2 glib-2.0 REQUIRED)
+
+pkg_check_modules(DBUS dbus-glib-1 REQUIRED)
+
+
+# FIXME: libproc should export more symbols
+# find libproc
+#FIND_PATH(LIBPROC_INCLUDE_DIR readproc.h /usr/include/proc /usr/local/include/proc)
+
+#FIND_LIBRARY(LIBPROC_LIBRARY NAMES proc PATH /usr/lib /usr/local/lib)
+
+#IF (LIBPROC_INCLUDE_DIR AND LIBPROC_LIBRARY)
+# SET(LIBPROC_FOUND TRUE)
+#ENDIF (LIBPROC_INCLUDE_DIR AND LIBPROC_LIBRARY)
+
+
+#IF (NOT LIBPROC_FOUND)
+# MESSAGE(FATAL_ERROR "Could not find libproc")
+#ENDIF (NOT LIBPROC_FOUND)
+
+# use own libproc copy
+
+set(LIBPROC_INCLUDE_DIRS src)
+#set(LIBPROC_LIBRARY src/proc/libproc.a)
+
+
+
+#find_package(lua51)
+INCLUDE(FindLua51)
+
+IF(NOT LUA51_FOUND)
+ message(FATAL_ERROR "lua 5.1 not found")
+ENDIF(NOT LUA51_FOUND)
+
+include_directories (${LUA_INCLUDE_DIR} ${LIBCGROUP_INCLUDE_DIRS} ${LIBPROC_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS})
+
+
+
+
+set(CMAKE_CXX_FLAGS "-g -Wall")
+add_subdirectory(src/bc)
+add_subdirectory(src/proc)
+add_subdirectory(src)
674 COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
32 README
@@ -0,0 +1,32 @@
+WARNING: this program is under development and not working yet
+
+== What is ulatency ==
+
+Ulatency is a daemon that controls how the Linux kernel will spend it's
+resources on the running processes. It uses dynamic cgroups to give the kernel
+hints and limitations on processes.
+
+== What tries it to fix ==
+
+The Linux scheduler does a pretty good job to give the available resources to
+all processes, but this may not be the best user experience in the desktop case.
+ulatencyd monitors the system and categorizes the running processes into cgroups.
+Processes that run wild to slow down the system by causing massive swaping will
+be isolated.
+
+== Architecture ==
+
+The core of the daemon is written in c, embedding a lua interpreter.
+Most of the rules are written in lua scripts, as heuristics for system behavior
+can best be written in a script language.
+The daemon exports system informations into lua script.
+
+There are two ways implementing a heuristic behavior:
+- using a timeout callback
+- using a filter class
+
+The timeout callback is called until it returns True
+The filter class is the preferred way. The filter gets executed on processes and
+can categorize the process. Depending on the return value of the call, the filter
+gets called on the next iteration of over all processes, not again on the specific
+process or on the iteration after a timeout value.
3  TODO
@@ -0,0 +1,3 @@
+TODO:
+
+- having a copy of libproc is very ugly, but currently it does not export enough symbols
82 rules/test.lua
@@ -0,0 +1,82 @@
+ul = ulatency
+
+print ("test run")
+
+print (ulatency)
+print (ulatency.version)
+
+ld1,ld5,ld15 = ulatency.get_load()
+print (ld1, ld5, ld15)
+
+function print_table(tab)
+ for k, v in pairs(tab) do
+ print(k, v)
+ end
+end
+
+
+ld1,ld5,ld15 = ulatency.get_load()
+print (ld1, ld5, ld15)
+
+print_table(ulatency.get_meminfo())
+
+print_table(ulatency.get_vminfo())
+
+print(ulatency.get_pid_digits())
+print(ulatency.hertz)
+print(ulatency.smp_num_cpus)
+
+
+proc = ul.get_pid(1)
+
+function pr(str)
+ print("proc", str, proc[str])
+end
+
+print(proc)
+pr('tid')
+pr('ppid')
+pr('state')
+pr('utime')
+pr('stime')
+pr('cutime')
+pr('cstime')
+pr('start_time')
+
+pr('signal')
+
+pr('blocked')
+pr('sigignore')
+pr('sigcatch')
+pr('_sigpnd')
+
+pr('cgroup_name')
+pr('cmdline')
+pr('environ')
+
+print_table(ul.list_pids())
+--
+-- test_filter = {
+-- process_re = "firefox.*"
+-- }
+--
+-- fuction test_filter:check(process) {
+-- print("check"..tostring(process)
+-- }
+--
+-- ulatency.register_filter(test_filter)
+
+si_run = 0
+function someinterval(data)
+ print("interval", data, si_run)
+ if si_run == 1 then
+ ul.quit_daemon()
+ return false
+ end
+ si_run = si_run + 1
+ return true
+end
+
+ulatency.add_timeout(someinterval, 1000)
+
+--ulatency.quit_daemon()
3  src/CMakeLists.txt
@@ -0,0 +1,3 @@
+
+add_executable(ulatencyd ulatencyd.c lua_binding.c)
+target_link_libraries (ulatencyd proc lbc ${LUA_LIBRARIES} ${LIBCGROUP_LIBRARIES} ${GLIB2_LIBRARIES})
3  src/bc/CMakeLists.txt
@@ -0,0 +1,3 @@
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+add_library(lbc STATIC
+ number.c lbc.c)
28 src/bc/README
@@ -0,0 +1,28 @@
+This is a big-number library for Lua 5.1. It is based on the arbitrary
+precision library number.c written by Philip A. Nelson for GNU bc-1.06:
+ http://www.gnu.org/software/bc/
+
+To try the library, just edit Makefile to reflect your installation of Lua and
+then run make. This will build the library and run a simple test. For detailed
+installation instructions, see
+ http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/install.html
+
+There is no manual but the library is simple and intuitive; see the summary
+below. Read also test.lua, which shows the library in action.
+
+This code is hereby placed in the public domain, except number.c and number.h,
+which are subject to GPL.
+
+Please send comments, suggestions, and bug reports to lhf@tecgraf.puc-rio.br .
+
+-------------------------------------------------------------------------------
+
+bc library:
+ __add(x,y) __pow(x,y) digits([n]) mul(x,y) sub(x,y)
+ __div(x,y) __sub(x,y) div(x,y) neg(x) tonumber(x)
+ __eq(x,y) __tostring(x) divmod(x,y) number(x) tostring(x)
+ __lt(x,y) __unm(x) isneg(x) pow(x,y) trunc(x,[n])
+ __mod(x,y) add(x,y) iszero(x) powmod(x,y,m) version
+ __mul(x,y) compare(x,y) mod(x,y) sqrt(x)
+
+-------------------------------------------------------------------------------
23 src/bc/config.h
@@ -0,0 +1,23 @@
+/*
+* config.h
+* number.c from GNU bc-1.06 exports some symbols without the bc_ prefix.
+* This header file fixes this without touching either number.c or number.h
+* (luckily, number.c already wants to include a config.h).
+* Clients of number.c should include config.h before number.h.
+*/
+
+#include <string.h>
+#include <limits.h>
+#define NDEBUG
+
+#define _zero_ bc_zero
+#define _one_ bc_one
+#define _two_ bc_two
+#define num2str bc_num2str
+#define mul_base_digits bc_mul_base_digits
+
+#define bc_rt_warn bc_error
+#define bc_rt_error bc_error
+#define bc_out_of_memory() bc_error(NULL)
+
+void bc_error(const char *mesg);
320 src/bc/lbc.c
@@ -0,0 +1,320 @@
+/*
+* lbc.c
+* big-number library for Lua 5.1 based on GNU bc-1.06 core library
+* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
+* 04 Apr 2010 22:40:22
+* This code is hereby placed in the public domain.
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "number.h"
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#define lua_boxpointer(L,u) \
+ (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
+
+#define MYNAME "bc"
+#define MYVERSION MYNAME " library for " LUA_VERSION " / Apr 2010 / "\
+ "based on GNU bc-1.06"
+#define MYTYPE MYNAME " bignumber"
+
+static int DIGITS=0;
+static lua_State *LL=NULL;
+
+void bc_error(const char *mesg)
+{
+ luaL_error(LL,"(bc) %s",mesg ? mesg : "not enough memory");
+}
+
+void Bnew(lua_State *L, bc_num x)
+{
+ lua_boxpointer(L,x);
+ luaL_getmetatable(L,MYTYPE);
+ lua_setmetatable(L,-2);
+}
+
+bc_num Bget(lua_State *L, int i)
+{
+ LL=L;
+ switch (lua_type(L,i))
+ {
+ case LUA_TNUMBER:
+ case LUA_TSTRING:
+ {
+ bc_num x=NULL;
+ const char *s=lua_tostring(L,i);
+ for (; isspace(*s); s++); /* bc_str2num chokes on spaces */
+ bc_str2num(&x,(char*)s,DIGITS);
+ if (bc_is_zero(x)) /* bc_str2num chokes on sci notation */
+ {
+ char *t=strchr(s,'e');
+ if (t==NULL) t=strchr(s,'E');
+ if (t!=NULL)
+ {
+ bc_num y=NULL,n=NULL;
+ int c=*t; *t=0; /* harmless const violation! */
+ bc_str2num(&x,(char*)s,DIGITS);
+ *t=c;
+ bc_int2num(&y,10);
+ bc_int2num(&n,atoi(t+1));
+ bc_raise(y,n,&y,DIGITS);
+ bc_multiply(x,y,&x,DIGITS);
+ bc_free_num(&y);
+ bc_free_num(&n);
+ }
+ }
+ Bnew(L,x);
+ lua_replace(L,i);
+ return x;
+ }
+ default:
+ return *((void**)luaL_checkudata(L,i,MYTYPE));
+ }
+ return NULL;
+}
+
+static int Bdo1(lua_State *L, void (*f)(bc_num a, bc_num b, bc_num *c, int n))
+{
+ bc_num a=Bget(L,1);
+ bc_num b=Bget(L,2);
+ bc_num c=NULL;
+ f(a,b,&c,DIGITS);
+ Bnew(L,c);
+ return 1;
+}
+
+static int Bdigits(lua_State *L) /** digits([n]) */
+{
+ lua_pushinteger(L,DIGITS);
+ DIGITS=luaL_optint(L,1,DIGITS);
+ return 1;
+}
+
+static int Btostring(lua_State *L) /** tostring(x) */
+{
+ bc_num a=Bget(L,1);
+#if 0
+ if (lua_toboolean(L,2))
+ {
+ lua_pushlstring(L,a->n_value,a->n_len+a->n_scale);
+ lua_pushinteger(L,a->n_len);
+ return 2;
+ }
+ else
+#endif
+ {
+ char *s=bc_num2str(a);
+ lua_pushstring(L,s);
+ free(s);
+ return 1;
+ }
+}
+
+static int Btonumber(lua_State *L) /** tonumber(x) */
+{
+ Btostring(L);
+ lua_pushnumber(L,lua_tonumber(L,-1));
+ return 1;
+}
+
+static int Biszero(lua_State *L) /** iszero(x) */
+{
+ bc_num a=Bget(L,1);
+ lua_pushboolean(L,bc_is_zero(a));
+ return 1;
+}
+
+static int Bisneg(lua_State *L) /** isneg(x) */
+{
+ bc_num a=Bget(L,1);
+ lua_pushboolean(L,bc_is_neg(a));
+ return 1;
+}
+
+static int Bnumber(lua_State *L) /** number(x) */
+{
+ Bget(L,1);
+ lua_settop(L,1);
+ return 1;
+}
+
+static int Bcompare(lua_State *L) /** compare(x,y) */
+{
+ bc_num a=Bget(L,1);
+ bc_num b=Bget(L,2);
+ lua_pushinteger(L,bc_compare(a,b));
+ return 1;
+}
+
+static int Beq(lua_State *L)
+{
+ bc_num a=Bget(L,1);
+ bc_num b=Bget(L,2);
+ lua_pushboolean(L,bc_compare(a,b)==0);
+ return 1;
+}
+
+static int Blt(lua_State *L)
+{
+ bc_num a=Bget(L,1);
+ bc_num b=Bget(L,2);
+ lua_pushboolean(L,bc_compare(a,b)<0);
+ return 1;
+}
+
+static int Badd(lua_State *L) /** add(x,y) */
+{
+ return Bdo1(L,bc_add);
+}
+
+static int Bsub(lua_State *L) /** sub(x,y) */
+{
+ return Bdo1(L,bc_sub);
+}
+
+static int Bmul(lua_State *L) /** mul(x,y) */
+{
+ return Bdo1(L,bc_multiply);
+}
+
+static int Bpow(lua_State *L) /** pow(x,y) */
+{
+ return Bdo1(L,bc_raise);
+}
+
+static int Bdiv(lua_State *L) /** div(x,y) */
+{
+ bc_num a=Bget(L,1);
+ bc_num b=Bget(L,2);
+ bc_num c=NULL;
+ if (bc_divide(a,b,&c,DIGITS)!=0) return 0;
+ Bnew(L,c);
+ return 1;
+}
+
+static int Bmod(lua_State *L) /** mod(x,y) */
+{
+ bc_num a=Bget(L,1);
+ bc_num b=Bget(L,2);
+ bc_num c=NULL;
+ if (bc_modulo(a,b,&c,0)!=0) return 0;
+ Bnew(L,c);
+ return 1;
+}
+
+static int Bdivmod(lua_State *L) /** divmod(x,y) */
+{
+ bc_num a=Bget(L,1);
+ bc_num b=Bget(L,2);
+ bc_num q=NULL;
+ bc_num r=NULL;
+ if (bc_divmod(a,b,&q,&r,0)!=0) return 0;
+ Bnew(L,q);
+ Bnew(L,r);
+ return 2;
+}
+
+static int Bgc(lua_State *L)
+{
+ bc_num x=Bget(L,1);
+ bc_free_num(&x);
+ lua_pushnil(L);
+ lua_setmetatable(L,1);
+ return 0;
+}
+
+static int Bneg(lua_State *L) /** neg(x) */
+{
+ bc_num a=bc_zero;
+ bc_num b=Bget(L,1);
+ bc_num c=NULL;
+ bc_sub(a,b,&c,DIGITS);
+ Bnew(L,c);
+ return 1;
+}
+
+static int Btrunc(lua_State *L) /** trunc(x,[n]) */
+{
+ bc_num a=Bget(L,1);
+ bc_num c=NULL;
+ bc_divide(a,bc_one,&c,luaL_optint(L,2,0));
+ Bnew(L,c);
+ return 1;
+}
+
+static int Bpowmod(lua_State *L) /** powmod(x,y,m) */
+{
+ bc_num a=Bget(L,1);
+ bc_num k=Bget(L,2);
+ bc_num m=Bget(L,3);
+ bc_num c=NULL;
+ if (bc_raisemod(a,k,m,&c,0)!=0) return 0;
+ Bnew(L,c);
+ return 1;
+}
+
+static int Bsqrt(lua_State *L) /** sqrt(x) */
+{
+ bc_num a=Bget(L,1);
+ bc_num b=bc_zero;
+ bc_num c=NULL;
+ bc_add(a,b,&c,DIGITS); /* bc_sqrt works inplace! */
+ if (bc_sqrt(&c,DIGITS)==0) return 0;
+ Bnew(L,c);
+ return 1;
+}
+
+static const luaL_Reg R[] =
+{
+ { "__add", Badd }, /** __add(x,y) */
+ { "__div", Bdiv }, /** __div(x,y) */
+ { "__eq", Beq }, /** __eq(x,y) */
+ { "__gc", Bgc },
+ { "__lt", Blt }, /** __lt(x,y) */
+ { "__mod", Bmod }, /** __mod(x,y) */
+ { "__mul", Bmul }, /** __mul(x,y) */
+ { "__pow", Bpow }, /** __pow(x,y) */
+ { "__sub", Bsub }, /** __sub(x,y) */
+ { "__tostring", Btostring}, /** __tostring(x) */
+ { "__unm", Bneg }, /** __unm(x) */
+ { "add", Badd },
+ { "compare", Bcompare},
+ { "digits", Bdigits },
+ { "div", Bdiv },
+ { "divmod", Bdivmod },
+ { "isneg", Bisneg },
+ { "iszero", Biszero },
+ { "mod", Bmod },
+ { "mul", Bmul },
+ { "neg", Bneg },
+ { "number", Bnumber },
+ { "pow", Bpow },
+ { "powmod", Bpowmod },
+ { "sqrt", Bsqrt },
+ { "sub", Bsub },
+ { "tonumber", Btonumber},
+ { "tostring", Btostring},
+ { "trunc", Btrunc },
+ { NULL, NULL }
+};
+
+LUALIB_API int luaopen_bc(lua_State *L)
+{
+ bc_init_numbers();
+ luaL_newmetatable(L,MYTYPE);
+ lua_setglobal(L,MYNAME);
+ luaL_register(L,MYNAME,R);
+ lua_pushliteral(L,"version"); /** version */
+ lua_pushliteral(L,MYVERSION);
+ lua_settable(L,-3);
+ lua_pushliteral(L,"__index");
+ lua_pushvalue(L,-2);
+ lua_settable(L,-3);
+ return 1;
+}
5 src/bc/lbc.h
@@ -0,0 +1,5 @@
+/* This file was automatically generated. Do not edit! */
+LUALIB_API int luaopen_bc(lua_State *L);
+bc_num Bget(lua_State *L,int i);
+void Bnew(lua_State *L,bc_num x);
+void bc_error(const char *mesg);
1,576 src/bc/number.c
@@ -0,0 +1,1576 @@
+/*
+* this file is originally from GNU bc-1.06. it was trimmed down by lhf to fix
+* a memory leak in bc_raisemod and to remove the free list, as in php bcmath.
+*/
+
+/* number.c: Implements arbitrary precision numbers. */
+/*
+ Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License , or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to:
+
+ The Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330
+ Boston, MA 02111-1307 USA.
+
+
+ You may contact the author by:
+ e-mail: philnelson@acm.org
+ us-mail: Philip A. Nelson
+ Computer Science Department, 9062
+ Western Washington University
+ Bellingham, WA 98226-9062
+
+*************************************************************************/
+
+#include <stdio.h>
+#include <config.h>
+#include <number.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ctype.h>/* Prototypes needed for external utility routines. */
+
+/* Storage used for special numbers. */
+bc_num _zero_;
+bc_num _one_;
+bc_num _two_;
+
+/* new_num allocates a number and sets fields to known values. */
+
+bc_num
+bc_new_num (length, scale)
+ int length, scale;
+{
+ bc_num temp;
+
+ temp = (bc_num) malloc (sizeof(bc_struct));
+ if (temp == NULL) bc_out_of_memory ();
+ temp->n_sign = PLUS;
+ temp->n_len = length;
+ temp->n_scale = scale;
+ temp->n_refs = 1;
+ temp->n_ptr = (char *) malloc (length+scale);
+ if (temp->n_ptr == NULL) bc_out_of_memory();
+ temp->n_value = temp->n_ptr;
+ memset (temp->n_ptr, 0, length+scale);
+ return temp;
+}
+
+/* "Frees" a bc_num NUM. Actually decreases reference count and only
+ frees the storage if reference count is zero. */
+
+void
+bc_free_num (num)
+ bc_num *num;
+{
+ if (*num == NULL) return;
+ (*num)->n_refs--;
+ if ((*num)->n_refs == 0) {
+ if ((*num)->n_ptr)
+ free ((*num)->n_ptr);
+ free (*num);
+ }
+ *num = NULL;
+}
+
+
+/* Intitialize the number package! */
+
+void
+bc_init_numbers ()
+{
+ _zero_ = bc_new_num (1,0);
+ _one_ = bc_new_num (1,0);
+ _one_->n_value[0] = 1;
+ _two_ = bc_new_num (1,0);
+ _two_->n_value[0] = 2;
+}
+
+
+/* Make a copy of a number! Just increments the reference count! */
+
+bc_num
+bc_copy_num (num)
+ bc_num num;
+{
+ num->n_refs++;
+ return num;
+}
+
+
+/* Initialize a number NUM by making it a copy of zero. */
+
+void
+bc_init_num (num)
+ bc_num *num;
+{
+ *num = bc_copy_num (_zero_);
+}
+
+/* For many things, we may have leading zeros in a number NUM.
+ _bc_rm_leading_zeros just moves the data "value" pointer to the
+ correct place and adjusts the length. */
+
+static void
+_bc_rm_leading_zeros (num)
+ bc_num num;
+{
+ /* We can move n_value to point to the first non zero digit! */
+ while (*num->n_value == 0 && num->n_len > 1) {
+ num->n_value++;
+ num->n_len--;
+ }
+}
+
+
+/* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less
+ than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just
+ compare the magnitudes. */
+
+static int
+_bc_do_compare (n1, n2, use_sign, ignore_last)
+ bc_num n1, n2;
+ int use_sign;
+ int ignore_last;
+{
+ char *n1ptr, *n2ptr;
+ int count;
+
+ /* First, compare signs. */
+ if (use_sign && n1->n_sign != n2->n_sign)
+ {
+ if (n1->n_sign == PLUS)
+ return (1); /* Positive N1 > Negative N2 */
+ else
+ return (-1); /* Negative N1 < Positive N1 */
+ }
+
+ /* Now compare the magnitude. */
+ if (n1->n_len != n2->n_len)
+ {
+ if (n1->n_len > n2->n_len)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ else
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+
+ /* If we get here, they have the same number of integer digits.
+ check the integer part and the equal length part of the fraction. */
+ count = n1->n_len + MIN (n1->n_scale, n2->n_scale);
+ n1ptr = n1->n_value;
+ n2ptr = n2->n_value;
+
+ while ((count > 0) && (*n1ptr == *n2ptr))
+ {
+ n1ptr++;
+ n2ptr++;
+ count--;
+ }
+ if (ignore_last && count == 1 && n1->n_scale == n2->n_scale)
+ return (0);
+ if (count != 0)
+ {
+ if (*n1ptr > *n2ptr)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ else
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+
+ /* They are equal up to the last part of the equal part of the fraction. */
+ if (n1->n_scale != n2->n_scale)
+ {
+ if (n1->n_scale > n2->n_scale)
+ {
+ for (count = n1->n_scale-n2->n_scale; count>0; count--)
+ if (*n1ptr++ != 0)
+ {
+ /* Magnitude of n1 > n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (1);
+ else
+ return (-1);
+ }
+ }
+ else
+ {
+ for (count = n2->n_scale-n1->n_scale; count>0; count--)
+ if (*n2ptr++ != 0)
+ {
+ /* Magnitude of n1 < n2. */
+ if (!use_sign || n1->n_sign == PLUS)
+ return (-1);
+ else
+ return (1);
+ }
+ }
+ }
+
+ /* They must be equal! */
+ return (0);
+}
+
+
+/* This is the "user callable" routine to compare numbers N1 and N2. */
+
+int
+bc_compare (n1, n2)
+ bc_num n1, n2;
+{
+ return _bc_do_compare (n1, n2, TRUE, FALSE);
+}
+
+/* In some places we need to check if the number is negative. */
+
+char
+bc_is_neg (num)
+ bc_num num;
+{
+ return num->n_sign == MINUS;
+}
+
+/* In some places we need to check if the number NUM is zero. */
+
+char
+bc_is_zero (num)
+ bc_num num;
+{
+ int count;
+ char *nptr;
+
+ /* Quick check. */
+ if (num == _zero_) return TRUE;
+
+ /* Initialize */
+ count = num->n_len + num->n_scale;
+ nptr = num->n_value;
+
+ /* The check */
+ while ((count > 0) && (*nptr++ == 0)) count--;
+
+ if (count != 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+/* In some places we need to check if the number NUM is almost zero.
+ Specifically, all but the last digit is 0 and the last digit is 1.
+ Last digit is defined by scale. */
+
+char
+bc_is_near_zero (num, scale)
+ bc_num num;
+ int scale;
+{
+ int count;
+ char *nptr;
+
+ /* Error checking */
+ if (scale > num->n_scale)
+ scale = num->n_scale;
+
+ /* Initialize */
+ count = num->n_len + scale;
+ nptr = num->n_value;
+
+ /* The check */
+ while ((count > 0) && (*nptr++ == 0)) count--;
+
+ if (count != 0 && (count != 1 || *--nptr != 1))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+/* Perform addition: N1 is added to N2 and the value is
+ returned. The signs of N1 and N2 are ignored.
+ SCALE_MIN is to set the minimum scale of the result. */
+
+static bc_num
+_bc_do_add (n1, n2, scale_min)
+ bc_num n1, n2;
+ int scale_min;
+{
+ bc_num sum;
+ int sum_scale, sum_digits;
+ char *n1ptr, *n2ptr, *sumptr;
+ int carry, n1bytes, n2bytes;
+ int count;
+
+ /* Prepare sum. */
+ sum_scale = MAX (n1->n_scale, n2->n_scale);
+ sum_digits = MAX (n1->n_len, n2->n_len) + 1;
+ sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
+
+ /* Zero extra digits made by scale_min. */
+ if (scale_min > sum_scale)
+ {
+ sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
+ for (count = scale_min - sum_scale; count > 0; count--)
+ *sumptr++ = 0;
+ }
+
+ /* Start with the fraction part. Initialize the pointers. */
+ n1bytes = n1->n_scale;
+ n2bytes = n2->n_scale;
+ n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
+ n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
+ sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
+
+ /* Add the fraction part. First copy the longer fraction.*/
+ if (n1bytes != n2bytes)
+ {
+ if (n1bytes > n2bytes)
+ while (n1bytes>n2bytes)
+ { *sumptr-- = *n1ptr--; n1bytes--;}
+ else
+ while (n2bytes>n1bytes)
+ { *sumptr-- = *n2ptr--; n2bytes--;}
+ }
+
+ /* Now add the remaining fraction part and equal size integer parts. */
+ n1bytes += n1->n_len;
+ n2bytes += n2->n_len;
+ carry = 0;
+ while ((n1bytes > 0) && (n2bytes > 0))
+ {
+ *sumptr = *n1ptr-- + *n2ptr-- + carry;
+ if (*sumptr > (BASE-1))
+ {
+ carry = 1;
+ *sumptr -= BASE;
+ }
+ else
+ carry = 0;
+ sumptr--;
+ n1bytes--;
+ n2bytes--;
+ }
+
+ /* Now add carry the longer integer part. */
+ if (n1bytes == 0)
+ { n1bytes = n2bytes; n1ptr = n2ptr; }
+ while (n1bytes-- > 0)
+ {
+ *sumptr = *n1ptr-- + carry;
+ if (*sumptr > (BASE-1))
+ {
+ carry = 1;
+ *sumptr -= BASE;
+ }
+ else
+ carry = 0;
+ sumptr--;
+ }
+
+ /* Set final carry. */
+ if (carry == 1)
+ *sumptr += 1;
+
+ /* Adjust sum and return. */
+ _bc_rm_leading_zeros (sum);
+ return sum;
+}
+
+
+/* Perform subtraction: N2 is subtracted from N1 and the value is
+ returned. The signs of N1 and N2 are ignored. Also, N1 is
+ assumed to be larger than N2. SCALE_MIN is the minimum scale
+ of the result. */
+
+static bc_num
+_bc_do_sub (n1, n2, scale_min)
+ bc_num n1, n2;
+ int scale_min;
+{
+ bc_num diff;
+ int diff_scale, diff_len;
+ int min_scale, min_len;
+ char *n1ptr, *n2ptr, *diffptr;
+ int borrow, count, val;
+
+ /* Allocate temporary storage. */
+ diff_len = MAX (n1->n_len, n2->n_len);
+ diff_scale = MAX (n1->n_scale, n2->n_scale);
+ min_len = MIN (n1->n_len, n2->n_len);
+ min_scale = MIN (n1->n_scale, n2->n_scale);
+ diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
+
+ /* Zero extra digits made by scale_min. */
+ if (scale_min > diff_scale)
+ {
+ diffptr = (char *) (diff->n_value + diff_len + diff_scale);
+ for (count = scale_min - diff_scale; count > 0; count--)
+ *diffptr++ = 0;
+ }
+
+ /* Initialize the subtract. */
+ n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
+ n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
+ diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
+
+ /* Subtract the numbers. */
+ borrow = 0;
+
+ /* Take care of the longer scaled number. */
+ if (n1->n_scale != min_scale)
+ {
+ /* n1 has the longer scale */
+ for (count = n1->n_scale - min_scale; count > 0; count--)
+ *diffptr-- = *n1ptr--;
+ }
+ else
+ {
+ /* n2 has the longer scale */
+ for (count = n2->n_scale - min_scale; count > 0; count--)
+ {
+ val = - *n2ptr-- - borrow;
+ if (val < 0)
+ {
+ val += BASE;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+ }
+
+ /* Now do the equal length scale and integer parts. */
+
+ for (count = 0; count < min_len + min_scale; count++)
+ {
+ val = *n1ptr-- - *n2ptr-- - borrow;
+ if (val < 0)
+ {
+ val += BASE;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+
+ /* If n1 has more digits then n2, we now do that subtract. */
+ if (diff_len != min_len)
+ {
+ for (count = diff_len - min_len; count > 0; count--)
+ {
+ val = *n1ptr-- - borrow;
+ if (val < 0)
+ {
+ val += BASE;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *diffptr-- = val;
+ }
+ }
+
+ /* Clean up and return. */
+ _bc_rm_leading_zeros (diff);
+ return diff;
+}
+
+
+/* Here is the full subtract routine that takes care of negative numbers.
+ N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN
+ is the minimum scale for the result. */
+
+void
+bc_sub (n1, n2, result, scale_min)
+ bc_num n1, n2, *result;
+ int scale_min;
+{
+ bc_num diff = NULL;
+ int cmp_res;
+ int res_scale;
+
+ if (n1->n_sign != n2->n_sign)
+ {
+ diff = _bc_do_add (n1, n2, scale_min);
+ diff->n_sign = n1->n_sign;
+ }
+ else
+ {
+ /* subtraction must be done. */
+ /* Compare magnitudes. */
+ cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE);
+ switch (cmp_res)
+ {
+ case -1:
+ /* n1 is less than n2, subtract n1 from n2. */
+ diff = _bc_do_sub (n2, n1, scale_min);
+ diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS);
+ break;
+ case 0:
+ /* They are equal! return zero! */
+ res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
+ diff = bc_new_num (1, res_scale);
+ memset (diff->n_value, 0, res_scale+1);
+ break;
+ case 1:
+ /* n2 is less than n1, subtract n2 from n1. */
+ diff = _bc_do_sub (n1, n2, scale_min);
+ diff->n_sign = n1->n_sign;
+ break;
+ }
+ }
+
+ /* Clean up and return. */
+ bc_free_num (result);
+ *result = diff;
+}
+
+
+/* Here is the full add routine that takes care of negative numbers.
+ N1 is added to N2 and the result placed into RESULT. SCALE_MIN
+ is the minimum scale for the result. */
+
+void
+bc_add (n1, n2, result, scale_min)
+ bc_num n1, n2, *result;
+ int scale_min;
+{
+ bc_num sum = NULL;
+ int cmp_res;
+ int res_scale;
+
+ if (n1->n_sign == n2->n_sign)
+ {
+ sum = _bc_do_add (n1, n2, scale_min);
+ sum->n_sign = n1->n_sign;
+ }
+ else
+ {
+ /* subtraction must be done. */
+ cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */
+ switch (cmp_res)
+ {
+ case -1:
+ /* n1 is less than n2, subtract n1 from n2. */
+ sum = _bc_do_sub (n2, n1, scale_min);
+ sum->n_sign = n2->n_sign;
+ break;
+ case 0:
+ /* They are equal! return zero with the correct scale! */
+ res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
+ sum = bc_new_num (1, res_scale);
+ memset (sum->n_value, 0, res_scale+1);
+ break;
+ case 1:
+ /* n2 is less than n1, subtract n2 from n1. */
+ sum = _bc_do_sub (n1, n2, scale_min);
+ sum->n_sign = n1->n_sign;
+ }
+ }
+
+ /* Clean up and return. */
+ bc_free_num (result);
+ *result = sum;
+}
+
+/* Recursive vs non-recursive multiply crossover ranges. */
+#if defined(MULDIGITS)
+#include "muldigits.h"
+#else
+#define MUL_BASE_DIGITS 80
+#endif
+
+int mul_base_digits = MUL_BASE_DIGITS;
+#define MUL_SMALL_DIGITS mul_base_digits/4
+
+/* Multiply utility routines */
+
+static bc_num
+new_sub_num (length, scale, value)
+ int length, scale;
+ char *value;
+{
+ bc_num temp;
+
+ temp = (bc_num) malloc (sizeof(bc_struct));
+ if (temp == NULL) bc_out_of_memory ();
+ temp->n_sign = PLUS;
+ temp->n_len = length;
+ temp->n_scale = scale;
+ temp->n_refs = 1;
+ temp->n_ptr = NULL;
+ temp->n_value = value;
+ return temp;
+}
+
+static void
+_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod,
+ int full_scale)
+{
+ char *n1ptr, *n2ptr, *pvptr;
+ char *n1end, *n2end; /* To the end of n1 and n2. */
+ int indx, sum, prodlen;
+
+ prodlen = n1len+n2len+1;
+
+ *prod = bc_new_num (prodlen, 0);
+
+ n1end = (char *) (n1->n_value + n1len - 1);
+ n2end = (char *) (n2->n_value + n2len - 1);
+ pvptr = (char *) ((*prod)->n_value + prodlen - 1);
+ sum = 0;
+
+ /* Here is the loop... */
+ for (indx = 0; indx < prodlen-1; indx++)
+ {
+ n1ptr = (char *) (n1end - MAX(0, indx-n2len+1));
+ n2ptr = (char *) (n2end - MIN(indx, n2len-1));
+ while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
+ sum += *n1ptr-- * *n2ptr++;
+ *pvptr-- = sum % BASE;
+ sum = sum / BASE;
+ }
+ *pvptr = sum;
+}
+
+
+/* A special adder/subtractor for the recursive divide and conquer
+ multiply algorithm. Note: if sub is called, accum must
+ be larger that what is being subtracted. Also, accum and val
+ must have n_scale = 0. (e.g. they must look like integers. *) */
+static void
+_bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
+{
+ signed char *accp, *valp;
+ int count, carry;
+
+ count = val->n_len;
+ if (val->n_value[0] == 0)
+ count--;
+ assert (accum->n_len+accum->n_scale >= shift+count);
+
+ /* Set up pointers and others */
+ accp = (signed char *)(accum->n_value +
+ accum->n_len + accum->n_scale - shift - 1);
+ valp = (signed char *)(val->n_value + val->n_len - 1);
+ carry = 0;
+
+ if (sub) {
+ /* Subtraction, carry is really borrow. */
+ while (count--) {
+ *accp -= *valp-- + carry;
+ if (*accp < 0) {
+ carry = 1;
+ *accp-- += BASE;
+ } else {
+ carry = 0;
+ accp--;
+ }
+ }
+ while (carry) {
+ *accp -= carry;
+ if (*accp < 0)
+ *accp-- += BASE;
+ else
+ carry = 0;
+ }
+ } else {
+ /* Addition */
+ while (count--) {
+ *accp += *valp-- + carry;
+ if (*accp > (BASE-1)) {
+ carry = 1;
+ *accp-- -= BASE;
+ } else {
+ carry = 0;
+ accp--;
+ }
+ }
+ while (carry) {
+ *accp += carry;
+ if (*accp > (BASE-1))
+ *accp-- -= BASE;
+ else
+ carry = 0;
+ }
+ }
+}
+
+/* Recursive divide and conquer multiply algorithm.
+ Based on
+ Let u = u0 + u1*(b^n)
+ Let v = v0 + v1*(b^n)
+ Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0
+
+ B is the base of storage, number of digits in u1,u0 close to equal.
+*/
+static void
+_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
+ int full_scale)
+{
+ bc_num u0, u1, v0, v1;
+ int u0len, v0len;
+ bc_num m1, m2, m3, d1, d2;
+ int n, prodlen, m1zero;
+ int d1len, d2len;
+
+ /* Base case? */
+ if ((ulen+vlen) < mul_base_digits
+ || ulen < MUL_SMALL_DIGITS
+ || vlen < MUL_SMALL_DIGITS ) {
+ _bc_simp_mul (u, ulen, v, vlen, prod, full_scale);
+ return;
+ }
+
+ /* Calculate n -- the u and v split point in digits. */
+ n = (MAX(ulen, vlen)+1) / 2;
+
+ /* Split u and v. */
+ if (ulen < n) {
+ u1 = bc_copy_num (_zero_);
+ u0 = new_sub_num (ulen,0, u->n_value);
+ } else {
+ u1 = new_sub_num (ulen-n, 0, u->n_value);
+ u0 = new_sub_num (n, 0, u->n_value+ulen-n);
+ }
+ if (vlen < n) {
+ v1 = bc_copy_num (_zero_);
+ v0 = new_sub_num (vlen,0, v->n_value);
+ } else {
+ v1 = new_sub_num (vlen-n, 0, v->n_value);
+ v0 = new_sub_num (n, 0, v->n_value+vlen-n);
+ }
+ _bc_rm_leading_zeros (u1);
+ _bc_rm_leading_zeros (u0);
+ u0len = u0->n_len;
+ _bc_rm_leading_zeros (v1);
+ _bc_rm_leading_zeros (v0);
+ v0len = v0->n_len;
+
+ m1zero = bc_is_zero(u1) || bc_is_zero(v1);
+
+ /* Calculate sub results ... */
+
+ bc_init_num(&d1);
+ bc_init_num(&d2);
+ bc_sub (u1, u0, &d1, 0);
+ d1len = d1->n_len;
+ bc_sub (v0, v1, &d2, 0);
+ d2len = d2->n_len;
+
+
+ /* Do recursive multiplies and shifted adds. */
+ if (m1zero)
+ m1 = bc_copy_num (_zero_);
+ else
+ _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1, 0);
+
+ if (bc_is_zero(d1) || bc_is_zero(d2))
+ m2 = bc_copy_num (_zero_);
+ else
+ _bc_rec_mul (d1, d1len, d2, d2len, &m2, 0);
+
+ if (bc_is_zero(u0) || bc_is_zero(v0))
+ m3 = bc_copy_num (_zero_);
+ else
+ _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3, 0);
+
+ /* Initialize product */
+ prodlen = ulen+vlen+1;
+ *prod = bc_new_num(prodlen, 0);
+
+ if (!m1zero) {
+ _bc_shift_addsub (*prod, m1, 2*n, 0);
+ _bc_shift_addsub (*prod, m1, n, 0);
+ }
+ _bc_shift_addsub (*prod, m3, n, 0);
+ _bc_shift_addsub (*prod, m3, 0, 0);
+ _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign);
+
+ /* Now clean up! */
+ bc_free_num (&u1);
+ bc_free_num (&u0);
+ bc_free_num (&v1);
+ bc_free_num (&m1);
+ bc_free_num (&v0);
+ bc_free_num (&m2);
+ bc_free_num (&m3);
+ bc_free_num (&d1);
+ bc_free_num (&d2);
+}
+
+/* The multiply routine. N2 times N1 is put int PROD with the scale of
+ the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
+ */
+
+void
+bc_multiply (n1, n2, prod, scale)
+ bc_num n1, n2, *prod;
+ int scale;
+{
+ bc_num pval;
+ int len1, len2;
+ int full_scale, prod_scale;
+
+ /* Initialize things. */
+ len1 = n1->n_len + n1->n_scale;
+ len2 = n2->n_len + n2->n_scale;
+ full_scale = n1->n_scale + n2->n_scale;
+ prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
+
+ /* Do the multiply */
+ _bc_rec_mul (n1, len1, n2, len2, &pval, full_scale);
+
+ /* Assign to prod and clean up the number. */
+ pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
+ pval->n_value = pval->n_ptr;
+ pval->n_len = len2 + len1 + 1 - full_scale;
+ pval->n_scale = prod_scale;
+ _bc_rm_leading_zeros (pval);
+ if (bc_is_zero (pval))
+ pval->n_sign = PLUS;
+ bc_free_num (prod);
+ *prod = pval;
+}
+
+/* Some utility routines for the divide: First a one digit multiply.
+ NUM (with SIZE digits) is multiplied by DIGIT and the result is
+ placed into RESULT. It is written so that NUM and RESULT can be
+ the same pointers. */
+
+static void
+_one_mult (num, size, digit, result)
+ unsigned char *num;
+ int size, digit;
+ unsigned char *result;
+{
+ int carry, value;
+ unsigned char *nptr, *rptr;
+
+ if (digit == 0)
+ memset (result, 0, size);
+ else
+ {
+ if (digit == 1)
+ memcpy (result, num, size);
+ else
+ {
+ /* Initialize */
+ nptr = (unsigned char *) (num+size-1);
+ rptr = (unsigned char *) (result+size-1);
+ carry = 0;
+
+ while (size-- > 0)
+ {
+ value = *nptr-- * digit + carry;
+ *rptr-- = value % BASE;
+ carry = value / BASE;
+ }
+
+ if (carry != 0) *rptr = carry;
+ }
+ }
+}
+
+
+/* The full division routine. This computes N1 / N2. It returns
+ 0 if the division is ok and the result is in QUOT. The number of
+ digits after the decimal point is SCALE. It returns -1 if division
+ by zero is tried. The algorithm is found in Knuth Vol 2. p237. */
+
+int
+bc_divide (n1, n2, quot, scale)
+ bc_num n1, n2, *quot;
+ int scale;
+{
+ bc_num qval;
+ unsigned char *num1, *num2;
+ unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
+ int scale1, val;
+ unsigned int len1, len2, scale2, qdigits, extra, count;
+ unsigned int qdig, qguess, borrow, carry;
+ unsigned char *mval;
+ char zero;
+ unsigned int norm;
+
+ /* Test for divide by zero. */
+ if (bc_is_zero (n2)) return -1;
+
+ /* Test for divide by 1. If it is we must truncate. */
+ if (n2->n_scale == 0)
+ {
+ if (n2->n_len == 1 && *n2->n_value == 1)
+ {
+ qval = bc_new_num (n1->n_len, scale);
+ qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
+ memset (&qval->n_value[n1->n_len],0,scale);
+ memcpy (qval->n_value, n1->n_value,
+ n1->n_len + MIN(n1->n_scale,scale));
+ bc_free_num (quot);
+ *quot = qval;
+ }
+ }
+
+ /* Set up the divide. Move the decimal point on n1 by n2's scale.
+ Remember, zeros on the end of num2 are wasted effort for dividing. */
+ scale2 = n2->n_scale;
+ n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
+ while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--;
+
+ len1 = n1->n_len + scale2;
+ scale1 = n1->n_scale - scale2;
+ if (scale1 < scale)
+ extra = scale - scale1;
+ else
+ extra = 0;
+ num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2);
+ if (num1 == NULL) bc_out_of_memory();
+ memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
+ memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
+
+ len2 = n2->n_len + scale2;
+ num2 = (unsigned char *) malloc (len2+1);
+ if (num2 == NULL) bc_out_of_memory();
+ memcpy (num2, n2->n_value, len2);
+ *(num2+len2) = 0;
+ n2ptr = num2;
+ while (*n2ptr == 0)
+ {
+ n2ptr++;
+ len2--;
+ }
+
+ /* Calculate the number of quotient digits. */
+ if (len2 > len1+scale)
+ {
+ qdigits = scale+1;
+ zero = TRUE;
+ }
+ else
+ {
+ zero = FALSE;
+ if (len2>len1)
+ qdigits = scale+1; /* One for the zero integer part. */
+ else
+ qdigits = len1-len2+scale+1;
+ }
+
+ /* Allocate and zero the storage for the quotient. */
+ qval = bc_new_num (qdigits-scale,scale);
+ memset (qval->n_value, 0, qdigits);
+
+ /* Allocate storage for the temporary storage mval. */
+ mval = (unsigned char *) malloc (len2+1);
+ if (mval == NULL) bc_out_of_memory ();
+
+ /* Now for the full divide algorithm. */
+ if (!zero)
+ {
+ /* Normalize */
+ norm = 10 / ((int)*n2ptr + 1);
+ if (norm != 1)
+ {
+ _one_mult (num1, len1+scale1+extra+1, norm, num1);
+ _one_mult (n2ptr, len2, norm, n2ptr);
+ }
+
+ /* Initialize divide loop. */
+ qdig = 0;
+ if (len2 > len1)
+ qptr = (unsigned char *) qval->n_value+len2-len1;
+ else
+ qptr = (unsigned char *) qval->n_value;
+
+ /* Loop */
+ while (qdig <= len1+scale-len2)
+ {
+ /* Calculate the quotient digit guess. */
+ if (*n2ptr == num1[qdig])
+ qguess = 9;
+ else
+ qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
+
+ /* Test qguess. */
+ if (n2ptr[1]*qguess >
+ (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ + num1[qdig+2])
+ {
+ qguess--;
+ /* And again. */
+ if (n2ptr[1]*qguess >
+ (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ + num1[qdig+2])
+ qguess--;
+ }
+
+ /* Multiply and subtract. */
+ borrow = 0;
+ if (qguess != 0)
+ {
+ *mval = 0;
+ _one_mult (n2ptr, len2, qguess, mval+1);
+ ptr1 = (unsigned char *) num1+qdig+len2;
+ ptr2 = (unsigned char *) mval+len2;
+ for (count = 0; count < len2+1; count++)
+ {
+ val = (int) *ptr1 - (int) *ptr2-- - borrow;
+ if (val < 0)
+ {
+ val += 10;
+ borrow = 1;
+ }
+ else
+ borrow = 0;
+ *ptr1-- = val;
+ }
+ }
+
+ /* Test for negative result. */
+ if (borrow == 1)
+ {
+ qguess--;
+ ptr1 = (unsigned char *) num1+qdig+len2;
+ ptr2 = (unsigned char *) n2ptr+len2-1;
+ carry = 0;
+ for (count = 0; count < len2; count++)
+ {
+ val = (int) *ptr1 + (int) *ptr2-- + carry;
+ if (val > 9)
+ {
+ val -= 10;
+ carry = 1;
+ }
+ else
+ carry = 0;
+ *ptr1-- = val;
+ }
+ if (carry == 1) *ptr1 = (*ptr1 + 1) % 10;
+ }
+
+ /* We now know the quotient digit. */
+ *qptr++ = qguess;
+ qdig++;
+ }
+ }
+
+ /* Clean up and return the number. */
+ qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
+ if (bc_is_zero (qval)) qval->n_sign = PLUS;
+ _bc_rm_leading_zeros (qval);
+ bc_free_num (quot);
+ *quot = qval;
+
+ /* Clean up temporary storage. */
+ free (mval);
+ free (num1);
+ free (num2);
+
+ return 0; /* Everything is OK. */
+}
+
+
+/* Division *and* modulo for numbers. This computes both NUM1 / NUM2 and
+ NUM1 % NUM2 and puts the results in QUOT and REM, except that if QUOT
+ is NULL then that store will be omitted.
+ */
+
+int
+bc_divmod (num1, num2, quot, rem, scale)
+ bc_num num1, num2, *quot, *rem;
+ int scale;
+{
+ bc_num quotient = NULL;
+ bc_num temp;
+ int rscale;
+
+ /* Check for correct numbers. */
+ if (bc_is_zero (num2)) return -1;
+
+ /* Calculate final scale. */
+ rscale = MAX (num1->n_scale, num2->n_scale+scale);
+ bc_init_num(&temp);
+
+ /* Calculate it. */
+ bc_divide (num1, num2, &temp, scale);
+ if (quot)
+ quotient = bc_copy_num (temp);
+ bc_multiply (temp, num2, &temp, rscale);
+ bc_sub (num1, temp, rem, rscale);
+ bc_free_num (&temp);
+
+ if (quot)
+ {
+ bc_free_num (quot);
+ *quot = quotient;
+ }
+
+ return 0; /* Everything is OK. */
+}
+
+
+/* Modulo for numbers. This computes NUM1 % NUM2 and puts the
+ result in RESULT. */
+
+int
+bc_modulo (num1, num2, result, scale)
+ bc_num num1, num2, *result;
+ int scale;
+{
+ return bc_divmod (num1, num2, NULL, result, scale);
+}
+
+/* Raise BASE to the EXPO power, reduced modulo MOD. The result is
+ placed in RESULT. If a EXPO is not an integer,
+ only the integer part is used. */
+
+int
+bc_raisemod (base, expo, mod, result, scale)
+ bc_num base, expo, mod, *result;
+ int scale;
+{
+ bc_num power, exponent, parity, temp;
+ int rscale;
+
+ /* Check for correct numbers. */
+ if (bc_is_zero(mod)) return -1;
+ if (bc_is_neg(expo)) return -1;
+
+ /* Set initial values. */
+ power = bc_copy_num (base);
+ exponent = bc_copy_num (expo);
+ temp = bc_copy_num (_one_);
+ bc_init_num(&parity);
+
+ /* Check the base for scale digits. */
+ if (base->n_scale != 0)
+ bc_rt_warn ("non-zero scale in base");
+
+ /* Check the exponent for scale digits. */
+ if (exponent->n_scale != 0)
+ {
+ bc_rt_warn ("non-zero scale in exponent");
+ bc_divide (exponent, _one_, &exponent, 0); /*truncate */
+ }
+
+ /* Check the modulus for scale digits. */
+ if (mod->n_scale != 0)
+ bc_rt_warn ("non-zero scale in modulus");
+
+ /* Do the calculation. */
+ rscale = MAX(scale, base->n_scale);
+ while ( !bc_is_zero(exponent) )
+ {
+ (void) bc_divmod (exponent, _two_, &exponent, &parity, 0);
+ if ( !bc_is_zero(parity) )
+ {
+ bc_multiply (temp, power, &temp, rscale);
+ (void) bc_modulo (temp, mod, &temp, scale);
+ }
+
+ bc_multiply (power, power, &power, rscale);
+ (void) bc_modulo (power, mod, &power, scale);
+ }
+
+ /* Assign the value. */
+ bc_free_num (&power);
+ bc_free_num (&exponent);
+ bc_free_num (result);
+ bc_free_num (&parity);
+ *result = temp;
+ return 0; /* Everything is OK. */
+}
+
+/* Raise NUM1 to the NUM2 power. The result is placed in RESULT.
+ Maximum exponent is LONG_MAX. If a NUM2 is not an integer,
+ only the integer part is used. */
+
+void
+bc_raise (num1, num2, result, scale)
+ bc_num num1, num2, *result;
+ int scale;
+{
+ bc_num temp, power;
+ long exponent;
+ int rscale;
+ int pwrscale;
+ int calcscale;
+ char neg;
+
+ /* Check the exponent for scale digits and convert to a long. */
+ if (num2->n_scale != 0)
+ bc_rt_warn ("non-zero scale in exponent");
+ exponent = bc_num2long (num2);
+ if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0))
+ bc_rt_error ("exponent too large in raise");
+
+ /* Special case if exponent is a zero. */
+ if (exponent == 0)
+ {
+ bc_free_num (result);
+ *result = bc_copy_num (_one_);
+ return;
+ }
+
+ /* Other initializations. */
+ if (exponent < 0)
+ {
+ neg = TRUE;
+ exponent = -exponent;
+ rscale = scale;
+ }
+ else
+ {
+ neg = FALSE;
+ rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
+ }
+
+ /* Set initial value of temp. */
+ power = bc_copy_num (num1);
+ pwrscale = num1->n_scale;
+ while ((exponent & 1) == 0)
+ {
+ pwrscale = 2*pwrscale;
+ bc_multiply (power, power, &power, pwrscale);
+ exponent = exponent >> 1;
+ }
+ temp = bc_copy_num (power);
+ calcscale = pwrscale;
+ exponent = exponent >> 1;
+
+ /* Do the calculation. */
+ while (exponent > 0)
+ {
+ pwrscale = 2*pwrscale;
+ bc_multiply (power, power, &power, pwrscale);
+ if ((exponent & 1) == 1) {
+ calcscale = pwrscale + calcscale;
+ bc_multiply (temp, power, &temp, calcscale);
+ }
+ exponent = exponent >> 1;
+ }
+
+ /* Assign the value. */
+ if (neg)
+ {
+ bc_divide (_one_, temp, result, rscale);
+ bc_free_num (&temp);
+ }
+ else
+ {
+ bc_free_num (result);
+ *result = temp;
+ if ((*result)->n_scale > rscale)
+ (*result)->n_scale = rscale;
+ }
+ bc_free_num (&power);
+}
+
+/* Take the square root NUM and return it in NUM with SCALE digits
+ after the decimal place. */
+
+int
+bc_sqrt (num, scale)
+ bc_num *num;
+ int scale;
+{
+ int rscale, cmp_res, done;
+ int cscale;
+ bc_num guess, guess1, point5, diff;
+
+ /* Initial checks. */
+ cmp_res = bc_compare (*num, _zero_);
+ if (cmp_res < 0)
+ return 0; /* error */
+ else
+ {
+ if (cmp_res == 0)
+ {
+ bc_free_num (num);
+ *num = bc_copy_num (_zero_);
+ return 1;
+ }
+ }
+ cmp_res = bc_compare (*num, _one_);
+ if (cmp_res == 0)
+ {
+ bc_free_num (num);
+ *num = bc_copy_num (_one_);
+ return 1;
+ }
+
+ /* Initialize the variables. */
+ rscale = MAX (scale, (*num)->n_scale);
+ bc_init_num(&guess);
+ bc_init_num(&guess1);
+ bc_init_num(&diff);
+ point5 = bc_new_num (1,1);
+ point5->n_value[1] = 5;
+